
Hibernate: lazy loading, inheritance and instanceof
Consider, as an example, the following situation. We have a User class with fields describing the user. There is a Phone class that is the parent of the CellPhone and SatellitePhone classes. In the User class, there is a field containing a list of user phones. In order to reduce the load on the database, we made this list “lazy." It will be downloaded only on demand.
In this configuration, when querying the list of phones of a specific user, we can get both a list of initialized phone objects (for example, if they are already in the cache), and a list of proxy objects.
In most situations, it does not matter to us what exactly we are working with (a real object or its proxy). When you request a field of any object, the proxy object is automatically initialized, and we will receive the expected data. But if we need to find out the type of object, then everything goes awry.
Let's see why this happens. The main problem is that Hibernate is not psychic and cannot know in advance (without fulfilling database queries) what type of objects are contained in the list. Accordingly, it creates a list containing proxy objects inherited from Phone.

When our team first encountered this problem, we studied this issue a bit and realized that we would have to make a “crutch”. The error occurred in the service method where it was necessary to know exactly which of the child classes we are dealing with. Right before this check, we implemented another: if the object is a proxy object, then it is initialized. Then safely forgotten this unpleasant story.
Over time, the project grew, the business logic became more complicated. And then came the moment when there were already too many such crutches (we realized that this would not work on the third or fourth crutch). Moreover, this problem began to arise not only when querying one object for a lazy list of other objects, but also when directly querying the list of objects from the database. I really did not want to refuse lazy loading. our base is so heavily loaded. We decided to no longer mix the architectural layers of the application and create something more universal.

Scheme of our application
In this scheme, the DAO layer deals with database queries. It consists of 1 abstract class JpaDao in which all the basic methods for working with the database are defined. And many classes - its heirs, each of which ultimately uses the methods of the base class. So, how did we overcome the problem of directly querying a list of objects of different types with a common parent? We created methods in the JpaDao class to initialize a single proxy object and initialize a list of proxy objects. With each request for a list of objects from the database, this list is initialized (we deliberately went to this step because if we request some list of objects in our application, then it is almost always needed that is fully initialized).
With the solution to the first problem, everything turned out not so smoothly. The above method does not work because Hibernate is directly involved in lazy loading. And we made a small concession. In all objects containing lazy lists of different types of objects with one parent (for example, User with the Phone list), we redefined getters for these lists. As long as the lists are not requested, everything is in order. The object contains only a proxy list and unnecessary requests are not executed. When a list is requested, it is initialized.
In this article, I demonstrated how to use the lazy Hibernate load when using lists containing objects of different types (with one parent), used in my team. Hope this example helps someone in a similar situation. If you know a more optimal / beautiful way to overcome this problem, I will be glad to add it to the article.
It all looks something like this
public class User {
...
@OneToMany(fetch = FetchType.LAZY)
private List phones = new ArrayList();
public List getPhones() {
return phones;
}
}
public class Phone {
...
}
public class CellPhone extends Phone {
...
}
public class SatellitePhone extends Phone {
...
}
In this configuration, when querying the list of phones of a specific user, we can get both a list of initialized phone objects (for example, if they are already in the cache), and a list of proxy objects.
In most situations, it does not matter to us what exactly we are working with (a real object or its proxy). When you request a field of any object, the proxy object is automatically initialized, and we will receive the expected data. But if we need to find out the type of object, then everything goes awry.
Let's see why this happens. The main problem is that Hibernate is not psychic and cannot know in advance (without fulfilling database queries) what type of objects are contained in the list. Accordingly, it creates a list containing proxy objects inherited from Phone.

When our team first encountered this problem, we studied this issue a bit and realized that we would have to make a “crutch”. The error occurred in the service method where it was necessary to know exactly which of the child classes we are dealing with. Right before this check, we implemented another: if the object is a proxy object, then it is initialized. Then safely forgotten this unpleasant story.
Over time, the project grew, the business logic became more complicated. And then came the moment when there were already too many such crutches (we realized that this would not work on the third or fourth crutch). Moreover, this problem began to arise not only when querying one object for a lazy list of other objects, but also when directly querying the list of objects from the database. I really did not want to refuse lazy loading. our base is so heavily loaded. We decided to no longer mix the architectural layers of the application and create something more universal.

Scheme of our application
In this scheme, the DAO layer deals with database queries. It consists of 1 abstract class JpaDao in which all the basic methods for working with the database are defined. And many classes - its heirs, each of which ultimately uses the methods of the base class. So, how did we overcome the problem of directly querying a list of objects of different types with a common parent? We created methods in the JpaDao class to initialize a single proxy object and initialize a list of proxy objects. With each request for a list of objects from the database, this list is initialized (we deliberately went to this step because if we request some list of objects in our application, then it is almost always needed that is fully initialized).
JpaDao implementation example
public abstract class JpaDao {
...
private ENTITY unproxy(ENTITY entity) {
if (entity != null) {
if (entity instanceof HibernateProxy) {
Hibernate.initialize(entity);
entity = (ENTITY) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
}
return entity;
}
private List unproxy(List entities) {
boolean hasProxy = false;
for (ENTITY entity : entities) {
if (entity instanceof HibernateProxy) {
hasProxy = true;
break;
}
}
if (hasProxy) {
List unproxiedEntities = new LinkedList();
for (ENTITY entity : entities) {
unproxiedEntities.add(unproxy(entity));
}
return unproxiedEntities;
}
return entities;
}
...
public List findAll() {
return unproxy(getEntityManager().createQuery("from " + entityClass.getName(), entityClass).getResultList());
}
...
}
With the solution to the first problem, everything turned out not so smoothly. The above method does not work because Hibernate is directly involved in lazy loading. And we made a small concession. In all objects containing lazy lists of different types of objects with one parent (for example, User with the Phone list), we redefined getters for these lists. As long as the lists are not requested, everything is in order. The object contains only a proxy list and unnecessary requests are not executed. When a list is requested, it is initialized.
An example implementation of the getter list of phone numbers for a user
public class User {
...
@OneToMany(fetch = FetchType.LAZY)
private List phones = new ArrayList();
public List getPhones() {
return ConverterUtil.unproxyList(phones);
}
}
public class ConverterUtil {
...
public static T unproxy(T entity) {
if (entity == null) {
return null;
}
Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return entity;
}
public static List unproxyList(List list) {
boolean hasProxy = false;
for (T entity : list) {
if (entity instanceof HibernateProxy) {
hasProxy = true;
break;
}
}
if (hasProxy) {
LinkedList result = new LinkedList();
for (T entity : list) {
if (entity instanceof HibernateProxy) {
result.add(ConverterUtil.unproxy(entity));
} else {
result.add(entity);
}
}
list.clear();
list.addAll(result);
}
return list;
}
}
In this article, I demonstrated how to use the lazy Hibernate load when using lists containing objects of different types (with one parent), used in my team. Hope this example helps someone in a similar situation. If you know a more optimal / beautiful way to overcome this problem, I will be glad to add it to the article.