Jul 24, 2016

The Evil of "Evil Annotations"

This is an evil article (Sorry I use the word "evil" which is copied from the article). And below is why
1) Annotation, like Java source code, is a way to express developer's intention to runtime environment. And it is a very expressive way of doing that. The author's point of "reducing the reusability of class" makes non-sense because:
  • the code with JEE annotation or other annotation is designed to run into a certain container/application server that follow the standard and understand the semantic of the anntoation as per designed
  • you can't blame Java source code reduce the reusabilty because it cannot run by a ruby interpreter, right?
2) In the "Evil Annotations Are Sometimes in the Wrong Place" section, the author point out that@ApplicationScoped does not belong to the class "DocumentFormatter" as shown below:
@ApplicationScoped  
public class DocumentFormatter {   
  ...  
}
And my view is: the annotation clearly expressed one important factor of the class: it is an application level singleton object, and container/application does not need to instantiate the instance of that class multiple times. Without using that annotation, you probably will go back to the Singleton pattern, which adds couple lines of code without any additional benefit.
The other example about JPA class is also funny, the point of "which couples the persistence directly to domain objects", should be rephrased into "which reduce the couples between persistence layer and domain object", because any persistence layer that implement the JPA requirement can handle your domain object. I wonder if the author is still thinking of writing his own JDBC code to handle persistence of the domain object. Here I want to mention that "persistence" IS one attribute of a domain object, and it is the system specification of your application, it is unfair to split it out from the domain object just because it doesn't represent the functional specification. If you are doing that, it's kind of like to say a programmer shall not eat because eating is not the domain feature of a programmer, which is just programming.
3) The author gives out the alternative to annotation: "of course good old Java Code", but I couldn't see any real world project/framework/application support that conclusion. And I want to point out the author's affinity to "the Java Language and its Compiler" is not generic in any way. The reason people relies on Java language and it's compiler is because it ONE of the standard of transfer developer's intention (in Java source code) into instructions to be run in a reliable standard environment (JVM). And there are many other "languages and compilers" could be used to do the same thing. On the flip side of the concern, the author looks like ignored the runtime environment which is also a standard part of the system, JVM is no doubt one of them, and JVM itself is not the only example of it. JEE containers and many other stacks are also good example of standard runtime environment, and they do recognized annotations (standard or even non-standard).
In conclusion, the problems of the article are:
  1. The author's overlook of system specification while highlighting functional specification. (Found in the JPA and @ApplicationScoped example)
  2. The author's overlook of Runtime environment while highlighting the language/compiler. (Found in across the whole article)

Mar 6, 2016

Introduce to ActFramework - an new MVC/RESTFul service framework in Java

I am happy to share my recent Open Source project ActFramework here.
So some events about ActFramework:
  1. About one year ago I start working on ActFramework.
  2. Three months ago I start using ActFramework to rewrite a commercial project which was written in Jersey originally, and the result is great. We have reduced the lines of code from 8900 to 4500 while keeping the same feature set and functionality.
  3. Last Wednesday I presented ActFramework in the first Sydney JVM meetup at FinTech hub in 2016.
In this blog I will brief major features of ActFramework

Controller

@GetAction("/")  
public void home() {
}    
@PostAction("/customer")   
public String createCustomer(Customer customer) {
      customerDao.save(customer);
      return customer.getId();  
}    
@PutAction("/customer/{id}/email")  
public void updateCustomerEmail(String id, String email) {
      Customer customer = customerDao.findById(id);
      notFoundIfNull(customer);
      customer.setEmail(email);
      customerDao.save(customer);
}
See the documentation for more about controller and action methods

Routing

There are two ways to create routing table:
  1. Through resources/routes file
    GET /customer/{id} any.pkg.CustomerController.get
    POST /customer any.pkg.CustomerController.create  
    ...  
  2. Through action method annoation as shown above
See the documentation for more about routing

Model and DAO

ActFramework support Morphia for MongoDB and Ebean for SQL. You can declare your Model class as a POJO with proper annotation. MorphiaDao and EbeanDao are provided to support find/save/delete entities:
@Entity  
public class Customer {
      @Id
      private ObjectId id;
      private String name;

