我有几个具有基本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


因此,听起来好像可以在地图的locale上找到属性T。似乎应该知道TCustomTranslations,因此知道locale上有一个CustomTranslations字段。

这仅仅是EclipseLink的问题吗?还是没有办法我可以做到这一点?我想知道Hibernate如何处理这个完全相同的代码。任何信息或建议对此将不胜感激。

最佳答案

似乎应该知道T是CustomTranslations


由于类型擦除,它不知道这一点。

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Java generics - type erasure - when and what happens

07-24 19:48