I have issues trying to persist an Entity to a PostgreSQL Database using Springs CrudRepository interface. I have had quite some issues setting this up with the correct values both on TomEE and adjusting the configuration of Spring itself. I tried briefly to use hibernate, but issues just got worse, so I switched back to OpenJpa that is bundled with TomEE.
I have a bit of experience with plain JavaEE and am creating this application to learn Spring and a friend of mine needs a Spring application to fool around with deployment on a TomEE based ApplicationServer, thus those two are requirements. I might go a bit overboard with the amount of code I attach, but I rather let you see what is there so you get a good overview.
Components I have developed and a brief description of what I'm doing, expecting and actually seeing. Components:
Flow of my actions:
What I'm expecting:
What I see and what I don't see but would expect to see:
My configuration files have gotten quite a mess after trying all different kinds of troubleshooting found via google, SO and lots of tutorials. After spending now several days trying to figure out what the issue is, I come now here and hope you might be able to point me to my error.
Coworker.java
@Entity
public class Coworker implements Serializable {
@Transient
Logger logger = LoggerFactory.getLogger(this.getClass());
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long coworkerId;
private String firstName;
private String lastName;
@Temporal(TemporalType.DATE)
private Date creationDate;
@Temporal(TemporalType.DATE)
private Date lastUpdatedDate;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "coworker", fetch = FetchType.EAGER)
private Set<Timeframe> timeframes = new HashSet<Timeframe>();
@PrePersist
private void setDateBeforePersisting() {
logger.info("Inside prepersisting a Coworker");
creationDate = new Date();
// Set the last updated Date to the creation date
lastUpdatedDate = (Date) creationDate.clone();
}
// ...snip.. Getters, Setters, equals, hashcode created by IDEA here
}
CoworkerController.java
@Controller
@RequestMapping(value = "coworker")
public class CoworkerController {
@Autowired
CoworkerService service;
Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public Long create(@RequestBody Coworker coworker) {
logger.info("Post to create Coworker.");
if (coworker == null) {
logger.info("Coworker == null");
} else {
logger.info("Coworker.firstName: " + coworker.getFirstName() + " Coworker.lastName: " + coworker.getLastName());
}
final Coworker coworker1 = service.addNewCoworker(coworker);
logger.info("Persisted coworker, id: " + coworker1.getCoworkerId());
return coworker1.getCoworkerId();
}
}
CoworkerServiceImpl.java
@Service
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public class CoworkerServiceImpl implements CoworkerService {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Coworker addNewCoworker(Coworker coworker) {
logger.info("Service saving coworker: " + coworker.getFirstName() + " " + coworker.getLastName());
final Coworker save = repo.save(coworker);
logger.info("Service saved coworker, is it != null? " + (save != null));
logger.info("First name: " + save.getFirstName() + " Last name: " + save.getLastName() + " Date created: " + save.getCreationDate() + " id: " + save.getCoworkerId());
return save;
}
}
CoworkerRepository.java
public interface CoworkerRepository extends CrudRepository<Coworker, Long> {
// Several queries here, but nothing that should interfer with
// CrudRepository.save(S)
}
persistence.xml
<?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="timeregistration" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>java:/comp/env/jdbc/timeregistration</non-jta-data-source>
<class>org.xezz.timeregistration.model.Coworker</class>
<class>org.xezz.timeregistration.model.Customer</class>
<class>org.xezz.timeregistration.model.Project</class>
<class>org.xezz.timeregistration.model.Timeframe</class>
</persistence-unit>
</persistence>
timeregistration-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<mvc:resources mapping="/static/**" location="/static/"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven />
<jpa:repositories base-package="org.xezz.timeregistration.repositories"/>
<context:component-scan base-package="org.xezz.timeregistration" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="timeregistration"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
<property name="generateDdl" value="true"/>
<property name="database" value="POSTGRESQL"/>
<property name="showSql" value="true"/>
</bean>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/comp/env/jdbc/timeregistration"/>
<property name="resourceRef" value="true" />
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="true"/>
</bean>
</list>
</property>
</bean>
</beans>
Consolelog
Mai 09, 2013 11:16:03 PM org.xezz.timeregistration.controller.CoworkerController create
Information: Post to create Coworker.
Mai 09, 2013 11:16:03 PM org.xezz.timeregistration.controller.CoworkerController create
Information: Coworker.firstName: Bastian Coworker.lastName: Koch
Mai 09, 2013 11:16:03 PM org.xezz.timeregistration.services.impl.CoworkerServiceImpl addNewCoworker
Information: Service saving coworker: Bastian Koch
Mai 09, 2013 11:16:03 PM org.xezz.timeregistration.model.Coworker setDateBeforePersisting
Information: Inside prepersisting a Coworker
Mai 09, 2013 11:16:03 PM org.xezz.timeregistration.services.impl.CoworkerServiceImpl addNewCoworker
Information: Service saved coworker, is it != null? true
59370 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 850080749> executing prepstmnt 553961214 SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE [params=?]
59421 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 850080749> [50 ms] spent
59423 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 683618612> executing prepstmnt 540500434 INSERT INTO OPENJPA_SEQUENCE_TABLE (ID, SEQUENCE_VALUE) VALUES (?, ?) [params=?, ?]
59474 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 683618612> [50 ms] spent
59476 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 334967428> executing prepstmnt 512431903 SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE [params=?]
59479 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 334967428> [3 ms] spent
59480 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 334967428> executing prepstmnt 1033569251 UPDATE OPENJPA_SEQUENCE_TABLE SET SEQUENCE_VALUE = ? WHERE ID = ? AND SEQUENCE_VALUE = ? [params=?, ?, ?]
59493 timeregistration TRACE [http-bio-8080-exec-1] openjpa.jdbc.SQL - <t 1732295982, conn 334967428> [12 ms] spent
Mai 09, 2013 11:16:04 PM org.xezz.timeregistration.services.impl.CoworkerServiceImpl addNewCoworker
Information: First name: Bastian Last name: Koch Date created: Thu May 09 23:16:03 CEST 2013 id: 1
Mai 09, 2013 11:16:04 PM org.xezz.timeregistration.controller.CoworkerController create
Information: Persisted coworker, id: 1
tomee.xml
<?xml version="1.0" encoding="UTF-8"?>
<tomee>
<Resource id="jdbc/timeregistration" type="DataSource">
JdbcDriver org.postgresql.Driver
JdbcUrl jdbc:postgresql://localhost/timeregdb
UserName timereg
Password supersecretpassword
jtaManaged false
InitialSize 0
MaxWait 50
MaxActive 20
MaxIdle 20
</Resource>
</tomee>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.xezz</groupId>
<artifactId>timeregistration</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.11</junit.version>
<javax-persistence.version>2.0.0</javax-persistence.version>
<javax-inject.version>1</javax-inject.version>
<spring.version>3.2.2.RELEASE</spring.version>
<spring-data.version>1.3.1.RELEASE</spring-data.version>
<jackson.version>2.1.4</jackson.version>
<jackson-mapper-asl.version>1.9.12</jackson-mapper-asl.version>
<jaxb-api.version>2.2.7</jaxb-api.version>
<slf4j-api.version>1.7.1</slf4j-api.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>${javax-persistence.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${spring-data.version}</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>${javax-inject.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson-mapper-asl.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb-api.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Thanks for any help in advance, I have wasted so much time right now trying to track down different errors (especially following hibernate stuff, which was more time consuming than I dare to tell), so right now I just have to ask someone else to look over this and share wisdom with me and don't hesitate if you need more information (I can update github with the current codebase if needed).
CrudRepository is a Spring Data interface for generic CRUD operations on a repository of a specific type. It provides several methods out of the box for interacting with a database. In this tutorial, we'll explain how and when to use the CrudRepository save() method.
The save () method returns the saved entity, including the updated id field. 5. CrudRepository save () to Update an Instance We can use the same save () method to update an existing entry in our database. Suppose we saved a MerchandiseEntity instance with a specific title:
CrudRepository save () to Update an Instance We can use the same save () method to update an existing entry in our database. Suppose we saved a MerchandiseEntity instance with a specific title: Later, we found that we wanted to update the price of the item.
Unfortunately, when I call repository.save () to update an existing entity the object returned does not have the createdBy and createdDate set. All the fields are set correctly in the database though This behavior is not caused by the auditing feature setting values or not. You are essentially resetting the fields to null.
I think you are using the wrong transactionManager in your spring configuration xml. Since you want to use spring with jpa, you should use the JpaTransactionManager.
For your example, I think your configuration should look as follows:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With