31

I want to persist my litte zoo with Hibernate:

@Entity
@Table(name = "zoo") 
public class Zoo {
    @OneToMany
    private Set<Animal> animals = new HashSet<Animal>();
}

// Just a marker interface
public interface Animal {
}

@Entity
@Table(name = "dog")
public class Dog implements Animal {
    // ID and other properties
}

@Entity
@Table(name = "cat")
public class Cat implements Animal {
    // ID and other properties
}

When I try to persist the zoo, Hibernate complains:

Use of @OneToMany or @ManyToMany targeting an unmapped class: blubb.Zoo.animals[blubb.Animal]

I know about the targetEntity-property of @OneToMany but that would mean, only Dogs OR Cats can live in my zoo.

Is there any way to persist a collection of an interface, which has several implementations, with Hibernate?

Olvagor
  • 2,332
  • 5
  • 25
  • 26

3 Answers3

31

JPA annotations are not supported on interfaces. From Java Persistence with Hibernate (p.210):

Note that the JPA specification doesn’t support any mapping annotation on an interface! This will be resolved in a future version of the specification; when you read this book, it will probably be possible with Hibernate Annotations.

A possible solution would be to use an abstract Entity with a TABLE_PER_CLASS inheritance strategy (because you can't use a mapped superclass - which is not an entity - in associations). Something like this:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractAnimal {
    @Id @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;
    ...
}

@Entity
public class Lion extends AbstractAnimal implements Animal {
    ...
}

@Entity
public class Tiger extends AbstractAnimal implements Animal {
    ...
}

@Entity
public class Zoo {
    @Id @GeneratedValue
    private Long id;

    @OneToMany(targetEntity = AbstractAnimal.class)
    private Set<Animal> animals = new HashSet<Animal>();

    ...
}

But there is not much advantages in keeping the interface IMO (and actually, I think persistent classes should be concrete).

References

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Truth is, my real problem is a bit more complex than the question above so your answer doesn't work in my case. But it looks like a correct answer to my question so I'll accept it. Thanks! – Olvagor May 27 '10 at 14:38
  • 1
    Any idea why the abstract class `AbstractAnimal` doesn't implement the interface `Animal`? – maxxyme Dec 02 '15 at 10:46
  • @Pascal, I tried this but then seems to require a table for AbstractAnimal table, which is not ideal but I can live with it. However after the Animal insert happens, the Animal needs a reference to a zoo and that fails because the update goes against AbstractAnimal rather than the concrete animal. – ssc327 Dec 30 '22 at 21:42
1

I can guess that what you want is mapping of inheritance tree. @Inheritance annotation is the way to go. I don't know if it will work with interfaces, but it will definitely work with abstract classes.

yatskevich
  • 2,085
  • 16
  • 25
  • I'll try that and if it doesn't work I'll go for abstract classes. – Olvagor May 26 '10 at 12:54
  • Yep, abstract class is a better solution. As Péter Török has already said, you can put the id and other common properties to the Animal class. – yatskevich May 26 '10 at 13:55
0

I think you have to annotate the interface too with @Entity and we have to annotate @Transient on all getters and setters of interface.

sammy
  • 21
  • 1
  • 1
  • 6