title: JPA with Java Generics
body: <p>I have several entities with a basic <code>Long</code> ID and other properties. These entities have a one-to-many relationship with another entity that holds different custom (user-entered) translations for the first entities. There's basically entity pairs with one holding all the non-translation stuff and the other holding multiple translations for text properties.</p>
  
  <p>In order to reduce duplication of code and annotations, I want to create an abstract class for each entity in one of these pairs. For the multiple translations I created a class like this:</p>
  
  <pre><code>@MappedSuperclass
  public abstract class CustomTranslations
  {
      @Id
      protected Long id;
      @Id
      protected String locale;
  }
  </code></pre>
  
  <p>For the primary entity I have this:</p>
  
  <pre><code>@MappedSuperclass
  public abstract class CustomTranslationsHolder&lt;T extends CustomTranslations&gt;
  {
      @OneToMany(fetch=FetchType.EAGER)
      @JoinColumn(name="ID")
      @MapKey(name="locale")
      protected Map&lt;String, T&gt; translationsByLocale;
  }
  </code></pre>
  
  <p>So say one of the entity pairs is for <code>Foo</code>. I would have this:</p>
  
  <pre><code>@Entity
  @Table(name="FOO_TRANSLATIONS")
  public class FooTranslations extends CustomTranslations
  {
      private String title;
      private String description;
      ....
  }
  </code></pre>
  
  <p>and this:</p>
  
  <pre><code>@Entity
  public class Foo extends CustomTranslationsHolder&lt;FooTranslations&gt;
  {
      @Id
      private Long id;
      private String whatever;
      private Integer blah;
      ...
      public String getTitle(String locale)
      {
          return translationsByLocale.get(locale).getTitle();
      }
  }
  </code></pre>
  
  <p>This all compiles just fine, but on server startup I get the following error:</p>
  
  <pre><code>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.&lt;init&gt;(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.&lt;init&gt;(MetamodelImpl.java:111)
  at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.&lt;init&gt;(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
  </code></pre>
  
  <p>So, it sounds like it can find the property <code>locale</code> on <code>T</code> for the Map. It seems like it should know that <code>T</code> is a <code>CustomTranslations</code> and therefore know that there is a <code>locale</code> field on <code>CustomTranslations</code>.</p>
  
  <p>Is this just an issue with EclipseLink? Or is there just no way I can do it like this? I'd be interested to know how Hibernate handles this exact same code. Any information or suggestions on this would be greatly appreciated.</p>