4

I have those jpa Entities

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
class AbstarctAddress {


}

@Entity
public class ConsolidationHub extends AbstarctAddress {

}


@Entity
class Transport {

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "delivery_address_id")
   private AbstarctAddress address;

}

when I am doing

select t from Transport t left join fetch t.address

and then instanceof check like this

t.getAddress() instanceOf ConsolidationHub it returns false . This is because I got hibernate proxy. when I change to EAGER I don't have that problem. but I don't want to put EAGER since I have performance problems with EAGER.

Do you know how it is possible to solve this issue?

PS. I know that instanceOf check is bad practice, I just need to maintain old code in which there are lots of instanceOf checks and I cannot refactor all of them now.

user1321466
  • 1,559
  • 2
  • 15
  • 27
  • 1
    I don't know how to make that work in hibernate, sorry. But are you really solving the right issue here. Why not fix the performance issue? – Jocke Dec 28 '18 at 10:55
  • I have performance problem when I put EAGER, one way of solving performance problem is to change it to lazy and write JPA query with join fetch(but in that case I got problem with instanceOf). So do youhave some other suggestions ? Thanks.@Jocke – user1321466 Dec 28 '18 at 11:01
  • @user1321466, try t.getAddress().isAssignableFrom(ConsolidationHub.class) with lazy loading. – Ankur Dec 28 '18 at 11:19
  • "instanceof" is a perfectly valid operation in Java. Other JPA providers dont impose that on you. PS You spelt "Abstract" wrong –  Dec 28 '18 at 11:23
  • It may not be applicable in your case, and I haven't really tried it, but it may be possible to limit a priori the type of addresses fetched by the query, using the TYPE operator (see section 4.6.17.5 in JPA 2.1 specs). E.g.: `SELECT t FROM Transport t LEFT JOIN FETCH t.address a WHERE TYPE(a)='ConsolidationHub'`. I am not sure if it would actually work with relationships. – Nikos Paraskevopoulos Dec 28 '18 at 12:03
  • If you want perform instanceOf check, you can use `Hibernate.getClass(proxyObject)` – Tijkijiki Dec 28 '18 at 15:27
  • In Hibernate 5.2.10 `unproxy` [method](https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/Hibernate.html#unproxy-java.lang.Object-) has been introduced. Maybe you can use it in the getter? It is also doable in older versions with slightly [more code](https://stackoverflow.com/a/11228887/1654233). – yegodm Jan 02 '19 at 15:58

1 Answers1

2

I'm afraid the answer is: start writing OOP code. instanceof flies in the face of polymorphism. The clients of a class should never care which specific subtype/implementation they are talking to.

If you used entity inheritance, and now need to use instanceof in your code, your design is most probably flawed. Hibernate uses proxies on many occasions, and you cannnot rely on instanceof or .getClass() always returning the exact class of your entity.

If, on the other hand, you've used instanceof out of curiosity, and were surprised to find that it actually returns false, fear not, all calls you make to this entity proxy are still polymorphic.

The reason why instanceof fails here is that Hibernate needs to initialize the lazy property with something, and it cannot determine the type of that something until the property is loaded. If you insist on using instanceof, you may try enabling entity enhancement.

crizzis
  • 7,901
  • 2
  • 22
  • 36