I’ve been working on converting from OpenJPA for a while, and this issue is giving me problems.
I have an inherited class using the InheritanceType.JOINED strategy. I’m using a lazy many-to-one relationship to the base class.
public class Person {
...
@ManyToOne(fetch = FetchType.LAZY)
protected Company company; // Can be a CustomerCompany or a DistributorCompany
@ManyToOne(fetch = FetchType.LAZY)
protected Department department; // Simple entity
...
}
When I fetch a Person, then call the getter for Department, Hibernate returns a Department object.
But when I call the getter for Company (polymorphic), I get an object of type Company$HibernateProxy$…, which “is a” Company, but is NOT a CustomerCompany.
I’d like to know if this is a bug with enableLazyInitialization for polymorphic classses. I can work around this using unproxy, but that complicates the code and seems to defeat the purpose of enhancement.
Here’s a snippet of code in my little test project:
Person person1 = entityManager.find(Person.class, 1l);
Department p1Department = person1.getDepartment();
Company p1Company = person1.getCompany();
System.out.println("p1Department is a " + person1Department.getClass().getSimpleName()); // p1Department is a Department
System.out.println("p1Company is a " + person1Company.getClass().getSimpleName()); // p1Company is a Company$HibernateProxy$xgY84llh
CustomerCompany customerCompany = (CustomerCompany) p1Company; // Exception: class Company$HibernateProxy$xgY84llh cannot be cast to class CustomerCompany
Associations that are FetchType.LAZY can always use proxies, so using instanceof, getClass() or explicitly casting them is not the recommended way of handling polymorphism. Until Hibernate initializes the association, we cannot know the sub-type of the Company entity since we’re going to need a query to the database to find out. If you wish to keep the lazyness aspect, I suggest using the Hibernate.getClassLazy() method to retrieve the specific class (not this will already trigger initialization) and Hibernate.unproxy() to retrieve the actual instance and cast it to e.g. CustomerCompany.
If you know you’re going to need the associated entity, you could make the association EAGER; if you only need it in some cases, you can always explicitly join fetch the association or specify an EntityGraph to eagerly load the entity instance for that specific need.
Thanks for the suggestions. I was hoping that since bytecode enhancement allows initializing lazy fields to actual entities (non-proxy), that it would also work with polymorphic classes. Wouldn’t that be a desirable feature?
With bytecode enhancement it would be possible to do this, but doing that would require to run a query to initialize the Company before the object is first “observable” by the application. This won’t get rid of proxies fully either though, because a proxy for a Company could come into existence in the persistence context through other means as well (EntityManager#getReference() call or other LAZY associations).
You could disable proxying entirely by annotating @Proxy(lazy = false) on the Company class, but I would not recommend that.
I would recommend you to implement your polymorphism needs through overridable methods instead, since methods are delegated to the actual instance of the correct type.
You could e.g. do the following:
class Company {
//...
@Transient
public Class<?> getRealClass() {
return getClass();
}
}
Isn’t the idea of lazy loading that it would perform a query on an entity when you first observe it? Maybe I’m missing something here.
Adding a method to call for the real class is not a great solution for me because in some cases I have an object who’s class could be any of 10 types (not all polymorphic), and I would have to modify each of the types to implement that method.
I would prefer if the lazy loading for bytecode-ehnahced entities would bring in real entities.
Or if the proxy object were a proxy of the subclass (CustomerCompany) - but that would probably require bringing in the discriminator column in a join when loading the Person entity.
Isn’t the idea of lazy loading that it would perform a query on an entity when you first observe it? Maybe I’m missing something here.
The idea of lazy loading is to only query a table for the data based on a foreign key if the data is accessed. Observing the object e.g. proxy is not considered to be a data access and hence no query is executed when your application gets your hands on a proxy. Only when you call a method (other than the getter for the identifier) on that proxy, it will initialize the proxy.
I would prefer if the lazy loading for bytecode-ehnahced entities would bring in real entities.
Or if the proxy object were a proxy of the subclass (CustomerCompany) - but that would probably require bringing in the discriminator column in a join when loading the Person entity.
Like I wrote, there are other possible scenarios that can lead to a proxy of the supertype being added to the persistence context. Creating a proxy of the subclass is not possible as that requires knowledge of the concrete entity type.
Adding a method to call for the real class is not a great solution for me because in some cases I have an object who’s class could be any of 10 types (not all polymorphic), and I would have to modify each of the types to implement that method.
The example I gave you would only require to add one method to the parent entity type.