      public void setId(ObjectId id) {
          this.id = id;
      }

      public ObjectId getId() {
          return this.id;
      }  

      public void setName(String name) {
          this.name = name;
      }  

      public String getName() {
          return this.name;
      }
}
public class CustomerController {
      @Inject MorphiaDao<Customer> dao;

      @GetAction("/customer")
      public Iterable<Customer> list() {
          return dao.findAll();
      } 

      @GetAction("/customer/{id}")
      public Customer get(String id) {
          return dao.findById(new ObjectId(id));
      }  

      @PostAction("/customer")
      public String create(Customer customer) {
          dao.save(customer);
          return customer.getId().toString();
      }
}
See the documentation on more about Model and DAO

Jobs and scheduler

public class MyClass {
      @Every("2s")
      public void jobA() {
          ...
      }  

      @InvokedAfter("MyClass.jobA")
      public void runAfterJobA() {  
        ...
      }   

      @OnAppStart
      public void jobB() {  
        ...
      }

      ...
}
See the documentation for more about jobs and scheduling

Events

public class CustomerController {
      @Inject
      EbeanDao dao;

      @Inject
      EventBus eventBus;

      public void create(Customer customer) {
          dao.save(customer);
          eventBus.trigger("new-customer", customer);
      }

}
@Mailer  
public class PostOffice extends Mailer.Util {

      @On("new-customer")
      @Async
      public void sendWelcomeLetter(Customer customer) {
          to(customer.getEmail());
          from("noreply@mycom.com");
          send(customer);
      }
}
See the documentation for more about events

Interceptors

  public class App {
      @Before(except = "login,logout")
      public void authenticate(ActionContext context) {
          if (!context.session().contains("username")) {
              if (context.isAjax()) {
                  throw new UnAuthorized();
              } else {
                  redirect("/login");
              }
          }
      }

      @Action(value = "/login" methods = {H.Method.GET, H.Method.POST})
      public void login() {
          ...
      }
  }
@With(App.class)  
public class CustomerController() {
      ...
}
See the documentation for more about interceptors

More features

  1. Sending Email
  2. Creating CLI commands

Comparing to PlayFramework v1.x

Project layout

Controller and action methods

  • Play controller must extends play.mvc.Controller. Action method must be void and static
  • Act controller does not need to extend any class. However extending act.controller.Controller.Util makes it easy to use renderXxx methods. Act action method does not need to be static. Act action method can return object

Routing

Templates

  • Play use groovy as default template engine
  • Act use Rythm as default template engine
  • Both framework support plugin different template engine

Models and DAO

  • Play's DAO methods are built into play.db.Model. Sub class get the data access capablitity via byte code enhancement
  • Act framework does not require Model class to extend any class. ActFramework inject default DAO implemenation to host class (e.g. a Controller, or Mailer) to provide DAO capablity

SQL Database access

  • Play use JPA/Hibernate to achieve SQL database access
  • Act use Ebean to achieve SQL database access

MongoDB access

  • Play use PlayMoprhia plugin (created by author of ActFramework) to access mongodb
  • Act use Morphia plugin to access mongodb

Jobs

  • Play job must be put into a class that extends play.jobs.Job. Each class implement one job logic
  • Act job is just a public void method without parameters. The class hosting job method does not require to extend any class

Events

Asynchronous http request handling

i18n

  • Play provides an easy to use i18n support
  • Act support i18n through Rythm's i18n() extension. Act's i18n support needs to be refined and improved

Cache

Sending email

Testing

  • Play provides a very descent testing facilities
  • Act relies on standard junit to implement application testing. Act also provides a specific act-test to support application's Model test. At the moment Morphia support is provided.

Security

  • Play provides limited security support. However there are some third party plugins like Deadbolt and play-aaa (created by author of ActFramework)
  • Act provides authentication/role based authorization/accounting via act-aaa

Modules and depedencies

  • Play applied it's specific way to manage modules and dependencies
  • Act relies on maven to manage dependencies and modules

Database evolutions

  • Play provides database evolution support
  • Act does not provide specific support on database evolution.

