Thank you very much for taking the time and giving me feedback.
close
Visitors are also reading...
Next →

Cleaner Java Code with CGLIB

20 Oct 2009

ASM - allows you to generate byte code at runtime.
It might not mean much to you at the moment, but this is a strong ability.
For example - this ability allowed the creation of the Groovy language.

Today I will show how hibernate uses ASM.

If You Use Hibernate, You Use CGLib! - Lazy Load With Hibernate

Lets say we have an Office object with One-To-Many relationship to another object called Employees.
The Office object will have a field that looks like this :

class Office {   
 @Column  
 String name;  

 @Column  
 String address;  

 @OneToMany(mappedBy = "office")  
 Collection<Employees> employees = new ... ;

 // getters and setters  
 public Collection<Employees> getEmployees{return employees;}
}

I also created a field for Name and Address.
The most important thing in the code above is the getter for employees, note that it does not run any query.

Search Feature By Name/Address Does Not Require Employees

Now lets assume for a minute I am writing a “search office by name or address” feature
For this feature, we only need the “name” and “address” of each Office.
We do not need the employees field.
So it will be better for performance that we do not query the database for them.
We can tell hibernate to not query for the empolyees unless we use the getter “getEmployees”. To achieve this, lets add “Lazy” definition to the “employees field annotation”

 @OneToMany(mappedBy = "office", fetch=FetchType.LAZY)  
 Collection<Employees> employees = new ... ;

Hibernate uses two queries to create the object we need, however - when you use lazy loading
this second query will execute only when we invoke the getter.
The queries will be :

  1. Query to fetch the office
  2. Query to fetch the employees when we use the getter

How does hibernate detect that I invoked the getter ?
The getter is a normal getter, it does not reference hibernate or the database in any way..
To understand the answer, you should stop the application in debug to see the runtime classname of the Office object.
You should see something like this :

packageName.Office$EnhancedByCGLIB$<id>@<number>

The field is standard information for any object and is not relevant in this discussion.
The ID is some unique identifier generated by CGLIB and is also of no real importance to us.
The important thing to see is that we didn’t get Office, but some other class.
This class was obviously not generated in compile time - we can check the contents of the jars to verify - so what happens here ?

Hibernate generates a new class in runtime.
This new class is called Office$EnhancedByCGLIB<div class="mograblog" and it has the exact same API as myOffice` class,
but at runtime, a different code is running.
This code is the “enhanced” class generated by CGLib.
The enhanced class has a reference to the Database and when it executes the getter for employees another query is executed.

When Should I Use CGLib?

It’s always hard to identify when you should or should not use some technology in your code.
For example - if I need a single connection to the Database for a small query,
it would be a shame to use Spring in order to initialize a connection pool and run in a different thread.

I find CGLIB most useful in configuration objects.
I also used it to extend selenium.

So for configuration purposes, I want my application to have code like this :

 class Configuration{  
   String username;   
   String password;   
   // getter and setter ...   
 }  

 Configuration myConf = new Configuration();   
 // myConf.getUsername() -- will get the username  
 // myconf.getPassword() -- will get the password

This way I can decouple my configuration fields from the configuration mechanism.
It does not matter if I use a JSON file, a YAML file, environment variable etc..
I can actually use them all!
I actually used this mechanism a couple of times, and it is quite useful.
It is especially useful when you want well structured objects for configuration and to easily initialize them with default values.
You can see it in My Play!Framework 2 Survival Kit!

References

Next →