gpt4 book ai didi

java - JPA 与 Java 泛型

转载 作者:行者123 更新时间:2023-11-29 09:49:34 25 4
gpt4 key购买 nike

我有几个具有基本 Long ID 和其他属性的实体。这些实体与另一个实体具有一对多关系,该实体为第一个实体保存不同的自定义(用户输入)翻译。基本上存在实体对,其中一个包含所有非翻译内容,另一个包含文本属性的多个翻译。

为了减少代码和注释的重复,我想为其中一对中的每个实体创建一个抽象类。对于多个翻译,我创建了一个这样的类:

@MappedSuperclass
public abstract class CustomTranslations
{
@Id
protected Long id;
@Id
protected String locale;
}

对于主要实体,我有这个:

@MappedSuperclass
public abstract class CustomTranslationsHolder<T extends CustomTranslations>
{
@OneToMany(fetch=FetchType.EAGER)
@JoinColumn(name="ID")
@MapKey(name="locale")
protected Map<String, T> translationsByLocale;
}

假设其中一个实体对用于 Foo。我会有这个:

@Entity
@Table(name="FOO_TRANSLATIONS")
public class FooTranslations extends CustomTranslations
{
private String title;
private String description;
....
}

还有这个:

@Entity
public class Foo extends CustomTranslationsHolder<FooTranslations>
{
@Id
private Long id;
private String whatever;
private Integer blah;
...
public String getTitle(String locale)
{
return translationsByLocale.get(locale).getTitle();
}
}

这一切都编译得很好,但是在服务器启动时我收到以下错误:

Exception Description: Neither the instance method or field named [locale] exists for the item class [class java.lang.Void], and therefore cannot be used to create a key for the Map.
at org.eclipse.persistence.exceptions.ValidationException.mapKeyNotDeclaredInItemClass(ValidationException.java:1332)
at org.eclipse.persistence.internal.queries.MapContainerPolicy.initializeKey(MapContainerPolicy.java:517)
at org.eclipse.persistence.internal.queries.MapContainerPolicy.getKeyType(MapContainerPolicy.java:438)
at org.eclipse.persistence.internal.jpa.metamodel.MapAttributeImpl.<init>(MapAttributeImpl.java:167)
at org.eclipse.persistence.internal.jpa.metamodel.ManagedTypeImpl.initialize(ManagedTypeImpl.java:1158)
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.initialize(MetamodelImpl.java:459)
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.<init>(MetamodelImpl.java:111)
at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.<init>(MetamodelImpl.java:130)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.getMetamodel(EntityManagerSetupImpl.java:2566)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate.getMetamodel(EntityManagerFactoryDelegate.java:592)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getMetamodel(EntityManagerFactoryImpl.java:506)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:376)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:517)
at $Proxy8.getMetamodel(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:176)
at $Proxy12.getMetamodel(Unknown Source)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:60)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:149)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:87)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:70)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:137)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:125)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:41)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 44 more

因此,听起来它可以在 T 上为 map 找到属性 locale。它似乎应该知道 T 是一个 CustomTranslations,因此知道 CustomTranslations 上有一个 locale 字段.

这只是 EclipseLink 的问题吗?还是我无法像这样做到?我很想知道 Hibernate 如何处理这个完全相同的代码。任何关于此的信息或建议将不胜感激。

最佳答案

接受的答案是错误的。泛型在 JPA 或 EclipseLink 中似乎没有得到很好的支持(可能是因为它们使用字节码编织而不是反射)。无论类型删除如何,使用反射在运行时肯定可以获得信息。

T 的实际运行时类型被删除,但 T 扩展 CustomTranslations 的事实没有。这是在编译时指定的,并存储在可从 Class 实例访问的类元数据中。

您可以调用 CustomTranslationsHolder.class.getTypeParameters(),它将返回一个数组,其中包含一个名为“T”的 TypeVariable 元素,您可以在该元素上调用 getBounds() 将返回 “CustomTranslations”。因此可以证明映射中的值包含 locale 属性。

我会向其他 JPA 提供商提交错误和/或测试。

关于java - JPA 与 Java 泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11812064/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com