2012-06-29 16 views
7

Me pregunto cómo manejaría una clase abstracta con genéricos con JPA? Me refiero a qué tipo de anotaciones necesito para el campo?JPA y genéricos

Considere estos:

@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; 
    } 
} 

Y entonces estos

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

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

¿Qué implementación utiliza? – JMelnik

+0

Hibernate 3.6 con Oracle 10g como base de datos. Además, genero las tablas manualmente a mano. – jaakko

+0

¿Qué estás tratando de lograr en un nivel de diseño? ¿De qué sirve tener una superclase? –

Respuesta

5

APP es perfectamente capaz de manejar su propuesta, ya que el aparece genéricos a nivel de clase abstracta y para sus clases concretas que tiene exactamente un solo valor por clase De hecho, JPA almacenará sus subclases en una o más tablas, de acuerdo con la estrategia @InheritanceStrategy que haya elegido y utilizará un mecanismo diferente para eso.

se puede averiguar por qué su caso no es un problema, el razonamiento acerca de cómo un ORM podría salvar las dos clases en una base de datos:

  • Puede almacenar MyStringClass y MyIntegerClass en la misma tabla, la adición de una Columna Discriminador para que el ORM, cuando se carga desde el DB, sepa a qué constructor se debe llamar.
  • Puede almacenar cada subclase en más tabla.

Lo que no es posible, por otro lado, es definir un genérico

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

La razón de esto es que, en tiempo de compilación, el T está "borrado" por el tipo de borrado. Se usa en tiempo de compilación para verificar las firmas y la corrección de los tipos, pero luego se convierte en un java.lang.Object dentro de la JVM. Si sigue hasta ahora, usted debe ser capaz de entender lo siguiente:

  • En su caso, cada subclase concreta de AbstractMyClass tiene un tipo T que se define para todas las instancias de la clase. Si bien la información T no se retiene en AbstractMyClass, se conserva y es única dentro de las subclases.
  • En el segundo caso que publiqué, cada posible instancia concreta de MyGenericClass podría tener un posible valor diferente para T, y debido a la borradura de tipo, esta información no se conserva.

* Nota: el hecho de que el segundo caso no pueda ser manejado por JPA es absolutamente razonable y, en este caso, debe hacerse preguntas sobre su diseño. Los genéricos son una gran herramienta para diseñar clases flexibles que pueden manejar otras clases de una manera segura para el tipo, pero type-safe es un concepto de lenguaje de programación que no tiene nada que ver con la persistencia.


adicional: se puede utilizar javap para ver lo que realmente está borrado. Quita las anotaciones de MyGenericClass y compila.

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); 
} 
+0

yo probamos este y se produjo una excepción @Entity @Table (name = "myFoo") MyFooClass clase pública se extiende AbstractMyClass {} Causado por: org.hibernate.MappingException: No se pudo determinar el tipo de: fukoka.foobar.Foo, en la tabla: MyFoo, para columnas: [org.hibernate.mapping.Column (field)] – user1885834

-2

Podemos. si el T implementa 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; 
} 
+0

más código explica ... – Raymond

+0

Por favor, explique por qué 'T' necesita implementar' Seralizable' ya que lo necesita para extender un tipo de entidad. –