Monday, December 9, 2013

If you love Code Generation, you must love Aspect programming too !

Being a lazy person I love Code generation ! I dont want to waste my life in writing same code again and again and sacrifice movies I could have watched in that time ! ;) That reminds me the great Bill Gates'  great quote, "I would rather hire lazy person for the job, because he/she will find easier way to do that !" !

So code generation, if some tool is there to generate code for you, why not ! I have used primarily Spring Roo and AndroMDA for Java. Both have fascinated me so much ! . AndroMDA for it's generate-from-UML approach and Spring Roo from it unix like shell . AndroMDA is also open-source and comes from a small country in Europe and Spring Roo, as name suggests , its from popular Spring guys.

Little bit about AndroMDA and Spring Roo :

If you have not used one or both of them I am sure you would be curious to know at least basics. AndroMDA - Let's you draw UML and give "stereotypes" lets you apply stereotypes to your objects. For example, stereotype "Entity" makes a class a database entity with all hibernate code for it, "Service" stereotype adds transaction boundaries to methods of that class and lets you add Dao as dependencies on service . So for AndroMDA , UML -> XMI -> Cartridges -> Java/XML code is the way to go. AndroMDA lets developer to worry about implementing  *Impl classes only where you add business logic. These Impl classes obviously extend from base classes where most of the stuff like CRUD operations , validating passed objects are done. Authors of AndroMDA guys are not glamorous and do not come from valley, but the work they have done is amazing.

For Spring Roo, you say on command line to generate an entity , for example, "entity jpa --class ~.domain.AppUser", Roo generates main POJO with annotations to make it an entity but it adds all the code using Aspects, specifically called ITD intertype-declarations. These Aspects add functionality such as CRUD operations on entity, finder methods etc.

Why you should love Aspect Programming if you love Code generation : 

Because aspects supports your laziness even further ! Being in love with code generation, I am sure you are fond of things to work with lightening speed ! You have all the knowledge of how things work , you want to show your friend how you can create website or an app on Friday evening while having beer. You also want to follow best coding practices ! See laziness is not just one reason to use code generation ! :) All these great developers who developed these code generation tools, follow ( and have to follow) best practices !

What is Aspects !?

Typical definition of Aspect programming as per Wikipedia is "is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.". This word Cross-cutting concerns is bit confusing. It gives feeling that Aspects are limited to logging, security etc. Typical example of cross cutting concern is " aspect saves to have logging code dispersed into your all your code. Instead you write one aspect to print incoming or outgoing parameters and it will log for you. Typical Aspect for logging incoming parameters looks like this 

    pointcut thePointcut(String userid, String password) :  execution(* com.mycompany.backend.web.AppUserController.theMethodToIntercept(..)) && args(userid,password);

    Object around(String userid, String password) : thePointcut(userid,password){
        log.info("User trying to login : " + userid); // Here logging without touching original method "theMethodToIntercept"
        return proceed(userid,password) ;
    }


Though Aspect promoters say several times that Aspects can be used for better purposes than just logging and security, I have seen developers not getting where they can use Aspects to make their life easier. Aspects evangelists may forget to mention about its big use in project based on code-generation, where developers would understand better how Aspects can make things even easier for them. 

Example of AspectJ users other than just "logging" :

Here is typical example. There is an entity called AppUser in your domain. Roo has generated CRUD operations for you for that entity. When you create user, the password for user should be encrypted. But here you may end up overwriting/overriding the Create method Roo generated for you. Instead if you write "before" or around aspect on that method, your encryptiion code is isolated, you did not have to touch or override the code Roo has generated for you, allowing code-generation (here Roo) to evolve independently. What you are doing here is adding your code like a decoration on the original code. 

Here is example of code generated by Roo to create AppUser :

    @RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
    public ResponseEntity<String> AppUserController.createFromJson(@RequestBody String json) {
        AppUser appUser = AppUser.fromJsonToAppUser(json);
        appUser.persist();
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        return new ResponseEntity<String>(headers, HttpStatus.CREATED);
    }

Here is example of the password encryption Aspect which can be added which takes effect before above method is called,

    pointcut aroundCreateUser(String jsonUserString) : execution(* com.softrism.sencha.backend.web.AppUserController.createFromJson(..)) && args(jsonUserString);

    Object around(String jsonUserString) : aroundCreateUSer(jsonUserString){

        AppUser appUser = AppUser.fromJsonToAppUser(jsonUserString);
        ShaPasswordEncoder encoder = new ShaPasswordEncoder(256);
        String password = appUser.getPassword() ;

        String encoded = encoder.encodePassword(password,null);
        appUser.setPassword(encoded);
        String finalJsonUser = appUser.toJson();

        ResponseEntity responseEntity = (ResponseEntity)proceed(finalJsonUser);

        return new ResponseEntity<String>(appUser.toJson(),responseEntity.getHeaders(), responseEntity.getStatusCode());
    }


Now just take your aspects across your Roo or AndroMDA projects :

If  your user entity name is AppUser in all the projects, you can move the aspect as is , if you change the name, just change the name of aspect as per that project. Thats it. User password encryption code just added in a snap in your new projects. Plus, your code-generation tool can independently evolve and there is no need to change anything with your custom code. 

There are so many of such needs where you have to repeat the code like password encryption. So combination of code generation and aspect make it so easy for you to reuse the code that you catch one more flick this evening ! ;)

My tweets on similar topics