Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Can't make @MappedSuperclass work with EclipseLink / Spring Data JPA
Can't make @MappedSuperclass work with EclipseLink / Spring Data JPA [message #986118] Sun, 18 November 2012 21:30 Go to next message
Emmanuel Cron is currently offline Emmanuel Cron
Messages: 1
Registered: November 2012
Location: San Francisco
Junior Member
Hey guys,

So I've been working two days to make something work without success. My goal is fairly simple: make a JPA repository using Spring Data JPA and EclipseLink that is able to query a superclass element (named 'HelpElement') that is implemented by two actual database objects ('HelpTopic' and 'HelpPage').

So I have been reading the web. A lot. And I can't make it work. Important note: everything is working fine using only EclipseLink. As soon as I add Spring Data JPA, i get the following exception that I now dream of during my nightmares.

Caused by: java.lang.IllegalArgumentException: No [EntityType] was found for the key class [com.dalarian.db.entity.help.HelpElement] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class>com.dalarian.db.entity.help.HelpElement</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.


So here are all the files I use that should be required to see where I have done things wrong.

META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="h t t p://java.sun.com/xml/ns/persistence" version="1.0">
  <persistence-unit name="default">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>com.dalarian.db.help.HelpTopic</class>
    <class>com.dalarian.db.help.HelpPage</class>
    <class>com.dalarian.db.help.HelpElement</class>
    <properties>
      <property name="eclipselink.logging.level" value="INFO"></property>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://${database.server}:${database.port}/${database.db_name}"></property>
      <property name="javax.persistence.jdbc.password" value="${database.password}"></property>
      <property name="javax.persistence.jdbc.user" value="${database.user}"></property>
    </properties>
  </persistence-unit>
</persistence>


com.dalarian.ApplicationContext
package com.dalarian;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;

import javax.persistence.EntityManagerFactory;

/**
 * Core application global configuration.
 *
 */
@Configuration
@ComponentScan(basePackages = {"com.dalarian.db"})
@EnableJpaRepositories
public class ApplicationContext {
  @Bean
  public JpaVendorAdapter vendorAdapter() {
    EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
    vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.MySQLPlatform");
    vendorAdapter.setShowSql(true);
    return vendorAdapter;
  }

//  @Bean
//  public DataSource dataSource() {
//    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
//    return builder.setType(EmbeddedDatabaseType.HSQL).build();
//  }

  @Bean
  public EntityManagerFactory entityManagerFactory() {
    EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
//    vendorAdapter.setGenerateDdl(true);
    vendorAdapter.setShowSql(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
//    factory.setPackagesToScan("com.acme.domain");
//    factory.setDataSource(dataSource());
    factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
    factory.afterPropertiesSet();

    return factory.getObject();
  }

  @Bean
  public PersistenceExceptionTranslator persistenceExceptionTranslator() {
    return new EclipseLinkJpaDialect();
  }
}


Database entities

com.dalarian.db.entity.help.HelpElement
package com.dalarian.db.entity.help;

import java.util.Set;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.TableGenerator;

@MappedSuperclass
public abstract class HelpElement implements Comparable<HelpElement> {
  @Id
  @GeneratedValue(generator="HelpElement")
  @TableGenerator(name="HelpElement", table="sequence",
    pkColumnName="Name", pkColumnValue="HelpElement",
    valueColumnName="Value", allocationSize=1)
  private long id;

  @Column(name="ParentID")
  private long parentId;

  @Column(name="Position")
  private int position;

  private transient Set<HelpElement> children;

  @Column(name="Title")
  private String title;

  public boolean isRoot() {
    return parentId < 1;
  }

  @Override
  public int compareTo(HelpElement o) {
    if (this.getParentId() != o.getParentId()) {
      throw new UnsupportedOperationException("Cannot compare two help elements belonging to two different parents");
    }

    int c = new Integer(this.getPosition()).compareTo(new Integer(o.getPosition()));
    if (c != 0) {
      return c;
    } else {
      return this.getTitle().compareTo(o.getTitle());
    }
  }

  // Getters and setters
  // ...
}


com.dalarian.db.entity.help.HelpTopic
package com.dalarian.db.entity.help;

import javax.persistence.AttributeOverride;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name="help_topic")
@AttributeOverride(name="id", column=@Column(name="HelpTopicID"))
public class HelpTopic extends HelpElement {
	
}


com.dalarian.db.entity.help.HelpPage
package com.dalarian.db.entity.help;

import javax.persistence.AttributeOverride;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name="help_page")
@AttributeOverride(name="id", column=@Column(name="HelpPageID"))
public class HelpPage extends HelpElement {
	@Column(name="Content")
	private String contents;

	public String getContents() {
		return contents;
	}

	public void setContents(String contents) {
		this.contents = contents;
	}
}


Repositories

com.dalarian.db.repository.HelpRepository
package com.dalarian.db.repository;

import com.dalarian.db.entity.help.HelpElement;

import org.springframework.data.repository.CrudRepository;

public interface HelpRepository extends CrudRepository<HelpElement, Long>, HelpRepositoryCustom {

}


com.dalarian.db.repository.HelpRepositoryCustom
package com.dalarian.db.repository;

import com.dalarian.db.entity.help.HelpElement;

import java.util.Set;

public interface HelpRepositoryCustom {
  public Set<HelpElement> findRootElements();
}


com.dalarian.db.repository.HelpRepositoryImpl
import com.dalarian.db.entity.help.HelpElement;

import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Set;
import java.util.TreeSet;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Repository
public class HelpRepositoryImpl implements HelpRepositoryCustom {

  @PersistenceContext
  private EntityManager entityManager;

