EclipseLink @MappedSuperclass 和泛型
我的 Web 应用程序中有一些域模型类,它们之间具有层次结构关系。其中一个示例是用于对用户发帖进行分类的分层类别结构。
有一些与这些类的层次性质相关的常见逻辑。因此,我尝试将逻辑移至通用的 @MappedSuperclass 带注释的超类中。
类似于:
@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) { ...
}
然后,子类扩展 HierarchicalBaseEntity,将自己作为泛型类型 N:
@Entity
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> {
在 Java 中,这一切都非常干净。但不幸的是 EclipseLink 似乎不喜欢通用的“父”字段:
private N parent;
它给出了以下异常:
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)
为什么它抱怨非实体字符串?
作为测试,我尝试删除泛型并仅将父字段定义为:
private HierarchicalBaseEntity parent;
没有泛型,EclipseLink 给出了此异常:
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)
True HierarchicalBaseEntity 在任何情况下都不是实体,是 @MappedSuperclass ..但是有没有办法做到这与泛型还是其他?看来您的 @MappedSuperclass 中不能有一个引用其子类之一的字段。
I have a few domain model classes in my web app that have a hierarchical relationship to themselves. An example of one is the hierarchical category structure used to classify users postings.
There is some logic relating to the hierarchical nature of these classes that is common. So I tried to move the logic into a generic @MappedSuperclass annotated superclass.
Something like :
@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) { ...
}
The subclasses then extend HierarchicalBaseEntity giving themselves as the generic type N:
@Entity
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> {
In Java this all works out quite cleanly. But unfortunately EclipseLink doesn't seems to like the generic 'parent' field:
private N parent;
It gives the following exception:
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)
Why is it complain about a non-entity String?
As a test I've tried removing the generics and just having the parent field defined as:
private HierarchicalBaseEntity parent;
Without generics, EclipseLink gave this exception:
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)
True HierarchicalBaseEntity its not an Entity in either case, is a @MappedSuperclass.. but is there a way to do this with generics or otherwise? It seems you can't have a field in your @MappedSuperclass that references one of it's subclass.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
支持持久关系中的泛型类型的另一个提供程序是 OpenJPA。 OpenJPA 所做的假设是通用类型字段是持久类型,并使用(OpenJPA 特定的)@Type 注释进行注释。
此 @Type 注释充当 OpenJPA 映射引擎的占位符,并保存一个映射,其中引用是运行时实例的持久标识。许多年前,我写了一篇博客;我在这里再次引用它不是为了自我推销,而是希望它可以为您指明一些支持泛型树的途径,而不必将具体类型信息下推到类型层次结构中(从而失去基于泛型的类型模型的本质) )。
The other provider that supports generic type in a persistent relation is OpenJPA. The assumption OpenJPA makes is that the generic type field is a persistent type and be annotated as such with an (OpenJPA-specific) @Type annotation.
This @Type annotation acts as a placeholder for OpenJPA Mapping engine, and holds a mapping where reference is a persistent identity of the runtime instance. Many years ago, I wrote a blog; I cite it here again not for self-promotion, but hoping it might indicate some pathways for you to support a generic tree without having to push down the concrete type information down a type hierarchy (and thereby losing the essence of generic-based type model).
问题是,当使用泛型作为关系的字段类型时,EclipseLink 直到运行时检查实际实例时才能知道目标类型是什么。因此映射必须在运行时动态创建,而这是不受支持的。
您可以继续使用通用超类,但这需要将字段移动到实体,在实体中定义类型,然后为返回对象的字段提供抽象的内部 getter/setter,泛型方法将调用强制转换为泛型类型。很复杂,但它允许使用通用映射超类。
The issue is that when using Generics as field types for relationships EclipseLink can not know what the target type is until runtime when the actual instance is inspected. So the mapping would have to be dynamically created at runtime and this is not supported.
You could continue to use the Generic SuperClass but this would require moving the field to the Entities where they would have types defined then have abstract internal getters/setters for those fields that return Object that the generic methods would call casting to the generic type. Convoluted but it would allow for the Generic MappedSuperclass.
我想我迟到了,但是寻找这个问题答案的人(像我一样)应该看看这个:
https://bugs.eclipse.org/bugs/show_bug.cgi?id= 312132
I think I'm late, but people looking for the answer to this problem (like me) should take a look at this:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=312132