Different join table for inherited classes?

How would I handle specifying a different @JoinTable in inherited classes?

For example, if I began with the example in the documentation, and I wanted to subclass Person to create Employee and have a different @JoinTable (because it’d have a different PK). What’s the right way to go about about specifying a different Join? Would the field need to be overridden with new annotations provided?

So, I think the answer is to use an @AssociationOverride annotation to specify the JoinTable for a field. However, my use case is more complicated than that. What I’d like to do is to directly get a collection of objects through an intermediate table by specifying a value for a third column. I think this would require a Hibernate @WhereJoinColumn annotation, but I’m not sure how to make that work. Can I put that on the parent class despite the @AssociationOverride in the child class?

Haven’t gotten anywhere with the @AssociationOverride.

Here’s my issue: I have a pair of similar objects and an associated join table. On the database side, it’s fine if these are separate tables, but I want to maintain similarity because I will want to move records from one to the other. On the application side, I don’t know how to intersect inheritance (“DRY”) with Hibernate. It would make sense to put all the commonality in an abstract class and create two subclasses from that. This would necessitate two separate join classes as the relating entity would be different. However, this also means I cannot put common functionality in the abstract class as it would be referencing join class types. I could use an interface, but I cannot get data with Hibernate for interfaces.

How can I make Hibernate work for this case? I can post some example code if it would be helpful (I don’t feel like I’m explaining it well).

You only need the interface to interact with objects in your user code. I’d suggest, since all you seem to care about is reusability, that you put all persistent attribute definitions into the subclasses and introduce interfaces so you can reuse logic. For example:

interface CanSwim {
  int getLocation();
  void setLocation(int location);

  default void swim() {
    setLocation(getLocation() + 1);

class Person implements CanSwim {
  private int location;
  public int getLocation() {
    return location;
  public void setLocation(int location) {
    this.location = location;