2010-08-08 5 views
5

Ich habe einige Domain Model Klassen in meiner Web App, die eine hierarchische Beziehung zu sich selbst haben. Ein Beispiel hierfür ist die hierarchische Kategoriestruktur, die zur Klassifizierung von Benutzerbuchungen verwendet wird.EclipseLink @MappedSuperclass und Generics

Es gibt einige Logik in Bezug auf die hierarchische Natur dieser Klassen, die häufig ist. Also habe ich versucht, die Logik in eine generische @MappedSuperclass Annotated Superklasse zu verschieben.

Etwas wie:

@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) { ... 
} 

Die Unterklassen erstrecken sich dann HierarchicalBaseEntity sich als gattungs N geben:

@Entity 
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> { 

In Java funktioniert das alles ganz sauber aus. Aber leider ist Eclipse scheint nicht die generische ‚Eltern‘ Feld zu mögen:

private N parent; 

Es gibt folgende Ausnahme:

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) 

Warum ist es beschweren sich über eine Nicht-Einheit String?

Als Test habe ich versucht, die Generika zu entfernen und mit nur dem übergeordneten Feld wie folgt definiert:

private HierarchicalBaseEntity parent; 

Ohne Generika, Eclipse diese Ausnahme gab:

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) 

Wahren HierarchicalBaseEntity seine keine Entität ist in jedem Fall eine @MappedSuperclass .. aber gibt es eine Möglichkeit, dies mit Generika oder anderweitig zu tun? Es scheint, dass Sie kein Feld in Ihrer @MappedSuperclass haben können, das auf eine seiner Unterklassen verweist.

+0

Das sieht irgendwie ähnlich * zu http://forums.sun.com/thread.jspa?threadID=5268944 (aber das damit verbundene Problem ist behoben). Könnten Sie es mit einem anderen Anbieter versuchen? –

Antwort

3

Das Problem ist, dass EclipseLink bei der Verwendung von Generics als Feldtypen für Beziehungen bis zur Laufzeit nicht wissen kann, was der Zieltyp ist, wenn die tatsächliche Instanz überprüft wird. Daher müsste das Mapping zur Laufzeit dynamisch erstellt werden und dies wird nicht unterstützt.

Sie könnten auch weiterhin das Generic Oberklasse verwenden, aber dies würde erfordern, um das Feld zu den Entitäten zu bewegen, wo sie Typen dann abstrakt internen Getter/Setter für diese Felder haben definiert haben würden, das Objekt zurückgeben, dass die generischen Methoden Gießen, um den Anruf würden generischer Typ. Convoluted, aber es würde für die Generic MappedSuperclass ermöglichen.

+0

Hallo Gordon, Danke für Ihre Antwort. Ich werde versuchen, die Felder in die Unterklassen zu schreiben. Ich kann sehen, wie es funktionieren würde. Ich habe derzeit eine HierarchicalEntity-Schnittstelle und eine statische "Helfer" -Klasse mit der Logik in. Works, aber es ist nicht so sauber wie ich es möchte. Ich frage mich, ob @AssociationOverride verwendet werden könnte, um die Zuordnung in irgendeiner Weise neu zu definieren .. –

+0

Leider ist in diesem Fall das Problem mit dem Attributtyp. @AssociationOverrides werden verwendet, um die Datenbankinformationen zu ändern, haben jedoch keine Attribute zum Angeben des Zieltyps. –

+0

Hi Wieder Gordon, ich kann keine sauberere Lösung finden als das, was Sie vorgeschlagen haben, um eine Superklasse für die allgemeine Logik mit abstrakten Gettern zu implementieren. Sie bekommen also meine Stimme. Übrigens. Wissen Sie, ob dies in anderen JPA-Implementierungen möglich ist oder ob es Teil der JPA-Spezifikation ist? –

-1

Der andere Anbieter, die generische Art in einer dauerhaften Beziehung unterstützt OpenJPA ist . Die Annahme, die OpenJPA vornimmt, besteht darin, dass das generische Typfeld ein persistenter Typ ist und als solches mit einer (OpenJPA-spezifischen) @Type-Annotation versehen wird.

Diese @Type-Annotation fungiert als Platzhalter für die OpenJPA Mapping-Engine und enthält eine Zuordnung, bei der es sich bei der Referenz um eine persistente Identität der Laufzeitinstanz handelt. Vor vielen Jahren schrieb ich ein blog; Ich zitiere es hier nicht zur Eigenwerbung, sondern hoffe, dass es einige Wege für Sie gibt, einen generischen Baum zu unterstützen, ohne die konkreten Typinformationen in einer Typhierarchie herunterzudrücken (und dadurch die Essenz des generisch basierten Typmodells zu verlieren)).