Reputation: 700
Imagine a situation:
@javax.persistence.Inheritance(strategy=javax.persistence.InheritanceType.JOINED)
@javax.persistence.DiscriminatorColumn
@javax.persistence.Entity
@javax.persistence.Table(name="PARENT")
public abstract class Parent{
...
}
@javax.persistence.Entity
@javax.persistence.Table(name="A")
public class A extends Parent{
...
}
@javax.persistence.Entity
@javax.persistence.Table(name="B")
public class B extends Parent{
...
}
Parent p = new A();
Now we call this:
p instance of A
always returns false!!
works ok on OpenJPA!
Should I file a bug? Hibernate 4.3.10
Upvotes: 2
Views: 4244
Reputation: 7141
This is most likely because hibernate is returning a proxy.
Why does it do this? To implement lazy loading the framework needs to intercept your method calls that return a lazy loaded object or list of objects. It does this so it can first load the object from the DB and then allow your method to run. Hibernate does this by creating a proxy class. If you check the type in debug you should be able to see the actual type is a generated class which does not extend from your base class.
How to get around it? I had this problem once and successfully used the visitor pattern instead of using instanceof
. It does add extra complication so it's not everyone's favorite pattern but IMHO it is a much cleaner approach than using instanceof
.
If you use instanceof
then you typically end up with if...else
blocks checking for the different types. As you add more types you will have to re-visit each of these blocks. The advantage of the visitor pattern is that the conditional logic is built into your class hierarchy so if you add more types it makes it less likely you need to change everywhere that uses these classes.
I found this article useful when implementing the visitor pattern.
Upvotes: 8
Reputation: 195
You can try to unproxy your object :
/**
*
* @param <T>
* @param entity
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T initializeAndUnproxy(T entity) {
if (entity == null) {
// throw new NullPointerException("Entity passed for initialization is null");
return null;
}
Hibernate.initialize(entity);
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
return entity;
}
Upvotes: 1
Reputation: 161
Not sure, but I think this will work.
public static boolean instanceOf(Object object, Class<?> superclass) {
return superclass.isAssignableFrom(Hibernate.getClass(object));
}
Upvotes: 4
Reputation: 1523
Hibernate returns Proxied Object. Rather than implementing a Visitor pattern (as described here), you can use the isAssignableFrom()
method on the class you want to test (https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#isAssignableFrom-java.lang.Class-).
Upvotes: 0
Reputation: 23226
That is because Hibernate uses run time proxies and OpenJPA, while supporting the proxy approach, prefers either compile time or runtime byte code enhancement.
See:
http://openjpa.apache.org/entity-enhancement.html
//Hibernate
Entity e = repository.load(entityId); // may return a proxy
//OpenJPA
Entity e = repository.load(entityId); //will return an (enhanced) actual instance of E
Upvotes: 0