简体   繁体   中英

JPA/Hibernate instance of not working

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

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.

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 

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- ).

Not sure, but I think this will work.

public static boolean instanceOf(Object object, Class<?> superclass) {
    return superclass.isAssignableFrom(Hibernate.getClass(object));
}

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;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM