2010-08-08 14 views
5

Mam kilka klas modelu domeny w mojej aplikacji internetowej, które mają hierarchiczną relację do siebie. Przykładem jest hierarchiczna struktura kategorii używana do klasyfikowania postów użytkowników.EclipseLink @MappedSuperclass i generics

Istnieje pewna logika związana z hierarchiczną naturą tych klas, która jest powszechna. Więc próbowałem przenieść logikę do ogólnej nadpisanej adnotacji nadrzędnej klasy @MappedSuperclass.

Coś jak:

@MappedSuperclass 
public abstract class HierarchicalBaseEntity<N extends HierarchicalBaseEntity<N>> extends BaseEntity { 

@ManyToOne(optional=true) 
@JoinColumn(name="parent") 
private N parent; 
private int depth; 

public N getParent() { ... 
public void setParent(N newParent) { ... 

public boolean isRoot() { ... 
public int getDepth() { ... 

public boolean isDescendantOf(N ancestor) { ... 
public static <N extends HierarchicalBaseEntity<N>> N getCommonAncestor(N a, N b) { ... 
public static <N extends HierarchicalBaseEntity<N>> Collection<N> reduceToCommonAncestors(Collection<N> entities) { ... 
} 

podklas następnie rozszerzyć HierarchicalBaseEntity podając się za generycznego typu N:

@Entity 
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> { 

W Javie to wszystko działa dość czysto. Ale niestety EclipseLink nie wydaje się podoba generycznym rodzica murawę:

private N parent; 

Daje następujący wyjątek:

Caused by: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: [class net.timp.yaase.core.model.HierarchicalBaseEntity] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [field parent]. 
at org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1341) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor.getReferenceDescriptor(RelationshipAccessor.java:416) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOneToOneForeignKeyRelationship(ObjectAccessor.java:609) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOwningMappingKeys(ObjectAccessor.java:678) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ManyToOneAccessor.process(ManyToOneAccessor.java:107) 

Dlaczego narzekać String spoza jednostki?

Jako test próbowałem usuwania leków generycznych i tylko o pole rodzic zdefiniowany jako:

private HierarchicalBaseEntity parent; 

Bez leków generycznych, EclipseLink dał ten wyjątek:

Caused by: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: [class net.timp.yaase.core.model.OnymBean] uses a non-entity [class net.timp.yaase.core.model.HierarchicalBaseEntity] as target entity in the relationship attribute [field parent]. 
at org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1341) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor.getReferenceDescriptor(RelationshipAccessor.java:416) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOneToOneForeignKeyRelationship(ObjectAccessor.java:609) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOwningMappingKeys(ObjectAccessor.java:678) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ManyToOneAccessor.process(ManyToOneAccessor.java:107) 

Prawdziwa HierarchicalBaseEntity Jej nie jest Podmiot w obu przypadkach jest klasą @MappedSuper .. ale czy istnieje sposób, aby to zrobić z rodzajami lub w inny sposób? Wygląda na to, że nie możesz mieć pola w klasie @MappedSuperclass, która odwołuje się do jednej z jego podklasy.

+0

Wygląda to jakoś * podobne * do http://forums.sun.com/thread.jspa?threadID=5268944 (ale powiązany problem został rozwiązany). Czy możesz spróbować z innym dostawcą? –

Odpowiedz

3

Problem polega na tym, że podczas korzystania z generics jako typów pól dla relacji EclipseLink nie może wiedzieć, jaki jest typ celu, dopóki nie zostanie wykonane środowisko wykonawcze podczas sprawdzania rzeczywistej instancji. A zatem mapowanie będzie musiało być tworzone dynamicznie w środowisku wykonawczym, a to nie jest obsługiwane.

Możesz nadal używać Generic SuperClass, ale wymagałoby to przeniesienia pola do Entities, gdzie miałyby zdefiniowane typy, a następnie miałyby abstrakcyjne wewnętrzne algorytmy pobierające/ustawiające dla tych pól, które zwracają Obiekt, który metody ogólne wywoływałyby rzutowanie do rodzaj ogólny. Przekonane, ale pozwoliłoby to na Generic MappedSuperclass.

+0

Cześć Gordon, Dziękuję za odpowiedź. Spróbuję twojej sugestii umieszczenia pól w podklasach. Widzę, jak to działa. Obecnie mam interfejs HierarchicalEntity i statyczną klasę helperów z logiką. Działa, ale nie jest tak czysty, jak bym chciał. Zastanawiam się, czy @AssociationOverride może być użyty do ponownego zdefiniowania powiązania w jakiś sposób .. –

+0

Niestety w tym przypadku problem dotyczy typu atrybutu. @AssociationOverrides są używane do zmiany danych bazy danych, ale nie mają atrybutów określających typ celu. –

+0

Cześć Ponownie Gordon, nie mogę znaleźć czystszego rozwiązania, niż to, co zasugerowałeś do implementacji superklasy dla wspólnej logiki z abstrakcyjnymi getterami. Więc dostajesz mój głos. BTW. Czy wiesz, czy jest to możliwe w przypadku innych impe- rementacji JPA lub czy jest to część specyfikacji JPA? –

-1

innego dostawcy, który obsługuje typu rodzajowego w trwałym związku jest OpenJPA . Założeniem OpenJPA jest to, że pole typu ogólnego jest typem trwałym i można je adnotować jako takie za pomocą adnotacji @Type (specyficznej dla OpenJPA).

Ta adnotacja @ Type pełni rolę symbolu zastępczego dla mechanizmu mapowania OpenJPA i przechowuje odwzorowanie, w przypadku którego odwołanie jest stałą tożsamością instancji środowiska wykonawczego. Wiele lat temu napisałem blog; Przytaczam to tutaj nie tylko w celu autopromocji, ale mam nadzieję, że może to wskazywać na pewne ścieżki do poparcia ogólnego drzewa bez konieczności przesyłania informacji o typie konkretnym do hierarchii typów (i tym samym utraty istoty modelu typu bazującego na rodzajach).