简体   繁体   中英

Mapping of generic classes in Hibernate

I have following classes in a Java Hibernate project:

@Entitiy
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ClassA<T extends ClassB>{

    @OneToOne
    @JoinColumn(name = "mycolumn_id")
    private T instance;

[...]

}


@Entitiy
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class ClassB{

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer id;

[...]

}

When I try to create/save an instance of ClassA (with an instance of a class which inherits ClassB) I get the following exception:

org.hibernate.AnnotationException: Property ClassA.instance has an unbound type and no explicit target entity. Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type

I can't set an explicit target to "T instance" in ClassA because ClassB is abstract and the literal "T.class" is not valid. However the generic usage is necessary because I have to save many different types of ClassB in ClassA.

How can I solve this problem?

After lots of testing, trying to get Java parameterisation working with an abstract parent (Single-table inheritance), and an abstract child table (one-table-per-class inheritance), I've given up.

It may be possible, but often you get problems where Hibernate tries to instantiate an abstract (parameterised) class as an entity.

I would suggest rewriting it using the JPA inheritance, moving the parameterised stuff down into extending classes. That way you get the same polymorphism back from the database.

@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "CLASS_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class ClassA {

  [...]

}

extension B:

@Entity
@DiscriminatorValue=("B")
public class ClassB extends ClassA {
  @OneToOne
  @JoinColumn(name = "mycolumn_id")
  private Integer instance;

  [...]
}

extension C:

@Entity
@DiscriminatorValue=("C")
public class ClassC extends ClassA {
  @OneToOne
  @JoinColumn(name = "mycolumn_id")
  private String instance;

  [...]
}

This error comes from hibernate trying to create an entity from an abstract class (either specified as 'abstract', or using the Java parameter).

You need to create an abstract base class, which is NOT an entity, and then extend that for specific types. Your subtypes can add columns which are nullable in the table, and/or specify the parameter.

@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TRACK_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class ClassA<T extends ClassB>{

    @OneToOne
    @JoinColumn(name = "mycolumn_id")
    private T instance;

[...]

}

You also need to decide whether ClassB is extending ClassA, or is a related table. You can't have B extending A, but use a different inheritance type. Assuming Single-Table:

@Entity
@DiscriminatorValue=("B")
public class ClassB extends ClassA<Integer>{

  [...]

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM