Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Inheritance - Getting superclass instance and casting into subclass

Tags:

java

hibernate

Consider this scenario.

There are plots, some are residential plots and some are commercial plots.

There are also owners. But an owner can buy only a plot and it can be residential or commercial.

So, here is my code.

@Entity
@Table(name = "PLOT")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Plot {
  private int id;
  private String number;
  private List<Owner> owners = new ArrayList<>();

  // getters and setters...
}


@Entity
@Table(name = "RESIDENTIAL_PLOT")
@PrimaryKeyJoinColumn(name = "PLOT_ID")
public class ResidentialPlot extends Plot {
  // Some fields
}


@Entity
@Table(name = "COMMERCIAL_PLOT")
@PrimaryKeyJoinColumn(name = "PLOT_ID")
public class CommercialPlot extends Plot {
  // Some fields
}


@Entity
@Table(name = "OWNER")
public class Owner {
  private int id;
  private String name;
  private Plot plot;

  // getters and setters
}

All works well, but when I call owner.getPlot() I was expecting ResidentialPlot or CommercialPlot instance So, I can apply appropriate operation by using instanceof operator. But it does not satisfy both conditions!

What am I doing wrong?

like image 477
Akshat Avatar asked Nov 20 '13 10:11

Akshat


People also ask

Can you cast from superclass to subclass?

You can try to convert the super class variable to the sub class type by simply using the cast operator. But, first of all you need to create the super class reference using the sub class object and then, convert this (super) reference type to sub class type using the cast operator.

Which inheritance strategy is better in hibernate?

Single Table. The single table strategy maps all entities of the inheritance structure to the same database table. This approach makes polymorphic queries very efficient and provides the best performance.

How is inheritance implemented in hibernate?

There are three inheritance mapping strategies defined in the hibernate: Table Per Hierarchy. Table Per Concrete class. Table Per Subclass.

Does the assignment of a superclass to a subclass require a cast?

Java doesn't allow assigning a superclass object to a subclass one. To do so would require explicit casting, or known as downcasting.


1 Answers

You're not using polymorphism, and it hurts even more in a JPA environment.

The reason you observe this behavior is because of the usage of proxies by Hibernate. When Hibernate loads an Owner, it can't tell if the plot is a commercial or residential plot. It would have to do an additional query to know it. So it initializes the plot field with a lazy proxy, which is an instance of a dynamically generated class which extends Plot, but is neither a CommercialPlot nor a ResidentialPlot.

When a method is called on the proxy, the proxy initializes itself by getting the Plot data from the database, and it delegates to an instance of CommercialPlot or ResidentialPlot.

The solution is to use ploymorphism. Add an abstract method to the Plot class (getType(), or isResidential(), for example), and implement it in both subclasses. If that isn't possible because you need business logic that depends on the entity type but shouldn't be in the entity itself, use the visitor pattern.

I wrote a blog article on this subject if you need more details, but it's in French. Maybe Google Translate could help you.

like image 119
JB Nizet Avatar answered Nov 03 '22 14:11

JB Nizet