logging

  • Play provides a Logger class with static logging method. See document
  • Act does not have any specific class for logging. Developer could use any Logging solution (e.g. Log4J) in their application. However developer are also free to use App.logger to create log items.

Deployment

  • Play can be deployed as a fullstack application or as a war file in JEE application servers
  • Act support only fullstack application deployment at the moment (0.1.1-SNAPSHOT)

Resources

Dec 6, 2012

Thinking about creating an new Java Web framework

Why: I love playframework v1 but not v2. However play team moves their attention away from v1.

What should be kept from v1:

  • Bytecode enhancement. This is a great stuff that enable framework and plugin developer to inject logic into Application code
  • A full stack framework. This should like Play which runs on itself instead of inside a servlet container
  • Support plugins. Though API might changed
  • Handy utility libraries for application developer, like IO, Codec, Images etc.
  • Built in simple Secure framework
  • The DB layer enable plugin different implementations, JPA, EBean, Morphia etc.
  • Built in validation
  • Easy to use asynchronous handling API, like Promise and Controller.await
  • Before, After, Final, Catch intecepters to plugin logic into request handling chain
  • Render with different template based on request.format
  • JavaExtension to template
  • And most important is Simple, Simple and Simple to application developers

What needs to be improved or changed:
  • Routing mechanism. Improve the routing performance for big routing table with more than 100 routes. This might involve code generator to generate routing source code dynamically
  • Action invocation mechanism. Reduce the use of reflection, static methods and Exception. But needs to keep the API still simple though
  • Plugin API. Support partitioned plugin API set instead of all-in-one big facade
  • Replace python stuff with pure script plus Java
  • CRUD
  • Replace default Groovy template engine with Rythm
  • Replace default JPA with Ebean ???
  • JSON support

Proposed Controller API:

public class Orders extends Controller {

  // --- Parameters used in action handling methods
  @Bind(method = Bind.ByID)
  protected Order order; // will bind to http request params with Order.findById(params.get("orderId"))
  
  @Bind(method = Bind.ById)
  protected User user;
  // -- eof Parameters
  
  // this use new return style API
  @Required("orderId")
  public Result show() {
    return new Render(order);
  }

  // this use old style API
  @Required("orderId")
  public void saveUpdate() {
    notFoundIfNull(user);
    order.save();
    render(order, user);
  }
  
  // this action method will be executed in a separate thread
  @Async
  public Result report() {
    order.save();
    List orders = ...
    return new RenderPDF(orders);
  }
  
}

Sample route file:

GET /orders/{orderId} Orders.show
POST /orders/{orderId} Orders.saveUpdate
GET /orderReport Orders.report

What do you think?

Aug 17, 2012

ToString Mode and Auto ToString Mode of Rythm template engine

In a recent blog I've introduced SIM (String Interpolation Mode) of Rythm. This blog introduces another two new feature named TSM (ToString Mode) and ATSM (Auto ToString Mode) of Rythm

ToString Mode

This feature allows developers to create String toString() method for their class easily:

public class Address {
    public String unitNo;
    public String streetNo;
    public String street;
    public String suburb;
    public String state;
    public String postCode;
    // use Rythm.toString() API call
    @Override public String toString() {
        return Rythm.toString("@_.unitNo @_.streetNo @_.street, @_.suburb, @_.state, @_.postCode", this);
    }
}

As a comparison, previously you need to write toString() method in the following way:

    @Override public String toString() {
        return Rythm.render("@args Address _;@_.unitNo @_.streetNo @_.street, @_.suburb, @_.state, @_.postCode", this);
    }

So here are several facts about TSM:

  1. the sign "_" is used to refer to this object instance in the template
  2. You don't need to declare "_" use @args statement in TSM
  3. You must use Rythm.toString() interface instead of the normal Rythm.render() in order to use TSM

Auto ToString Mode

If TSM makes writting toString() easy, ATSM makes it even easier because you don't need to write the template:

public class Address {
    public String unitNo;
    public String streetNo;
    public String street;
    public String suburb;
    public String state;
    public String postCode;
    @com.greenlaw110.rythm.toString.NoExpose
    public String accessCode;
    @Override public String toString() {
        return Rythm.toString(this);
    }
}

