1

私は基本的にはいくつかのエンティティ持っLongIDおよびその他のプロパティを。これらのエンティティは最初のエンティティのための別のカスタム(ユーザが入力した)の翻訳を保持している別のエンティティと1対多の関係を持っています。1は、すべての非翻訳のものを保持し、テキストプロパティのための他の保持複数の翻訳を持つエンティティペアが基本的にあります。

コードとアノテーションの重複を減らすために、これらのペアの1つにあるエンティティごとに抽象クラスを作成したいと思います。複数の翻訳のために私は、このようなクラスを作成しました:

@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;
}

したがって、エンティティペアの1つが。用であるとし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を見つけることができるようです。それがaでTあることを知っている必要があるようであり、したがって、にフィールドがあることを知っている必要があります。TCustomTranslationslocaleCustomTranslations

これはEclipseLinkの問題ですか?それとも、私がこのようにそれを行うことができる方法はありませんか?Hibernateがこれとまったく同じコードをどのように処理するかを知りたいと思います。これに関する情報や提案をいただければ幸いです。

4

3 に答える 3

8

受け入れられた答えは間違っています。ジェネリックスは、JPAやEclipseLinkでは十分にサポートされていないようです(おそらく、リフレクションの代わりにバイトコードウィービングを使用しているためです)。情報は、型消去に関係なく、リフレクションを使用して実行時に確実に利用できます。

の実際の実行時タイプTは消去されますが、T拡張されるという事実は消去されCustomTranslationsません。これはコンパイル時に指定され、Classインスタンスからアクセス可能なクラスメタデータに格納されます。

を呼び出すと、「T」という名前の要素がCustomTranslationsHolder.class.getTypeParameters()1つある配列が返され、それを呼び出すと、が返されます。したがって、マップ内の値にプロパティが含まれていることを証明できます。TypeVariablegetBounds()"CustomTranslations"locale

バグを報告したり、他のJPAプロバイダーにテストしたりします。

于 2012-08-11T22:36:54.547 に答える
3

TがCustomTranslations

型消去のため、これはわかりません。

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

Javaジェネリック-型消去-いつ、何が起こるか

于 2012-08-04T21:20:04.587 に答える
0

JPA仕様によると:

マップされたスーパークラスによって定義される永続的な関係は、単方向である必要があります。

これが、 CustomTranslationsHolderを別のマップされたスーパークラスとManyToOneの関係があるため、マップされたスーパークラスとして定義できない理由です。このクラスはエンティティである可能性があります。

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

ただし、この場合、残念ながらJPAは実行時にTタイプを抽出できません。

デザインを確認することをお勧めします。

于 2016-04-14T07:41:08.140 に答える