  private SimpleJpaRepository<HelpElement, Long> helpRepository;

  @Override
  public Set<HelpElement> findRootElements() {
    Set<HelpElement> elements = new TreeSet<HelpElement>();
    for (HelpElement element : helpRepository.findAll()) {
      if (element.getParentId() == 0) {
        elements.add(element);
      }
    }
    return elements;
  }

  @PostConstruct
  public void init() {
    helpRepository = new SimpleJpaRepository<HelpElement, Long>(HelpElement.class, entityManager);
  }

}


Test class

Finally, this is the code I use to test my code using JUnit:
package com.dalarian.test.audit;

import com.dalarian.ApplicationContext;
import com.dalarian.db.entity.help.HelpElement;
import com.dalarian.db.repository.HelpRepository;

import org.apache.log4j.Logger;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public final class HelpAudit {
	private static final Logger LOG = Logger.getLogger(HelpAudit.class);

	private HelpAudit() {}

	public static void main(String[] args) {
	  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationContext.class);
	  HelpRepository helpRepository = applicationContext.getBean(HelpRepository.class);
//	  HelpManager helpManager = applicationContext.getBean(HelpManager.class);
		for (HelpElement element : helpRepository.findRootElements()) {
			recursiveDisplay(element, "");
		}
	}

	private static void recursiveDisplay(HelpElement element, String prefix) {
		LOG.debug(prefix + element.getPosition() + ". " + element.getTitle());
		if (element.getChildren() != null) {
			for (HelpElement child : element.getChildren()) {
				recursiveDisplay(child, prefix + "\t");
			}
		}
	}
}


Resulting exception Sad

[EL Info]: 2012-11-18 18:23:09.215--ServerSession(51898531)--Thread(Thread[main,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.4.0.v20120608-r11652
[EL Fine]: connection: 2012-11-18 18:23:09.441--Thread(Thread[main,5,main])--Detected database platform: org.eclipse.persistence.platform.database.MySQLPlatform
[EL Config]: connection: 2012-11-18 18:23:09.455--ServerSession(51898531)--Connection(1856697764)--Thread(Thread[main,5,main])--connecting(DatabaseLogin(
  platform=>MySQLPlatform
  user name=> "***"
  datasource URL=> "jdbc:mysql://localhost:3306/***"
))
[EL Config]: connection: 2012-11-18 18:23:09.466--ServerSession(51898531)--Connection(1575554065)--Thread(Thread[main,5,main])--Connected: jdbc:mysql://localhost:3306/***
  User: ***@***
  Database: MySQL  Version: 5.1.42-community
  Driver: MySQL-AB JDBC Driver  Version: mysql-connector-java-5.1.12 ( Revision: ${bzr.revision-id} )
[EL Info]: connection: 2012-11-18 18:23:09.555--ServerSession(51898531)--Thread(Thread[main,5,main])--file:/***/target/classes/_default login successful
Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: No [EntityType] was found for the key class [com.dalarian.db.entity.help.HelpElement] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class>com.dalarian.db.entity.help.HelpElement</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.; nested exception is java.lang.IllegalArgumentException: No [EntityType] was found for the key class [com.dalarian.db.entity.help.HelpElement] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class>com.dalarian.db.entity.help.HelpElement</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
  at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:301)
  at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:120)
  at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
  at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
  at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
  at $Proxy16.findRootElements(Unknown Source)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:601)
  at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
  at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:309)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:91)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
  at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
  at $Proxy19.findRootElements(Unknown Source)
  at com.dalarian.test.audit.HelpAudit.main(HelpAudit.java:22)
Caused by: java.lang.IllegalArgumentException: No [EntityType] was found for the key class [com.dalarian.db.entity.help.HelpElement] in the Metamodel - please verify that the [Entity] class was referenced in persistence.xml using a specific <class>com.dalarian.db.entity.help.HelpElement</class> property or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element.
  at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entityEmbeddableManagedTypeNotFound(MetamodelImpl.java:174)
  at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.entity(MetamodelImpl.java:194)
  at org.eclipse.persistence.internal.jpa.querydef.AbstractQueryImpl.from(AbstractQueryImpl.java:97)
  at org.springframework.data.jpa.repository.support.SimpleJpaRepository.applySpecificationToCriteria(SimpleJpaRepository.java:474)
  at org.springframework.data.jpa.repository.support.SimpleJpaRepository.getQuery(SimpleJpaRepository.java:437)
  at org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:239)
  at com.dalarian.db.repository.HelpRepositoryImpl.findRootElements(HelpRepositoryImpl.java:33)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:601)
  at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:319)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
  at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
  ... 21 more


Sorry for the long post, but if anybody has an idea on how to fix that, I'd be glad!
Re: Can't make @MappedSuperclass work with EclipseLink / Spring Data JPA [message #986485 is a reply to message #986118] Tue, 20 November 2012 10:49 Go to previous message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Not sure if this is an issue with the SimpleJpaRepository or with how you have configured things in Spring.

SimpleJpaRepository seems to be using some sort of Criteria query, can you try using a simple JPQL query, or your own Criteria query directly on the EntityManager obtained from Spring?

It may also be some sort of initialization, or class loader issue. Spring does stuff with class loaders, so you may have two different versions of the class on the classpath somehow.
Maybe start with a simple Spring example, and go from there.



James : Wiki : Book : Blog : Twitter
Previous Topic:Persistence unit with entities in multiple jars and static weaving
Next Topic:Replication/union partitioning and elasticity
Goto Forum:
  


Current Time: Fri Aug 22 21:51:27 EDT 2014

Powered by FUDForum. Page generated in 0.01752 seconds