JPA and generics

I'm wondering how an abstract class with generics would handle with JPA? I mean what kind of annotations do I need for the field?

Consider these:

@MappedSuperclass
public abstract class AbstractMyClass<T> {
  // What about Strings and Integers? Do I need some kind of @LOB?
  private T field;

  public T getField() {
    return field;
  }

  public void setField(T field) {
    this.field = field;
  }
}

And then these

@Entity
@Table(name = "String")
public class MyStringClass extends AbstractMyClass<String> {
}

@Entity
@Table(name = "Integer")
public class MyIntegerClass extends AbstractMyClass<Integer> {
}

JPA is perfectly able to handle your proposed, because the generic appears at the abstract class level and for your concrete classes it has exactly a single value per class. In fact, JPA will store your subclasses in one or more table, according to the @InheritanceStrategy you have chosen and uses different mechanism for that.

You can figure out yourself why your case is not a problem, reasoning about how an ORM could save the two classes on a DB:

  • You can store MyStringClass and MyIntegerClass in the same table, adding a Discriminator column so that the ORM, when it loads from the DB, know which constructor should be called.
  • You can store every subclass in more table.
  • What is not possible, on the other side, is to define a generic

    @Entity
    @Table(name = "MyGenericClass")
    public class MyGenericClass<T> {
        private T t;
        public MyGenericClass(T t) {
           this.t=t;
        }
    }
    

    The reason for this is that, at compile time, the T is "erased" because of type erasure. It is used at compile time to verify signatures and correctness of types, but then it is turned into a java.lang.Object inside the JVM. If you follow until now, you should be able to understand the following:

  • In your case, every concrete subclass of AbstractMyClass has a type T which is defined for all instances of the class. While the T information is not retained into the AbstractMyClass, it is retained and unique inside the subclasses.
  • In the second case I posted, each possible concrete instance of MyGenericClass could have a possible different value for T, and because of type erasure this information is not retained.
  • *Note: the fact that the second case cannot be handled by JPA is absolutely reasonable and if you fall in that case you should ask yourself questions about your design. Generics are a great tool to design flexible classes which can handle other classes in a type-safe manner, but type-safe is a programming language concept which has nothing to do with persistance.


    Extra : you could use javap to see what really is erasure. Take off annotations from MyGenericClass and compile it.

    G:>javac MyGenericClass.java
    
    G:>javap -p MyGenericClass
    Compiled from "MyGenericClass.java"
    public class MyGenericClass extends java.lang.Object{
        private java.lang.Object t;
        public MyGenericClass(java.lang.Object);
    }
    

    We can. if the T implements Serializable

    @Entity
    public class IgsSubject extends BasicObject implements Serializable{
    
        private static final long serialVersionUID = -5387429446192609471L;
    
    @MappedSuperclass
    public class IgsBasicLog<T> extends BasicObject {
    
        @ManyToOne
        @JoinColumn(name = "ITEM_ID")
        private T item;
    
    @Entity
    public class IgsLogA extends IgsBasicLog<IgsSubject> implements Serializable {
        private static final long serialVersionUID = -8207430344929724212L;
    }
    
    链接地址: http://www.djcxy.com/p/10928.html

    上一篇: 使用Mono在Windows中构建Mac .app文件

    下一篇: JPA和泛型