Thursday, January 14, 2016

Why JPA Entity or Hibernate Persistence Class Should Not be Final?

One of the interesting hibernate interview questions is, why you should not make a Hibernate persistent class final? I'll try to answer this question in this short blog post. Use of proxies is the core feature of Hibernate (one of the most popular ORM framework for Java Projects) for implementing key performance features e.g. lazy loading and lazy associations fetching. In order to use a proxy in place of real class, your hibernate persistence class must be either non-final or the implementation of an interface that declares all of the public methods. Why? because you cannot extend a final class in Java, and to stand up as a proxy, proxy class must satisfy the IS-A relation, which comes either by extending a class using "extends", or implementing an interface using "implements".

By the way, it doesn't mean that you cannot persist your final entity class, you can, but this will limit Hibernate's ability to use proxies for lazy association fetching, which will affect the performance of Java application, read Java Persistence with Hibernate by Gavin King, the author of Hibernate to learn more about this feature.

Hibernate framework makes extensive use or proxy e.g. it uses proxies when you call the load() method, it also uses proxies for lazily loading associations and collections of an entity class. Even Hibernate  Reference Manual says "Prefer non-final classes".

Not using proxies is bad for performance because more SQL than you'd like may be fired against the database, which also increases database round-trips. You can verify this by printing class name of your entity class and look at Hibernate query logs, as shown in the following example:

Let's say you load your entity class e.g. a Book, an Employee or a Customer using the load() method and further print name of class, you will see a different name e.g.

Customer customer = (Customer) session.load(Customer.class, 1L);"Name of Customer Entity class : " + customer.getClass());

will print "sample.hibernate.Customer_$$_javassist_0" which is a JavaAssist generated the proxy.

You will not see any select query fired because the load is lazy and it will not load object until you call any method other than the getId(), as seen in the difference between the get() vs load() in Hibernate article.

Now, if you make the class final and reprint the name of the class, you will see the actual name of the class as "Customer". You will also see the select queries fired by hibernate to initialize the object.

You should now understand how costly it can be if you are creating too many objects and only accessing their getId() method, as it will result in lots of database calls. That's why you should not make your JPA Entity or Hibernate persistence class final in Java. Let's see some more points in next section.

Hibernate interview questions with answers

Important points to about Entity class, Final, and Proxying

Let's revise a couple of important things about a JPA entity class, final modifier and use of Proxy design pattern in Hibernate framework.

1) Hibernate doesn't create a proxy for final class, instead, they use the real class, but Hibernate does create a proxy for a non-final class with final methods.

2) Since in Java, you cannot override final methods, the code inside final method remain unchanged in the proxy class. Which means, if you call a final method on a proxy, it will simply delegate the call to the super class method. You should be careful not to modify state on final method because calling them on proxy has a good chance of throwing NullPointerException, as the object was likely to be not initialized at that point.

In short, avoid final methods on hibernate entity class, until you know what you are doing. Hibernate reference also stress this point "You should  avoid declaring public final methods as this will again limit the ability to generate proxies from this class. If you want to use a class with public final methods, you must explicitly disable proxying".

3) As per Hibernate documentation, if  you're going to make a class final you should explicitly disable proxy generation by adding @Proxy(lazy=false), but I haven't noticed any differences between doing that and just making the class final.

4) You should also disable proxy generation if you're going to make any public methods final in persistent class, as hibernate will not be able to override them to put its smart code which triggers lazy loading etc.

5) If you really want to make the Hibernate entity classes final then you can do it by having your entity implement an interface that declares all of its public methods. This will still allow Hibernate to use proxies.

In short, making a JPA Entity or Hibernate Persistence class final, limits the ability of Hibernate to use Proxies, which in turn prevent Hibernate from applying some performance optimizations. Without proxies, your application loses lazy loading, and lazy association fetching will issue more SQL queries and make more database roundtrip, which will cost performance.

The only way to make a Hibernate entity class final without losing lazy behavior is to use interface and define all public methods of persistence class there, this will still allow Hibernate to use a proxy in place of real class, see Java Persistence with hibernate more details.

Why Hibernate Entity class should not be final in Java

Related Hibernate and Spring Interview Questions
  • Difference between save(), persist() and saveOrUpdate() in Hibernate? (answer)
  • Difference between First and Second level cache in Hibernate? (answer)
  • Difference between get() and load() method in Hibernate? (answer)
  • What should you remember while overriding equals() and hashCode for Hibernate entity class?(answer)
  • Why default or no-argument constructor is important in Java? (answer)
  • When should you use setter and constructor injection in Spring? (answer)
  • What is the default bean scope in Spring framework? (answer)
  • What is the difference between BeanFactory and ApplicationContext in Spring? (answer)

Further Learning
Introduction To Hibernate
Spring and Hibernate for Beginners
Hibernate Interview Questions Preparation Course

No comments :

Post a Comment