And you can pass in parameters to configure the style and output fields:

@Override public String toString() {
    return Rythm.toString(this,
        com.greenlaw110.rythm.toString.ToStringOption.defaultOption.setAppendTransient(true),
        com.greenlaw110.rythm.toString.ToStringStyle.MULTI_LINE_STYLE);
}

The above code indicate that output transient fields which is not output by default. It also indicate that output should be in multiple lines. Refer to here for more details out the option and styling configuration.

You can use the following annotation to mark the fields that you don't want to output with Rythm's ATSM:

  • com.greenlaw110.rythm.toString.NoExpose
  • org.codehaus.jackson.annotate.JsonIgnore

Compare to Apache Commons Lang's StringBuilder

Like ATSM, org.apache.commons.lang3.builder.ReflectionToStringBuilder also allows to generate toString() output automatically. ATSM is slightly (around 20%) faster than ReflectionToStringBuilder. As a comparison, TSM is 2 times faster than it.

Foot notes: Rythm Template Engine is a static typed Java template engine using Razor like syntax. There is a full feature set demo hosted on GAE. The source code is hosted on github

Jun 30, 2012

Rythm now has SIM (String Interpolation Mode)

In the latest release of Rythm Template Engine you can use String Interpolation Mode (short to SIM later) for simple template, where simple template means something you can do with String.format().
String result = Rythm.render("Hello @who!", "Rythm");
As a comparison, previously you need the following code:
String result = Rythm.render("@args String who;Hello @who!", "Rythm");
It's really annoy to declare render argument types for such a simple template because we could treat the argument used in the expression as an Object. Yes, this is exactly what SIM did for you, automatically declare the argument reference to java.lang.Object type, and save your typing. Looks not a big deal, but it literally make Rythm.render() an replacement of String.format() for most cases. You get two benefit from Rythm SIM over String format:
  1. performance: Rythm.render is 2 times faster than String.format except the first call
  2. You can pass in arguments not only by position, but also by name
    Map<String, Object> args = new HashMap<String, Object>();
    args.put("who", "world");
    String result = Rythm.render("Hello @who!", args);
    

SIM Limitation

So as mentioned above SIM only applies to simple templates. The question is what defines a simple template?
  • First you can only have single variables in an expression, reference to class fields or method or any combination of two or more variables is not allowed. If you want to use these advanced expression, you must declare the type of the render arguments explicitly

    Rythm.render("the name is @user.username", user); // bad
    Rythm.render("the name is @name", user.username); // good
    Rythm.render("@args User user;the name is @user.username", user); // good
    
    Rythm.render("the sum is @(left + right)", left, right); // bad
    Rythm.render("the sum is @sum", left + right); // good
    Rythm.render("@args int left, int right;the sum is @(left + right)", left, right); // good
    
  • You cannot use some keywords. In other words, some Rythm template features are not available to SIM. Here is a list of Rythm keywords you should avoid to use in SIM:

    1. @args, declare template argument variables
    2. @extends, extends a layout template
    3. @section, define a template part to be inserted in the layout template
    4. @render, used in layout template to render a template section defined in sub template
    5. @doLayout, same as @render
    6. @doBody, call back tag body
    7. @include, include another template content in place
    8. @set, set template variable to be fetched by layout template
    9. @get, get the template variable set in the sub template
    10. @expand, execute/expand an macro
    11. @exec, same as expand
    12. @macro, define an macro
    13. @def, define an inline tag
    14. @tag, same as @def
    15. All extended keywords including the following defined in PlayRythm plugin
      1. @url, reverse url lookup
      2. @fullUrl, absolute reverse url lookup
      3. @msg, message lookup

How to render with SIM

Now the question is how to specify Rythm to render with SIM instead of ordinary rendering mode. The answer is simple, if your template does not contains the keywords listed above, Rythm will render the template in SIM.

Foot notes: Rythm Template Engine is a static typed Java template engine using Razor like syntax. There is a full feature set demo hosted on GAE. The source code is hosted on github

About Me

My photo