Reputation: 4380
Another question for my EclipseLink and Spring (MVC and spring-data) version 3.1.1 set-up:
I'm trying to get JPA working without the use of the persistence.xml file in accordance with this article. In the article it says:
Usually, JPA defines a persistence unit through the META-INF/persistence.xml file. Starting with Spring 3.1, this XML file is no longer necessary – the LocalContainerEntityManagerFactoryBean now supports a ‘packagesToScan’ property where the packages to scan for @Entity classes can be specified.
The persistence.xml file was the last piece of XML to be removed – now, JPA can be fully set up with no XML.
I understand that if one were making use of the persistence.xml file, all Entity classes here should be declared here. However, I'm trying to make use of the packagesToScan
property instead. Below is the full startup log and the error produced after making one request to the servlet which ultimately attempts to create a new user in the database. It doesn't seem to recognise that the User
object is an Entity. Since I have little experience with Spring, I was wondering if anyone, firstly can spot a mistake I'm making, but otherwise, knows the best way to debug this. I want to know what Entity objects have been recognised by the EntityManagerFactory.
My backup option is to switch to using persistence.xml (haven't tried it yet actually) but I'd like to be rid of that if possible (one less XML file to worry about).
UPDATE: I've updated the error log after making the recommended config change to the entityManagerFactory, based on the answer by Sean Patrick Floyd but that did not solve the main issue. What I have also done is tried an alternative way of getting this to work by creating a persistence.xml file (the old and more common way of doing this) and added a small piece of test code within the servlet I access to kick off this functionality. So now I have this bit of code in my servlet:
User user = new User();
user.setFirstName("John");
user.setLastName("Doe");
// user = userService.addUser(user);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("proxiPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(user);
em.getTransaction().commit();
em.close();
emf.close();
And this persistence.xml file:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="proxiPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.proxi.user.User</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
<property name="eclipselink.jdbc.url" value="jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true"/>
<property name="eclipselink.jdbc.user" value="proxi"/>
<property name="eclipselink.jdbc.password" value=""/>
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.HSQLPlatform"/>
<property name="eclipselink.logging.level" value="FINEST"/>
<property name="eclipselink.orm.throw.exceptions" value="true"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
</properties>
</persistence-unit>
</persistence>
This actually works so I'm wondering now whether it's a problem with the way the EntityManagerFactory is initialised or something like that. I've included the code for the UserService class that is supposed to do the database related stuff.
Here is the startup log (including error) in full:
INFO: Reloading Context with name [/proxi] is completed
INFO : com.proxi.controller.HomeController - Welcome home! The client locale is en_GB
[EL Info]: 2012-04-26 15:17:35.066--ServerSession(313687096)--Thread(Thread[http-bio-8980-exec-3,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.2.0.v20110202-r8913
[EL Config]: 2012-04-26 15:17:35.079--ServerSession(313687096)--Connection(1182807222)--Thread(Thread[http-bio-8980-exec-3,5,main])--connecting(DatabaseLogin(
platform=>HSQLPlatform
user name=> ""
connector=>JNDIConnector datasource name=>null
))
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose start
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose end
[EL Config]: 2012-04-26 15:17:36.016--ServerSession(313687096)--Connection(1257700692)--Thread(Thread[http-bio-8980-exec-3,5,main])--Connected: jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true
User: proxi
Database: HSQL Database Engine Version: 2.2.6
Driver: HSQL Database Engine Driver Version: 2.2.6
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - Database closed
[EL Config]: 2012-04-26 15:17:36.365--ServerSession(313687096)--Connection(385835848)--Thread(Thread[http-bio-8980-exec-3,5,main])--connecting(DatabaseLogin(
platform=>HSQLPlatform
user name=> ""
connector=>JNDIConnector datasource name=>null
))
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose start
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose end
[EL Config]: 2012-04-26 15:17:36.877--ServerSession(313687096)--Connection(603544782)--Thread(Thread[http-bio-8980-exec-3,5,main])--Connected: jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true
User: proxi
Database: HSQL Database Engine Version: 2.2.6
Driver: HSQL Database Engine Driver Version: 2.2.6
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - Database closed
[EL Info]: 2012-04-26 15:17:37.328--ServerSession(313687096)--Thread(Thread[http-bio-8980-exec-3,5,main])--file:/C:/Users/nly31175/workspace/spring/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/proxi/WEB-INF/classes/_default login successful
Apr 26, 2012 3:17:37 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/proxi] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Object: com.proxi.user.User@5ca3ce3f is not a known entity type.] with root cause
java.lang.IllegalArgumentException: Object: com.proxi.user.User@5ca3ce3f is not a known entity type.
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4128)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:406)
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.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy23.persist(Unknown Source)
at com.proxi.user.UserService.save(UserService.java:27)
at com.proxi.user.UserService.addUser(UserService.java:39)
at com.proxi.controller.HomeController.home(HomeController.java:51)
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.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
root-context.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="userService" class="com.proxi.user.UserService" >
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- Starting with Spring 3.1, the persistence.xml XML file is no longer
necessary. The LocalContainerEntityManagerFactoryBean now supports a ‘packagesToScan’
property where the packages to scan for @Entity classes can be specified. -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaDialect" ref="jpaDialect" />
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.proxi.user" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.HSQLPlatform" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
</property>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect " />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true" />
<property name="username" value="proxi" />
<property name="password" value="" />
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
User.java class:
/**
*
*/
package com.proxi.user;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Table;
import javax.persistence.Id;
/**
* Represents an application user.
*/
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
// /////// GETTERS AND SETTERS ///////////
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Here is UserService.java
package com.proxi.user;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import org.springframework.transaction.annotation.Transactional;
/**
* Performs user related operations.
*
*/
public class UserService {
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
@Transactional
public User save(User user) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
if (user.getId() == null) {
entityManager.persist(user);
return user;
} else {
return entityManager.merge(user);
}
}
public User findUser(String userid) {
return null;
}
public User addUser(User user) {
return save(user);
}
// /////////////////////// GETTERS AND SETTERS //////////////////////
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
}
Upvotes: 2
Views: 5751
Reputation: 2355
@chrisjleu you are very close. I got it to work by setting eclipse link to use static weaving:
private static final Properties jpaProperties = new Properties();
static {
jpaProperties.put("eclipselink.logging.level", "INFO");
jpaProperties.put("eclipselink.weaving", "static");
}
And add it to the LocalContainerEntityManagerFactoryBean.setJpaProperties(jpaProperties)
To get static weaving to work, I am using AspectJ. My project is in Maven, so I use the following plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<!-- NB: do not use 1.3 or 1.3.x due to MASPECTJ-90 and do not use 1.4
due to declare parents issue -->
<dependencies>
<!-- NB: You must use Maven 2.0.9 or above or these are ignored (see
MNG-2972) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${version.aspectj}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${version.aspectj}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>${version.java}</source>
<target>${version.java}</target>
</configuration>
</plugin>
Upvotes: 0
Reputation: 11481
Is your persistence.xml
file present in the project?
If it is the case remove persistence.xml
completely from the project. This file somehow conflicts with packagesToScan
property, even if you don't explicitly mention it anywhere in the configuration. I myself have come across this peculiarity.
Upvotes: 0
Reputation: 4380
I've really searched on this issue for days now and the best I can come up with is a small note on the limitations of JPA in this tutorial titled: EclipseLink JPA Deployed on Tomcat 6 using Eclipse WTP. The relevant section says:
As Tomcat is not a Java EE 5 compatible server, there are some limitiations to JPA.
- No dynamic weaving (instrumentation) - static weaving of entities is still available via EclipseLink.
- No
@EJB
injection of a session bean (containing theEntityManager
) is available - use the persistence factory and manager directly.- No
@PersistenceContext
injection of a container managed persistence unit is available - usePersistence.createEntityManagerFactory(JTA_PU_NAME)
.
I think the latter two points are applicable to the problem I'm having. As I say I can get it to work no problem with the test code snippet but the moment I try to wire it up properly I get a problem. Therefore, without any other answers, I think this is the one I will have to settle for. Any further insights welcome though as I don't find it a very satisfying answer.
Upvotes: 1
Reputation: 298828
Internal Exception: java.sql.SQLSyntaxErrorException: object name already exists: USER in statement [CREATE TABLE user (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL, first_name VARCHAR(255), last_name VARCHAR(255), PRIMARY KEY (id))]
This seems to be the problem: Spring / EclipseLink is trying to create an already existing table.
try removing this line from your xml context:
<property name="generateDdl" value="true" />
Upvotes: 1