I have two entities. One inherited from the other.
Example:
@Entity
@Table(name = "vehicle")
@Inheritance(strategy = InheritanceType.JOINED)
public class VehicleEntity {
//id, etc., all reference fetch type is LAZY
}
@Entity
@Table(name = "car")
public class CarEntity extends VehicleEntity {
//special parameters, all reference fetch type is LAZY
}
When I call a find() on EntityManager with an existing car's id like this:
VehicleEntity vehicleEntity = entityManager.find(VehicleEntity.class, carID);
I get back a proxy object, but I need to access the special methods of the CarEntity class, because I would like to set some new parameters.
Can someone help me how can I do this?
Of course this is just an example problem. More specifically: after I call find I'm checking the instance of the returned object, if it is "CarEntity" I set the parameters, if not I don't do anything. I have much more inherited classes beside "CarEntity", and I do the same procedure like before. I know I could solve this with "find"s on the specific object classes, but then I have to call "find" several times, and when I'm looking for any "VehicleEntity" I'm always interested in the actual object so the best would be a global solution.
Consider the following sequence of statements:
VehicleEntity vehicleEntityProxy = entityManager.getReference(VehicleEntity.class, carID);
VehicleEntity vehicleEntityInitialized = entityManager.find(VehicleEntity.class, carID);
The vehicleEntityProxy
is a proxy, because you wanted it to be (obtained via getReference
).
In the second statement, you want an initialized instance, so you are obtaining it with find
:
Find by primary key. Search for an entity of the specified class and primary key. If the entity instance is contained in the persistence context, it is returned from there.
So, find
will check whether the instance is already in the persistence context, it will determine that it is because there is already a proxy created in the first statement, it will initialize the proxy (because it delegates to Hibernate Session.get
which never returns an uninitialized instance) and will return the proxy.
The similar thing happens if instead of the first statement you have loaded some other entity which has a lazy to-one association to the VehicleEntity
with the carID
id. Then a proxy is created in place of the real entity instance, and that proxy will be returned (and initialized if not already) from the find
method when finding the entity for the same id.
All of this further implies that instanceof
is not your friend when working with Hibernate proxies (putting aside that it is not your friend in general when it comes to good OOP code).
As a workaround you could deproxy the object:
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
But this is tedious and error prone (and unnecessarily exposes Hibernate specific API). Also, you may need to do it for all of the associated objects as well since they can be proxies also.
Better approach is to use proven OOP constructs and patterns, like the Visitor
pattern:
class Vehicle {
...
public void accept(VehicleVisitor visitor) {
}
}
class Car extends Vehicle {
...
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
class Bus extends Vehicle {
...
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
interface VehicleVisitor {
void visit(Car car);
void visit(Bus bus);
}
Now, instead of:
Vehicle vehicle = entityManager.find(Vehicle.class, vehicleId);
if (vehicle istanceof Car) {
Car car = (Car) vehicle;
// Do something with car
}
if (vehicle istanceof Bus) {
Bus bus = (Bus) vehicle;
// Do something with bus
}
you can do:
class SomeVehicleVisitor implements VehicleVisitor {
public void visit(Car car) {
// Do something with car
}
public void visit(Bus bus) {
// Do something with bus
}
}
SomeVehicleVisitor visitor = ...
Vehicle vehicle = entityManager.find(Vehicle.class, vehicleId);
vehicle.accept(visitor);
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