2012-06-29 3 views
7

Мне интересно, как абстрактный класс с дженериками будет обрабатывать JPA? Я имею в виду, какие аннотации мне нужны для этой области?JPA и generics

Рассмотрим эти:

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

А потом эти

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

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

Какую реализацию вы используете? – JMelnik

+0

Hibernate 3.6 с базой данных Oracle 10g. Кроме того, я вручную создаю таблицы вручную. – jaakko

+0

Что вы пытаетесь достичь на уровне дизайна? Какой смысл иметь такой суперкласс? –

ответ

5

JPA вполне в состоянии справиться с вашей предложил, потому что общие появляется на уровне абстрактного класса и для ваших конкретных классов имеет точно одно значение для каждого класса. Фактически, JPA будет хранить ваши подклассы в одной или нескольких таблицах в соответствии с выбранной вами структурой @InheritanceStrategy и использует для этого другой механизм.

Вы можете выяснить сами, почему ваш случай не является проблемой, рассуждая о том, как ОРМ может сохранить два класса на БД:

  • Вы можете хранить MyStringClass и MyIntegerClass в той же таблице, добавив Столбец дискриминатора, чтобы ORM, когда он загружается из БД, знает, какой конструктор должен быть вызван.
  • Вы можете сохранить каждый подкласс в другой таблице.

Что не представляется возможным, с другой стороны, чтобы определить общий

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

Причина этого заключается в том, что во время компиляции, то Т «стирается» из-за типа стирания. Он используется во время компиляции для проверки подписей и правильности типов, но затем он превращается в java.lang.Object внутри JVM. Если вы следуете до сих пор, вы должны быть в состоянии понять следующее:

  • В вашем случае, каждый конкретный подкласс AbstractMyClass имеет тип T, который определен для всех экземпляров класса. Хотя информация T не сохраняется в AbstractMyClass, она сохраняется и уникальна внутри подклассов.
  • Во втором случае, который я опубликовал, каждый возможный конкретный экземпляр MyGenericClass может иметь различное значение для T, и из-за стирания типа эта информация не сохраняется.

* Примечание: факт, что второй случай не может быть обработан JPA, абсолютно разумен, и если вы попадете в этот случай, вы должны задать себе вопросы о своем дизайне. Generics - отличный инструмент для разработки гибких классов, которые могут обрабатывать другие классы безопасным типом, но безопасный тип - это концепция языка программирования, которая не имеет ничего общего с устойчивостью.

Дополнительно: вы можете использовать javap, чтобы увидеть, что на самом деле является стиранием. Удалите аннотации из MyGenericClass и скомпилируйте их.

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

Я попробовал это, и это произвело исключение @Entity @Table (имя = "MYFOO") общественного класса MyFooClass расширяет AbstractMyClass { } Вызванный: org.hibernate.MappingException: Не удалось определить тип для: fukoka.foobar.Foo, за таблицей: MyFoo, для столбцов: [org.hibernate.mapping.Column (field)] – user1885834

-2

Мы можем. если используются TSerializable

@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

больше кода объясняет ... – Raymond

+0

Пожалуйста, объясните, почему 'T' необходимо реализовать' Seralizable', так как им нужно для расширения типа объекта. –