I have a hierarchy in my domain model, which is described by classes:
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class BaseEntity {
@Id
private Long id;
// other fields
}
@DiscriminatorValue(value = "Individual")
public class IndividualEntity extends BaseEntity {
// fields
}
@DiscriminatorValue(value = "Branch")
public class BranchEntity extends BaseEntity {
// fields
}
I'm fetching objects like this:
Specification<BaseEntity> specification = createSpecification();
BaseEntity entity = baseRepository.findOne(specification);
(I'm using spring-data)
The problem is that Hibernate returns proxy object (what I understand), but the proxy is of BaseEntity
, not the proper subclass (its' class is BaseEntity_$$_jvsted9_26
, therefore entity instanceof IndividualEntity
is false).
What is interesting, not all objects are returned as proxy.
I'm fetching entities in loop (common transaction), some of them are returned in normal form (i.e. IndividualEntity
/BranchEntity
), some as proxies.
If I change mechanism, so that every fetch is done in separate transaction - no proxy objects are returned at all.
I know that I can unwrap that proxy (e.g. like here), but what is the reason for such behaviour (kinda strange for me) and can I avoid it?
Hibernate session get method returns proxy object.
By definition, a proxy is “a function authorized to act as the deputy or substitute for another”. This applies to Hibernate when we call Session. load() to create what is called an uninitialized proxy of our desired entity class. This subclass will be the one to be returned instead of querying the database directly.
The JPA lazy loading mechanism can either be implemented using Proxies or Bytecode Enhancement so that calls to lazy associations can be intercepted and relationships initialized prior to returning the result back to the caller.
Proxy is a structural design pattern that provides an object that acts as a substitute for a real service object used by a client. A proxy receives client requests, does some work (access control, caching, etc.) and then passes the request to a service object.
Can't be certain without seeing more of the object model, but one reason Hibernate would do this is if the BaseEntity had already had to be resolved as a proxy for the same BaseEntity.id
earlier in the session.
For example, if there is another class that has a ToOne relation to a BaseEntity
, it will just have a foreign key to the id
, so will use a BaseEntity_$$...
proxy to delay resolving the correct subclass for the other end. This then becomes the instance for that id
that is managed in the Hibernate PersistenceContext
.
Clearly a Hibernate.unwrap()
, or one of the other options in the link above will reveal the 'true' instance. One other option is to use abstract methods on BaseEntity
(e.g. isIndividual()
). This can look a bit tidier, but ultimately Hibernate will still need to resolve the proxy when the method is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With