#186 - Prepare upgrade to Spring Boot 1.4 M2 and Hibernate 5.

Upgraded to Spring Boot 1.4 M2 and thus Hibernate 5.1 transitively.
Switched to H2 as database for all examples using JPA by accident as the
invalid error logging for HSQLDB schema creation got worse in 5.1 (see
[0]). The JPA examples themselves have to stay on HSQLDB as H2 doesn't
support stored procedures. The stored procedures example in turn has to
be downgraded to 5.0.7 as all following versions currently break stored
procedure execution support [1]. Reworked the JPA auditing example as
5.1 breaks on generic types used in support types like AbstractAuditable
[2].

Tweaked content type assertions in some REST related test cases as
Spring 4.3 returns an encoding alongside the media type.

[0] https://hibernate.atlassian.net/browse/HHH-10605
[1] https://hibernate.atlassian.net/browse/HHH-10515
[2] https://hibernate.atlassian.net/browse/HHH-10514
This commit is contained in:
Oliver Gierke
2016-04-11 16:09:36 +02:00
parent 763710ddc9
commit 2314c6e726
13 changed files with 73 additions and 118 deletions

View File

@@ -18,11 +18,16 @@ package example.springdata.jpa.eclipselink;
import java.util.Collections;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;
/**
* Spring Boot application that uses EclipseLink as the JPA provider.
@@ -33,6 +38,16 @@ import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
@SpringBootApplication
public class Application extends JpaBaseConfiguration {
/**
* @param dataSource
* @param properties
* @param jtaTransactionManagerProvider
*/
protected Application(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManagerProvider) {
super(dataSource, properties, jtaTransactionManagerProvider);
}
/*
* (non-Javadoc)
* @see org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration#createJpaVendorAdapter()
@@ -52,12 +67,12 @@ public class Application extends JpaBaseConfiguration {
// Turn off dynamic weaving to disable LTW lookup in static weaving mode
return Collections.singletonMap("eclipselink.weaving", "false");
}
public static void main(String[] args) {
CustomerRepository repository = SpringApplication.run(Application.class, args).getBean(CustomerRepository.class);
repository.save(new Customer("Richard", "Feynman"));
System.out.println(repository.findAll());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,23 @@
*/
package example.springdata.jpa.auditing;
import javax.persistence.Entity;
import lombok.Data;
import java.time.LocalDateTime;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.domain.Auditable;
import org.springframework.data.jpa.domain.AbstractAuditable;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* User domain class that uses auditing functionality of Spring Data that can either be aquired implementing
@@ -27,28 +40,17 @@ import org.springframework.data.jpa.domain.AbstractAuditable;
* @author Oliver Gierke
* @author Thomas Darimont
*/
@Data
@Entity
public class AuditableUser extends AbstractAuditable<AuditableUser, Long> {
private static final long serialVersionUID = 1L;
@EntityListeners(AuditingEntityListener.class)
public class AuditableUser {
private @Id @GeneratedValue Long id;
private String username;
/**
* Set's the user's name.
*
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
private @CreatedDate LocalDateTime createdDate;
private @LastModifiedDate LocalDateTime lastModifiedDate;
/**
* Returns the user's name.
*
* @return the username
*/
public String getUsername() {
return username;
}
private @ManyToOne @CreatedBy AuditableUser createdBy;
private @ManyToOne @LastModifiedBy AuditableUser lastModifiedBy;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,4 @@ import org.springframework.data.repository.CrudRepository;
/**
* @author Oliver Gierke
*/
public interface AuditableUserRepository extends CrudRepository<AuditableUser, Long> {
}
public interface AuditableUserRepository extends CrudRepository<AuditableUser, Long> {}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,48 +15,17 @@
*/
package example.springdata.jpa.auditing;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
/**
* @author Oliver Gierke
*/
@Configuration
@EnableAutoConfiguration
@SpringBootApplication
@EnableJpaAuditing
class AuditingConfiguration {
/**
* We need to configure a {@link LocalContainerEntityManagerFactoryBean} manually here as Spring does <em>not</em>
* automatically add the {@code orm.xml} <em>if</em> a {@code persistence.xml} is located right beside it. This is
* necessary to get the {@link example.springdata.jpa.basics.BasicFactorySetup} sample working. However, in a {code
* persistence.xml}-less codebase you can rely on Spring Boot on setting the correct defaults.
*
* @return
*/
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.HSQL);
adapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPackagesToScan(getClass().getPackage().getName());
factoryBean.setMappingResources("META-INF/orm.xml");
factoryBean.setJpaVendorAdapter(adapter);
factoryBean.setDataSource(dataSource);
return factoryBean;
}
@Bean
AuditorAwareImpl auditorAware() {
return new AuditorAwareImpl();

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd" version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>

View File

@@ -21,24 +21,20 @@ import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.annotation.Transactional;
import example.springdata.jpa.auditing.AuditableUser;
import example.springdata.jpa.auditing.AuditableUserRepository;
import example.springdata.jpa.auditing.AuditingConfiguration;
import example.springdata.jpa.auditing.AuditorAwareImpl;
/**
* @author Oliver Gierke
* @author Thomas Darimont
*/
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration(classes = AuditingConfiguration.class)
@SpringBootTest(classes = AuditingConfiguration.class)
public class AuditableUserSample {
@Autowired AuditableUserRepository repository;
@@ -58,7 +54,7 @@ public class AuditableUserSample {
user = repository.save(user);
user = repository.save(user);
assertEquals(user, user.getCreatedBy());
assertEquals(user, user.getLastModifiedBy());
assertThat(user.getCreatedBy(), is(user));
assertThat(user.getLastModifiedBy(), is(user));
}
}

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="error" />
<root level="error">
<appender-ref ref="console" />
</root>
</configuration>

View File

@@ -11,4 +11,9 @@
<artifactId>spring-data-jpa-jpa21</artifactId>
<name>Spring Data JPA - JPA 2.1 specific features</name>
<properties>
<!-- Last Hibernate 5.x version that doesn't break stored procedure support on HSQLDB -->
<hibernate.version>5.0.7.Final</hibernate.version>
</properties>
</project>

View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.M1</version>
<version>1.4.0.M2</version>
</parent>
<modules>

View File

@@ -25,8 +25,8 @@
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>

View File

@@ -20,8 +20,8 @@
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>

View File

@@ -29,8 +29,8 @@
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>

View File

@@ -22,10 +22,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import example.springdata.rest.security.Application;
import example.springdata.rest.security.Employee;
import example.springdata.rest.security.SecurityConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -75,7 +71,7 @@ public class UrlLevelSecurityTests {
mvc.perform(get("/").//
accept(MediaTypes.HAL_JSON)).//
andExpect(header().string("Content-Type", MediaTypes.HAL_JSON.toString())).//
andExpect(content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)).//
andExpect(status().isOk()).//
andDo(print());
}
@@ -94,12 +90,12 @@ public class UrlLevelSecurityTests {
public void allowsGetRequestsButRejectsPostForUser() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON.toString());
headers.add(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
headers.add(HttpHeaders.AUTHORIZATION, "Basic " + new String(Base64.encode(("greg:turnquist").getBytes())));
mvc.perform(get("/employees").//
headers(headers)).//
andExpect(content().contentType(MediaTypes.HAL_JSON)).//
andExpect(content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)).//
andExpect(status().isOk()).//
andDo(print());
@@ -113,20 +109,22 @@ public class UrlLevelSecurityTests {
public void allowsPostRequestForAdmin() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT, "application/hal+json");
headers.set(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
headers.set(HttpHeaders.AUTHORIZATION, "Basic " + new String(Base64.encode(("ollie:gierke").getBytes())));
mvc.perform(get("/employees").//
headers(headers)).//
andExpect(content().contentType(MediaTypes.HAL_JSON)).//
andExpect(content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)).//
andExpect(status().isOk()).//
andDo(print());
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
String location = mvc.perform(post("/employees").//
content(PAYLOAD).//
headers(headers)).//
String location = mvc
.perform(post("/employees").//
content(PAYLOAD).//
headers(headers))
.//
andExpect(status().isCreated()).//
andDo(print()).//
andReturn().getResponse().getHeader(HttpHeaders.LOCATION);