Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA and generics

Tags:

java

generics

jpa

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> {
}
like image 791
jaakko Avatar asked Jun 29 '12 11:06

jaakko


People also ask

What is JPA and why it is used?

JPA stands for Java Persistence API (Application Programming Interface). It was initially released on 11 May 2006. It is a Java specification that gives some functionality and standard to ORM tools. It is used to examine, control, and persist data between Java objects and relational databases.

Can I use polymorphism in generics?

The polymorphism applies only to the 'base' type (type of the collection class) and NOT to the generics type.

What is the use of JPA in Java?

The Java™ Persistence API (JPA) provides a mechanism for managing persistence and object-relational mapping and functions since the EJB 3.0 specifications. The JPA specification defines the object-relational mapping internally, rather than relying on vendor-specific mapping implementations.

What are generics in Java?

Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.


1 Answers

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);
}
like image 89
Edmondo1984 Avatar answered Oct 03 '22 11:10

Edmondo1984