2012-06-29 11 views
7

Mi chiedo come gestire una classe astratta con generici con JPA? Voglio dire che tipo di annotazioni ho bisogno per il campo?JPA e generici

considerare questi:

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

E poi questi

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

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

Cosa realizzazione si usa? – JMelnik

+0

Hibernate 3.6 con Oracle 10g come database. Inoltre, genero manualmente le tabelle manualmente. – jaakko

+0

Cosa stai cercando di ottenere a livello di design? Qual è il punto di avere una tale superclasse? –

risposta

5

APP è perfettamente in grado di gestire il vostro proposto, perché le appare generici a livello di classe astratta e per le vostre classi concrete ha esattamente un singolo valore per classe. In effetti, JPA memorizzerà le sottoclassi in una o più tabelle, in base alla @InheritanceStrategy che hai scelto e utilizza un meccanismo diverso per quello.

Si può capire voi stessi perché il vostro caso non è un problema, ragionando su come un ORM potrebbe salvare le due classi su un DB:

  • È possibile memorizzare MyStringClass e MyIntegerClass nella stessa tabella, l'aggiunta di un Colonna Discriminator in modo che l'ORM, quando carica dal DB, sappia quale costruttore deve essere chiamato.
  • È possibile memorizzare ogni sottoclasse in più tabelle.

Ciò che non è possibile, dall'altro lato, è quello di definire un generico

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

La ragione di questo è che, al momento della compilazione, il T viene "svuotata" perché di tipo cancellazione. Viene utilizzato in fase di compilazione per verificare le firme e la correttezza dei tipi, ma in seguito viene trasformato in java.lang.Object all'interno della JVM. Se si segue fino ad ora, si dovrebbe essere in grado di comprendere la seguente:

  • Nel tuo caso, ogni sottoclasse concreta di AbstractMyClass ha un tipo T che è definita per tutte le istanze della classe. Mentre l'informazione T non viene mantenuta in AbstractMyClass, viene mantenuta e unica all'interno delle sottoclassi.
  • Nel secondo caso che ho postato, ogni possibile istanza concreta di MyGenericClass potrebbe avere un possibile valore diverso per T, e a causa della cancellazione del tipo questa informazione non viene mantenuta.

* Nota: il fatto che il secondo caso non può essere gestito da APP è assolutamente ragionevole e se si cade in questo caso si dovrebbe porsi domande sul vostro disegno. I generici sono un ottimo strumento per progettare classi flessibili in grado di gestire altre classi in un modo sicuro dal punto di vista del tipo, ma type-safe è un concetto di linguaggio di programmazione che non ha nulla a che fare con la persistenza.


Extra: si potrebbe usare javap per vedere che cosa è veramente la cancellazione. Rimuovere le annotazioni da MyGenericClass e compilarle.

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

Ho provato questo e ha prodotto un'eccezione @Entity @Table (name = "MyFoo") public class MyFooClass estende AbstractMyClass {} Causato da: org.hibernate.MappingException: Impossibile determinare il tipo di: fukoka.foobar.Foo, alla tabella: MyFoo, per le colonne: [org.hibernate.mapping.Column (campo)] – user1885834

-2

Possiamo. se i 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

altro codice spiega ... – Raymond

+0

Spiega perché 'T' ha bisogno di implementare' Serializable' poiché imo necessita per estendere un tipo di entità. –