Commit 943262bb authored by Andy Wilkinson's avatar Andy Wilkinson

Raise the minimum supported version of Hibernate to 5.2.x

Closes gh-7586
parent 1782d778
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.orm.jpa;
import org.springframework.util.ClassUtils;
/**
* Supported Hibernate versions.
*
* @author Phillip Webb
*/
enum HibernateVersion {
/**
* Version 4.
*/
V4,
/**
* Version 5.
*/
V5;
private static final String HIBERNATE_5_CLASS = "org.hibernate.boot.model."
+ "naming.PhysicalNamingStrategy";
private static HibernateVersion running;
public static HibernateVersion getRunning() {
if (running == null) {
setRunning(ClassUtils.isPresent(HIBERNATE_5_CLASS, null) ? V5 : V4);
}
return running;
}
static void setRunning(HibernateVersion running) {
HibernateVersion.running = running;
}
}
...@@ -140,8 +140,7 @@ public class JpaProperties { ...@@ -140,8 +140,7 @@ public class JpaProperties {
/** /**
* Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. This is * Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. This is
* actually a shortcut for the "hibernate.id.new_generator_mappings" property. * actually a shortcut for the "hibernate.id.new_generator_mappings" property.
* When not specified will default to "false" with Hibernate 5 for back * When not specified will default to "false" for backwards compatibility.
* compatibility.
*/ */
private Boolean useNewIdGeneratorMappings; private Boolean useNewIdGeneratorMappings;
...@@ -172,7 +171,7 @@ public class JpaProperties { ...@@ -172,7 +171,7 @@ public class JpaProperties {
DataSource dataSource) { DataSource dataSource) {
Map<String, String> result = new HashMap<String, String>(existing); Map<String, String> result = new HashMap<String, String>(existing);
applyNewIdGeneratorMappings(result); applyNewIdGeneratorMappings(result);
getNaming().applyNamingStrategy(result); getNaming().applyNamingStrategies(result);
String ddlAuto = getOrDeduceDdlAuto(existing, dataSource); String ddlAuto = getOrDeduceDdlAuto(existing, dataSource);
if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) { if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) {
result.put("hibernate.hbm2ddl.auto", ddlAuto); result.put("hibernate.hbm2ddl.auto", ddlAuto);
...@@ -188,8 +187,7 @@ public class JpaProperties { ...@@ -188,8 +187,7 @@ public class JpaProperties {
result.put(USE_NEW_ID_GENERATOR_MAPPINGS, result.put(USE_NEW_ID_GENERATOR_MAPPINGS,
this.useNewIdGeneratorMappings.toString()); this.useNewIdGeneratorMappings.toString());
} }
else if (HibernateVersion.getRunning() == HibernateVersion.V5 else if (!result.containsKey(USE_NEW_ID_GENERATOR_MAPPINGS)) {
&& !result.containsKey(USE_NEW_ID_GENERATOR_MAPPINGS)) {
result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "false"); result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "false");
} }
} }
...@@ -219,28 +217,20 @@ public class JpaProperties { ...@@ -219,28 +217,20 @@ public class JpaProperties {
public static class Naming { public static class Naming {
private static final String DEFAULT_HIBERNATE4_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy";
private static final String DEFAULT_PHYSICAL_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy"; private static final String DEFAULT_PHYSICAL_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy";
private static final String DEFAULT_IMPLICIT_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"; private static final String DEFAULT_IMPLICIT_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy";
/** /**
* Hibernate 5 implicit naming strategy fully qualified name. * Fully qualfied name of the implicit naming strategy.
*/ */
private String implicitStrategy; private String implicitStrategy;
/** /**
* Hibernate 5 physical naming strategy fully qualified name. * Fully qualified name of the physical naming strategy.
*/ */
private String physicalStrategy; private String physicalStrategy;
/**
* Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate
* 5.
*/
private String strategy;
public String getImplicitStrategy() { public String getImplicitStrategy() {
return this.implicitStrategy; return this.implicitStrategy;
} }
...@@ -257,36 +247,15 @@ public class JpaProperties { ...@@ -257,36 +247,15 @@ public class JpaProperties {
this.physicalStrategy = physicalStrategy; this.physicalStrategy = physicalStrategy;
} }
public String getStrategy() { private void applyNamingStrategies(Map<String, String> properties) {
return this.strategy; applyNamingStrategy(properties, "hibernate.implicit_naming_strategy",
} this.implicitStrategy, DEFAULT_IMPLICIT_STRATEGY);
applyNamingStrategy(properties, "hibernate.physical_naming_strategy",
public void setStrategy(String strategy) { this.physicalStrategy, DEFAULT_PHYSICAL_STRATEGY);
this.strategy = strategy;
}
private void applyNamingStrategy(Map<String, String> properties) {
switch (HibernateVersion.getRunning()) {
case V4:
applyHibernate4NamingStrategy(properties);
break;
case V5:
applyHibernate5NamingStrategy(properties);
break;
}
} }
private void applyHibernate5NamingStrategy(Map<String, String> properties) { private void applyNamingStrategy(Map<String, String> properties, String key,
applyHibernate5NamingStrategy(properties, String strategy, String defaultStrategy) {
"hibernate.implicit_naming_strategy", this.implicitStrategy,
DEFAULT_IMPLICIT_STRATEGY);
applyHibernate5NamingStrategy(properties,
"hibernate.physical_naming_strategy", this.physicalStrategy,
DEFAULT_PHYSICAL_STRATEGY);
}
private void applyHibernate5NamingStrategy(Map<String, String> properties,
String key, String strategy, String defaultStrategy) {
if (strategy != null) { if (strategy != null) {
properties.put(key, strategy); properties.put(key, strategy);
} }
...@@ -295,21 +264,6 @@ public class JpaProperties { ...@@ -295,21 +264,6 @@ public class JpaProperties {
} }
} }
private void applyHibernate4NamingStrategy(Map<String, String> properties) {
if (!properties.containsKey("hibernate.ejb.naming_strategy_delegator")) {
properties.put("hibernate.ejb.naming_strategy",
getHibernate4NamingStrategy(properties));
}
}
private String getHibernate4NamingStrategy(Map<String, String> existing) {
if (!existing.containsKey("hibernate.ejb.naming_strategy")
&& this.strategy != null) {
return this.strategy;
}
return DEFAULT_HIBERNATE4_STRATEGY;
}
} }
} }
...@@ -26,7 +26,6 @@ import javax.transaction.TransactionManager; ...@@ -26,7 +26,6 @@ import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.junit.After;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
...@@ -41,6 +40,7 @@ import org.springframework.jdbc.core.JdbcTemplate; ...@@ -41,6 +40,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link HibernateJpaAutoConfiguration}. * Tests for {@link HibernateJpaAutoConfiguration}.
...@@ -55,11 +55,6 @@ public class HibernateJpaAutoConfigurationTests ...@@ -55,11 +55,6 @@ public class HibernateJpaAutoConfigurationTests
@Rule @Rule
public ExpectedException thrown = ExpectedException.none(); public ExpectedException thrown = ExpectedException.none();
@After
public void cleanup() {
HibernateVersion.setRunning(null);
}
@Override @Override
protected Class<?> getAutoConfigureClass() { protected Class<?> getAutoConfigureClass() {
return HibernateJpaAutoConfiguration.class; return HibernateJpaAutoConfiguration.class;
...@@ -90,38 +85,6 @@ public class HibernateJpaAutoConfigurationTests ...@@ -90,38 +85,6 @@ public class HibernateJpaAutoConfigurationTests
.queryForObject("SELECT COUNT(*) from CITY", Integer.class)).isEqualTo(1); .queryForObject("SELECT COUNT(*) from CITY", Integer.class)).isEqualTo(1);
} }
@Test
public void testCustomNamingStrategy() throws Exception {
HibernateVersion.setRunning(HibernateVersion.V4);
EnvironmentTestUtils.addEnvironment(this.context,
"spring.jpa.hibernate.naming.strategy:"
+ "org.hibernate.cfg.EJB3NamingStrategy");
setupTestConfiguration();
this.context.refresh();
LocalContainerEntityManagerFactoryBean bean = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class);
String actual = (String) bean.getJpaPropertyMap()
.get("hibernate.ejb.naming_strategy");
assertThat(actual).isEqualTo("org.hibernate.cfg.EJB3NamingStrategy");
}
@Test
public void testCustomNamingStrategyViaJpaProperties() throws Exception {
HibernateVersion.setRunning(HibernateVersion.V4);
EnvironmentTestUtils.addEnvironment(this.context,
"spring.jpa.properties.hibernate.ejb.naming_strategy:"
+ "org.hibernate.cfg.EJB3NamingStrategy");
setupTestConfiguration();
this.context.refresh();
LocalContainerEntityManagerFactoryBean bean = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class);
String actual = (String) bean.getJpaPropertyMap()
.get("hibernate.ejb.naming_strategy");
// You can't override this one from spring.jpa.properties because it has an
// opinionated default
assertThat(actual).isNotEqualTo("org.hibernate.cfg.EJB3NamingStrategy");
}
@Test @Test
public void testFlywayPlusValidation() throws Exception { public void testFlywayPlusValidation() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
...@@ -175,7 +138,7 @@ public class HibernateJpaAutoConfigurationTests ...@@ -175,7 +138,7 @@ public class HibernateJpaAutoConfigurationTests
@Override @Override
public TransactionManager retrieveTransactionManager() { public TransactionManager retrieveTransactionManager() {
throw new UnsupportedOperationException(); return mock(TransactionManager.class);
} }
@Override @Override
......
...@@ -27,7 +27,6 @@ import org.junit.Test; ...@@ -27,7 +27,6 @@ import org.junit.Test;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
...@@ -49,54 +48,14 @@ public class JpaPropertiesTests { ...@@ -49,54 +48,14 @@ public class JpaPropertiesTests {
@After @After
public void close() { public void close() {
HibernateVersion.setRunning(null);
if (this.context != null) { if (this.context != null) {
this.context.close(); this.context.close();
} }
} }
@Test @Test
public void hibernate4NoCustomNamingStrategy() throws Exception { public void noCustomNamingStrategy() throws Exception {
JpaProperties properties = load(HibernateVersion.V4); JpaProperties properties = load();
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties).contains(entry("hibernate.ejb.naming_strategy",
SpringNamingStrategy.class.getName()));
assertThat(hibernateProperties).doesNotContainKeys(
"hibernate.implicit_naming_strategy",
"hibernate.physical_naming_strategy");
}
@Test
public void hibernate4CustomNamingStrategy() throws Exception {
JpaProperties properties = load(HibernateVersion.V4,
"spring.jpa.hibernate.naming.strategy:"
+ "org.hibernate.cfg.EJB3NamingStrategy");
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties).contains(entry("hibernate.ejb.naming_strategy",
"org.hibernate.cfg.EJB3NamingStrategy"));
assertThat(hibernateProperties).doesNotContainKeys(
"hibernate.implicit_naming_strategy",
"hibernate.physical_naming_strategy");
}
@Test
public void hibernate4CustomNamingStrategyViaJpaProperties() throws Exception {
JpaProperties properties = load(HibernateVersion.V4,
"spring.jpa.properties.hibernate.ejb.naming_strategy:"
+ "org.hibernate.cfg.EJB3NamingStrategy");
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
String actual = hibernateProperties.get("hibernate.ejb.naming_strategy");
// You can't override this one from spring.jpa.properties because it has an
// opinionated default
assertThat(actual).isNotEqualTo("org.hibernate.cfg.EJB3NamingStrategy");
}
@Test
public void hibernate5NoCustomNamingStrategy() throws Exception {
JpaProperties properties = load(HibernateVersion.V5);
Map<String, String> hibernateProperties = properties Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource()); .getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties) assertThat(hibernateProperties)
...@@ -111,7 +70,7 @@ public class JpaPropertiesTests { ...@@ -111,7 +70,7 @@ public class JpaPropertiesTests {
@Test @Test
public void hibernate5CustomNamingStrategies() throws Exception { public void hibernate5CustomNamingStrategies() throws Exception {
JpaProperties properties = load(HibernateVersion.V5, JpaProperties properties = load(
"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit", "spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit",
"spring.jpa.hibernate.naming.physical-strategy:com.example.Physical"); "spring.jpa.hibernate.naming.physical-strategy:com.example.Physical");
Map<String, String> hibernateProperties = properties Map<String, String> hibernateProperties = properties
...@@ -125,7 +84,7 @@ public class JpaPropertiesTests { ...@@ -125,7 +84,7 @@ public class JpaPropertiesTests {
@Test @Test
public void hibernate5CustomNamingStrategiesViaJpaProperties() throws Exception { public void hibernate5CustomNamingStrategiesViaJpaProperties() throws Exception {
JpaProperties properties = load(HibernateVersion.V5, JpaProperties properties = load(
"spring.jpa.properties.hibernate.implicit_naming_strategy:com.example.Implicit", "spring.jpa.properties.hibernate.implicit_naming_strategy:com.example.Implicit",
"spring.jpa.properties.hibernate.physical_naming_strategy:com.example.Physical"); "spring.jpa.properties.hibernate.physical_naming_strategy:com.example.Physical");
Map<String, String> hibernateProperties = properties Map<String, String> hibernateProperties = properties
...@@ -139,17 +98,8 @@ public class JpaPropertiesTests { ...@@ -139,17 +98,8 @@ public class JpaPropertiesTests {
} }
@Test @Test
public void useNewIdGeneratorMappingsDefaultHibernate4() throws Exception { public void useNewIdGeneratorMappingsDefault() throws Exception {
JpaProperties properties = load(HibernateVersion.V4); JpaProperties properties = load();
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties)
.doesNotContainKey(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS);
}
@Test
public void useNewIdGeneratorMappingsDefaultHibernate5() throws Exception {
JpaProperties properties = load(HibernateVersion.V5);
Map<String, String> hibernateProperties = properties Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource()); .getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties) assertThat(hibernateProperties)
...@@ -158,7 +108,7 @@ public class JpaPropertiesTests { ...@@ -158,7 +108,7 @@ public class JpaPropertiesTests {
@Test @Test
public void useNewIdGeneratorMappingsTrue() throws Exception { public void useNewIdGeneratorMappingsTrue() throws Exception {
JpaProperties properties = load(HibernateVersion.V5, JpaProperties properties = load(
"spring.jpa.hibernate.use-new-id-generator-mappings:true"); "spring.jpa.hibernate.use-new-id-generator-mappings:true");
Map<String, String> hibernateProperties = properties Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource()); .getHibernateProperties(mockStandaloneDataSource());
...@@ -173,8 +123,7 @@ public class JpaPropertiesTests { ...@@ -173,8 +123,7 @@ public class JpaPropertiesTests {
return ds; return ds;
} }
private JpaProperties load(HibernateVersion hibernateVersion, String... environment) { private JpaProperties load(String... environment) {
HibernateVersion.setRunning(hibernateVersion);
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment); EnvironmentTestUtils.addEnvironment(ctx, environment);
ctx.register(TestConfiguration.class); ctx.register(TestConfiguration.class);
......
...@@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@RunWith(ModifiedClassPathRunner.class) @RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("tomcat-embed-el-*.jar") @ClassPathExclusions({ "tomcat-embed-el-*.jar", "el-api-*.jar" })
public class ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests { public class ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests {
private AnnotationConfigApplicationContext context; private AnnotationConfigApplicationContext context;
......
...@@ -3,6 +3,8 @@ databaseChangeLog: ...@@ -3,6 +3,8 @@ databaseChangeLog:
id: 1 id: 1
author: dsyer author: dsyer
changes: changes:
- createSequence:
sequenceName: hibernate_sequence
- createTable: - createTable:
tableName: city tableName: city
columns: columns:
......
CREATE SEQUENCE HIBERNATE_SEQUENCE;
CREATE TABLE CITY ( CREATE TABLE CITY (
id BIGINT GENERATED BY DEFAULT AS IDENTITY, id BIGINT GENERATED BY DEFAULT AS IDENTITY,
name VARCHAR(30), name VARCHAR(30),
state VARCHAR(30), state VARCHAR(30),
country VARCHAR(30), country VARCHAR(30),
map VARCHAR(30) map VARCHAR(30)
); );
\ No newline at end of file
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
<hazelcast.version>3.7.1</hazelcast.version> <hazelcast.version>3.7.1</hazelcast.version>
<hazelcast-hibernate4.version>3.6.5</hazelcast-hibernate4.version> <hazelcast-hibernate4.version>3.6.5</hazelcast-hibernate4.version>
<hazelcast-hibernate5.version>1.0.1</hazelcast-hibernate5.version> <hazelcast-hibernate5.version>1.0.1</hazelcast-hibernate5.version>
<hibernate.version>5.0.11.Final</hibernate.version> <hibernate.version>5.2.5.Final</hibernate.version>
<hibernate-validator.version>5.2.4.Final</hibernate-validator.version> <hibernate-validator.version>5.2.4.Final</hibernate-validator.version>
<hikaricp.version>2.4.7</hikaricp.version> <hikaricp.version>2.4.7</hikaricp.version>
<hikaricp-java6.version>2.3.13</hikaricp-java6.version> <hikaricp-java6.version>2.3.13</hikaricp-java6.version>
...@@ -610,11 +610,6 @@ ...@@ -610,11 +610,6 @@
<artifactId>jackson-datatype-guava</artifactId> <artifactId>jackson-datatype-guava</artifactId>
<version>${jackson.version}</version> <version>${jackson.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId> <artifactId>jackson-datatype-hibernate5</artifactId>
...@@ -710,11 +705,6 @@ ...@@ -710,11 +705,6 @@
<artifactId>hazelcast-client</artifactId> <artifactId>hazelcast-client</artifactId>
<version>${hazelcast.version}</version> <version>${hazelcast.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-hibernate4</artifactId>
<version>${hazelcast-hibernate4.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.hazelcast</groupId> <groupId>com.hazelcast</groupId>
<artifactId>hazelcast-hibernate5</artifactId> <artifactId>hazelcast-hibernate5</artifactId>
......
...@@ -650,9 +650,8 @@ content into your application; rather pick only the properties that you need. ...@@ -650,9 +650,8 @@ content into your application; rather pick only the properties that you need.
spring.jpa.database-platform= # Name of the target database to operate on, auto-detected by default. Can be alternatively set using the "Database" enum. spring.jpa.database-platform= # Name of the target database to operate on, auto-detected by default. Can be alternatively set using the "Database" enum.
spring.jpa.generate-ddl=false # Initialize the schema on startup. spring.jpa.generate-ddl=false # Initialize the schema on startup.
spring.jpa.hibernate.ddl-auto= # DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property. Default to "create-drop" when using an embedded database, "none" otherwise. spring.jpa.hibernate.ddl-auto= # DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" property. Default to "create-drop" when using an embedded database, "none" otherwise.
spring.jpa.hibernate.naming.implicit-strategy= # Hibernate 5 implicit naming strategy fully qualified name. spring.jpa.hibernate.naming.implicit-strategy= # Implicit naming strategy fully qualified name.
spring.jpa.hibernate.naming.physical-strategy= # Hibernate 5 physical naming strategy fully qualified name. spring.jpa.hibernate.naming.physical-strategy= # Physical naming strategy fully qualified name.
spring.jpa.hibernate.naming.strategy= # Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate 5.
spring.jpa.hibernate.use-new-id-generator-mappings= # Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. spring.jpa.hibernate.use-new-id-generator-mappings= # Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE.
spring.jpa.open-in-view=true # Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request. spring.jpa.open-in-view=true # Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request.
spring.jpa.properties.*= # Additional native properties to set on the JPA provider. spring.jpa.properties.*= # Additional native properties to set on the JPA provider.
......
...@@ -1812,12 +1812,10 @@ whether you are using an embedded database (`create-drop`) or not (`none`). In a ...@@ -1812,12 +1812,10 @@ whether you are using an embedded database (`create-drop`) or not (`none`). In a
all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties
(with the prefix stripped) when the local `EntityManagerFactory` is created. (with the prefix stripped) when the local `EntityManagerFactory` is created.
Spring Boot provides a consistent naming strategy regardless of the Hibernate generation Hibernate defines `Physical` and `Implicit` naming strategies: Spring Boot configures
that you are using. If you are using Hibernate 4, you can customize it using `SpringPhysicalNamingStrategy` by default. This implementation provides the same
`spring.jpa.hibernate.naming.strategy`; Hibernate 5 defines a `Physical` and `Implicit` table structure as Hibernate 4. If you'd rather use Hibernate 5's default instead, set
naming strategies: Spring Boot configures `SpringPhysicalNamingStrategy` by default. This the following property:
implementation provides the same table structure as Hibernate 4. If you'd rather use
Hibernate 5's default instead, set the following property:
[indent=0,subs="verbatim,quotes,attributes"] [indent=0,subs="verbatim,quotes,attributes"]
---- ----
......
...@@ -2897,15 +2897,6 @@ http://spring.io and read the http://projects.spring.io/spring-data-jpa/[Spring ...@@ -2897,15 +2897,6 @@ http://spring.io and read the http://projects.spring.io/spring-data-jpa/[Spring
and http://hibernate.org/orm/documentation/[Hibernate] reference documentation. and http://hibernate.org/orm/documentation/[Hibernate] reference documentation.
[NOTE]
====
By default, Spring Boot uses Hibernate 5.0.x. However it's also possible to use 4.3.x
or 5.2.x if you wish. Please refer to the
{github-code}/spring-boot-samples/spring-boot-sample-hibernate4[Hibernate 4] and
{github-code}/spring-boot-samples/spring-boot-sample-hibernate52[Hibernate 5.2] samples
to see how to do so.
====
[[boot-features-entity-classes]] [[boot-features-entity-classes]]
==== Entity Classes ==== Entity Classes
......
...@@ -77,12 +77,6 @@ The following sample applications are provided: ...@@ -77,12 +77,6 @@ The following sample applications are provided:
| link:spring-boot-sample-hateoas[spring-boot-sample-hateoas] | link:spring-boot-sample-hateoas[spring-boot-sample-hateoas]
| RESTful API built using Spring Hateoas | RESTful API built using Spring Hateoas
| link:spring-boot-sample-hibernate4[spring-boot-sample-hibernate4]
| Demonstrates how to use Hibernate 4
| link:spring-boot-sample-hibernate4[spring-boot-sample-hibernate52]
| Demonstrates how to use Hibernate 5.2
| link:spring-boot-sample-hypermedia[spring-boot-sample-hypermedia] | link:spring-boot-sample-hypermedia[spring-boot-sample-hypermedia]
| Demonstrates Actuator's hypermedia support, including HAL Browser | Demonstrates Actuator's hypermedia support, including HAL Browser
......
...@@ -45,8 +45,6 @@ ...@@ -45,8 +45,6 @@
<module>spring-boot-sample-devtools</module> <module>spring-boot-sample-devtools</module>
<module>spring-boot-sample-flyway</module> <module>spring-boot-sample-flyway</module>
<module>spring-boot-sample-hateoas</module> <module>spring-boot-sample-hateoas</module>
<module>spring-boot-sample-hibernate4</module>
<module>spring-boot-sample-hibernate52</module>
<module>spring-boot-sample-hypermedia</module> <module>spring-boot-sample-hypermedia</module>
<module>spring-boot-sample-hypermedia-gson</module> <module>spring-boot-sample-hypermedia-gson</module>
<module>spring-boot-sample-hypermedia-jpa</module> <module>spring-boot-sample-hypermedia-jpa</module>
......
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-hibernate4</artifactId>
<name>Spring Boot Hibernate 4 Sample</name>
<description>Spring Boot Hibernate 4 Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<hibernate.version>4.3.11.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleHibernate4Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleHibernate4Application.class, args);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class City implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
@Column(nullable = false)
private String country;
@Column(nullable = false)
private String map;
protected City() {
}
public City(String name, String country) {
super();
this.name = name;
this.country = country;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
public String getCountry() {
return this.country;
}
public String getMap() {
return this.map;
}
@Override
public String toString() {
return getName() + "," + getState() + "," + getCountry();
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.hibernate.annotations.NaturalId;
@Entity
public class Hotel implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@NaturalId
private City city;
@Column(nullable = false)
@NaturalId
private String name;
@Column(nullable = false)
private String address;
@Column(nullable = false)
private String zip;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
private Set<Review> reviews;
protected Hotel() {
}
public Hotel(City city, String name) {
this.city = city;
this.name = name;
}
public City getCity() {
return this.city;
}
public String getName() {
return this.name;
}
public String getAddress() {
return this.address;
}
public String getZip() {
return this.zip;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
public interface HotelSummary {
City getCity();
String getName();
Double getAverageRating();
default Integer getAverageRatingRounded() {
return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
public enum Rating {
TERRIBLE, POOR, AVERAGE, GOOD, EXCELLENT,
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
public interface RatingCount {
Rating getRating();
long getCount();
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.util.Assert;
@Entity
public class Review implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
private Hotel hotel;
@Column(nullable = false, name = "idx")
private int index;
@Column(nullable = false)
@Enumerated(EnumType.ORDINAL)
private Rating rating;
@Column(name = "CHECK_IN_DATE", nullable = false)
@Temporal(TemporalType.DATE)
private Date checkInDate;
@Column(name = "TRIP_TYPE", nullable = false)
@Enumerated(EnumType.ORDINAL)
private TripType tripType;
@Column(nullable = false)
private String title;
@Column(nullable = false, length = 5000)
private String details;
protected Review() {
}
public Review(Hotel hotel, int index, ReviewDetails details) {
Assert.notNull(hotel, "Hotel must not be null");
Assert.notNull(details, "Details must not be null");
this.hotel = hotel;
this.index = index;
this.rating = details.getRating();
this.checkInDate = details.getCheckInDate();
this.tripType = details.getTripType();
this.title = details.getTitle();
this.details = details.getDetails();
}
public Hotel getHotel() {
return this.hotel;
}
public int getIndex() {
return this.index;
}
public Rating getRating() {
return this.rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Date getCheckInDate() {
return this.checkInDate;
}
public void setCheckInDate(Date checkInDate) {
this.checkInDate = checkInDate;
}
public TripType getTripType() {
return this.tripType;
}
public void setTripType(TripType tripType) {
this.tripType = tripType;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetails() {
return this.details;
}
public void setDetails(String details) {
this.details = details;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
import java.io.Serializable;
import java.util.Date;
public class ReviewDetails implements Serializable {
private static final long serialVersionUID = 1L;
private Rating rating;
private Date checkInDate;
private TripType tripType;
private String title;
private String details;
public ReviewDetails() {
}
public Rating getRating() {
return this.rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Date getCheckInDate() {
return this.checkInDate;
}
public void setCheckInDate(Date checkInDate) {
this.checkInDate = checkInDate;
}
public TripType getTripType() {
return this.tripType;
}
public void setTripType(TripType tripType) {
this.tripType = tripType;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetails() {
return this.details;
}
public void setDetails(String details) {
this.details = details;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.domain;
public enum TripType {
BUSINESS, COUPLES, FAMILY, FRIENDS, SOLO
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import sample.hibernate4.domain.City;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
Page<City> findByNameContainingAndCountryContainingAllIgnoringCase(String name,
String country, Pageable pageable);
City findByNameAndCountryAllIgnoringCase(String name, String country);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import java.io.Serializable;
import org.springframework.util.Assert;
public class CitySearchCriteria implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public CitySearchCriteria() {
}
public CitySearchCriteria(String name) {
Assert.notNull(name, "Name must not be null");
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import sample.hibernate4.domain.City;
import sample.hibernate4.domain.HotelSummary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface CityService {
Page<City> findCities(CitySearchCriteria criteria, Pageable pageable);
City getCity(String name, String country);
Page<HotelSummary> getHotels(City city, Pageable pageable);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import sample.hibernate4.domain.City;
import sample.hibernate4.domain.HotelSummary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@Component("cityService")
@Transactional
class CityServiceImpl implements CityService {
private final CityRepository cityRepository;
private final HotelRepository hotelRepository;
public CityServiceImpl(CityRepository cityRepository,
HotelRepository hotelRepository) {
this.cityRepository = cityRepository;
this.hotelRepository = hotelRepository;
}
@Override
public Page<City> findCities(CitySearchCriteria criteria, Pageable pageable) {
Assert.notNull(criteria, "Criteria must not be null");
String name = criteria.getName();
if (!StringUtils.hasLength(name)) {
return this.cityRepository.findAll(null);
}
String country = "";
int splitPos = name.lastIndexOf(",");
if (splitPos >= 0) {
country = name.substring(splitPos + 1);
name = name.substring(0, splitPos);
}
return this.cityRepository
.findByNameContainingAndCountryContainingAllIgnoringCase(name.trim(),
country.trim(), pageable);
}
@Override
public City getCity(String name, String country) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(country, "Country must not be null");
return this.cityRepository.findByNameAndCountryAllIgnoringCase(name, country);
}
@Override
public Page<HotelSummary> getHotels(City city, Pageable pageable) {
Assert.notNull(city, "City must not be null");
return this.hotelRepository.findByCity(city, pageable);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import java.util.List;
import sample.hibernate4.domain.City;
import sample.hibernate4.domain.Hotel;
import sample.hibernate4.domain.HotelSummary;
import sample.hibernate4.domain.RatingCount;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
interface HotelRepository extends Repository<Hotel, Long> {
Hotel findByCityAndName(City city, String name);
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
+ "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
@Query("select r.rating as rating, count(r) as count "
+ "from Review r where r.hotel = ?1 group by r.rating order by r.rating DESC")
List<RatingCount> findRatingCounts(Hotel hotel);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import sample.hibernate4.domain.City;
import sample.hibernate4.domain.Hotel;
import sample.hibernate4.domain.Review;
import sample.hibernate4.domain.ReviewDetails;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface HotelService {
Hotel getHotel(City city, String name);
Page<Review> getReviews(Hotel hotel, Pageable pageable);
Review getReview(Hotel hotel, int index);
Review addReview(Hotel hotel, ReviewDetails details);
ReviewsSummary getReviewSummary(Hotel hotel);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import sample.hibernate4.domain.City;
import sample.hibernate4.domain.Hotel;
import sample.hibernate4.domain.Rating;
import sample.hibernate4.domain.RatingCount;
import sample.hibernate4.domain.Review;
import sample.hibernate4.domain.ReviewDetails;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@Component("hotelService")
@Transactional
class HotelServiceImpl implements HotelService {
private final HotelRepository hotelRepository;
private final ReviewRepository reviewRepository;
public HotelServiceImpl(HotelRepository hotelRepository,
ReviewRepository reviewRepository) {
this.hotelRepository = hotelRepository;
this.reviewRepository = reviewRepository;
}
@Override
public Hotel getHotel(City city, String name) {
Assert.notNull(city, "City must not be null");
Assert.hasLength(name, "Name must not be empty");
return this.hotelRepository.findByCityAndName(city, name);
}
@Override
public Page<Review> getReviews(Hotel hotel, Pageable pageable) {
Assert.notNull(hotel, "Hotel must not be null");
return this.reviewRepository.findByHotel(hotel, pageable);
}
@Override
public Review getReview(Hotel hotel, int reviewNumber) {
Assert.notNull(hotel, "Hotel must not be null");
return this.reviewRepository.findByHotelAndIndex(hotel, reviewNumber);
}
@Override
public Review addReview(Hotel hotel, ReviewDetails details) {
Review review = new Review(hotel, 1, details);
return this.reviewRepository.save(review);
}
@Override
public ReviewsSummary getReviewSummary(Hotel hotel) {
List<RatingCount> ratingCounts = this.hotelRepository.findRatingCounts(hotel);
return new ReviewsSummaryImpl(ratingCounts);
}
private static class ReviewsSummaryImpl implements ReviewsSummary {
private final Map<Rating, Long> ratingCount;
public ReviewsSummaryImpl(List<RatingCount> ratingCounts) {
this.ratingCount = new HashMap<Rating, Long>();
for (RatingCount ratingCount : ratingCounts) {
this.ratingCount.put(ratingCount.getRating(), ratingCount.getCount());
}
}
@Override
public long getNumberOfReviewsWithRating(Rating rating) {
Long count = this.ratingCount.get(rating);
return count == null ? 0 : count;
}
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import sample.hibernate4.domain.Hotel;
import sample.hibernate4.domain.Review;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
interface ReviewRepository extends Repository<Review, Long> {
Page<Review> findByHotel(Hotel hotel, Pageable pageable);
Review findByHotelAndIndex(Hotel hotel, int index);
Review save(Review review);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import sample.hibernate4.domain.Rating;
public interface ReviewsSummary {
long getNumberOfReviewsWithRating(Rating rating);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.web;
import sample.hibernate4.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SampleController {
@Autowired
private CityService cityService;
@GetMapping("/")
@ResponseBody
@Transactional(readOnly = true)
public String helloWorld() {
return this.cityService.getCity("Bath", "UK").getName();
}
}
spring.h2.console.enabled=true
logging.level.org.hibernate.SQL=debug
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4;
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
import org.junit.Before;
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.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Integration test to run the application.
*
* @author Oliver Gierke
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@SpringBootTest
// Enable JMX so we can test the MBeans (you can't do this in a properties file)
@TestPropertySource(properties = { "spring.jmx.enabled:true",
"spring.datasource.jmx-enabled:true" })
@ActiveProfiles("scratch")
// Separate profile for web tests to avoid clashing databases
public class SampleHibernate4ApplicationTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void testHome() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(content().string("Bath"));
}
@Test
public void testJmx() throws Exception {
assertThat(ManagementFactory.getPlatformMBeanServer()
.queryMBeans(new ObjectName("jpa.sample:type=ConnectionPool,*"), null))
.hasSize(1);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import sample.hibernate4.domain.City;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link CityRepository}.
*
* @author Oliver Gierke
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CityRepositoryIntegrationTests {
@Autowired
CityRepository repository;
@Test
public void findsFirstPageOfCities() {
Page<City> cities = this.repository.findAll(new PageRequest(0, 10));
assertThat(cities.getTotalElements()).isGreaterThan(20L);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate4.service;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import sample.hibernate4.domain.City;
import sample.hibernate4.domain.Hotel;
import sample.hibernate4.domain.HotelSummary;
import sample.hibernate4.domain.Rating;
import sample.hibernate4.domain.RatingCount;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link HotelRepository}.
*
* @author Oliver Gierke
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class HotelRepositoryIntegrationTests {
@Autowired
CityRepository cityRepository;
@Autowired
HotelRepository repository;
@Test
public void executesQueryMethodsCorrectly() {
City city = this.cityRepository
.findAll(new PageRequest(0, 1, Direction.ASC, "name")).getContent()
.get(0);
assertThat(city.getName()).isEqualTo("Atlanta");
Page<HotelSummary> hotels = this.repository.findByCity(city,
new PageRequest(0, 10, Direction.ASC, "name"));
Hotel hotel = this.repository.findByCityAndName(city,
hotels.getContent().get(0).getName());
assertThat(hotel.getName()).isEqualTo("Doubletree");
List<RatingCount> counts = this.repository.findRatingCounts(hotel);
assertThat(counts).hasSize(1);
assertThat(counts.get(0).getRating()).isEqualTo(Rating.AVERAGE);
assertThat(counts.get(0).getCount()).isGreaterThan(1L);
}
}
spring.datasource.name=scratchdb
spring.jmx.default-domain=jpa.sample
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-hibernate52</artifactId>
<name>Spring Boot Hibernate 5.2 Sample</name>
<description>Spring Boot Hibernate 5.2 Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<hibernate.version>5.2.0.Final</hibernate.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleHibernate52Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleHibernate52Application.class, args);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class City implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
@Column(nullable = false)
private String country;
@Column(nullable = false)
private String map;
protected City() {
}
public City(String name, String country) {
super();
this.name = name;
this.country = country;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
public String getCountry() {
return this.country;
}
public String getMap() {
return this.map;
}
@Override
public String toString() {
return getName() + "," + getState() + "," + getCountry();
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.hibernate.annotations.NaturalId;
@Entity
public class Hotel implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@NaturalId
private City city;
@Column(nullable = false)
@NaturalId
private String name;
@Column(nullable = false)
private String address;
@Column(nullable = false)
private String zip;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "hotel")
private Set<Review> reviews;
protected Hotel() {
}
public Hotel(City city, String name) {
this.city = city;
this.name = name;
}
public City getCity() {
return this.city;
}
public String getName() {
return this.name;
}
public String getAddress() {
return this.address;
}
public String getZip() {
return this.zip;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
public interface HotelSummary {
City getCity();
String getName();
Double getAverageRating();
default Integer getAverageRatingRounded() {
return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
public enum Rating {
TERRIBLE, POOR, AVERAGE, GOOD, EXCELLENT,
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
public interface RatingCount {
Rating getRating();
long getCount();
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.util.Assert;
@Entity
public class Review implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
private Hotel hotel;
@Column(nullable = false, name = "idx")
private int index;
@Column(nullable = false)
@Enumerated(EnumType.ORDINAL)
private Rating rating;
@Column(name = "CHECK_IN_DATE", nullable = false)
@Temporal(TemporalType.DATE)
private Date checkInDate;
@Column(name = "TRIP_TYPE", nullable = false)
@Enumerated(EnumType.ORDINAL)
private TripType tripType;
@Column(nullable = false)
private String title;
@Column(nullable = false, length = 5000)
private String details;
protected Review() {
}
public Review(Hotel hotel, int index, ReviewDetails details) {
Assert.notNull(hotel, "Hotel must not be null");
Assert.notNull(details, "Details must not be null");
this.hotel = hotel;
this.index = index;
this.rating = details.getRating();
this.checkInDate = details.getCheckInDate();
this.tripType = details.getTripType();
this.title = details.getTitle();
this.details = details.getDetails();
}
public Hotel getHotel() {
return this.hotel;
}
public int getIndex() {
return this.index;
}
public Rating getRating() {
return this.rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Date getCheckInDate() {
return this.checkInDate;
}
public void setCheckInDate(Date checkInDate) {
this.checkInDate = checkInDate;
}
public TripType getTripType() {
return this.tripType;
}
public void setTripType(TripType tripType) {
this.tripType = tripType;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetails() {
return this.details;
}
public void setDetails(String details) {
this.details = details;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
import java.io.Serializable;
import java.util.Date;
public class ReviewDetails implements Serializable {
private static final long serialVersionUID = 1L;
private Rating rating;
private Date checkInDate;
private TripType tripType;
private String title;
private String details;
public ReviewDetails() {
}
public Rating getRating() {
return this.rating;
}
public void setRating(Rating rating) {
this.rating = rating;
}
public Date getCheckInDate() {
return this.checkInDate;
}
public void setCheckInDate(Date checkInDate) {
this.checkInDate = checkInDate;
}
public TripType getTripType() {
return this.tripType;
}
public void setTripType(TripType tripType) {
this.tripType = tripType;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetails() {
return this.details;
}
public void setDetails(String details) {
this.details = details;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.domain;
public enum TripType {
BUSINESS, COUPLES, FAMILY, FRIENDS, SOLO
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import sample.hibernate52.domain.City;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
Page<City> findByNameContainingAndCountryContainingAllIgnoringCase(String name,
String country, Pageable pageable);
City findByNameAndCountryAllIgnoringCase(String name, String country);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import java.io.Serializable;
import org.springframework.util.Assert;
public class CitySearchCriteria implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public CitySearchCriteria() {
}
public CitySearchCriteria(String name) {
Assert.notNull(name, "Name must not be null");
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import sample.hibernate52.domain.City;
import sample.hibernate52.domain.HotelSummary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface CityService {
Page<City> findCities(CitySearchCriteria criteria, Pageable pageable);
City getCity(String name, String country);
Page<HotelSummary> getHotels(City city, Pageable pageable);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import sample.hibernate52.domain.City;
import sample.hibernate52.domain.HotelSummary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@Component("cityService")
@Transactional
class CityServiceImpl implements CityService {
private final CityRepository cityRepository;
private final HotelRepository hotelRepository;
public CityServiceImpl(CityRepository cityRepository,
HotelRepository hotelRepository) {
this.cityRepository = cityRepository;
this.hotelRepository = hotelRepository;
}
@Override
public Page<City> findCities(CitySearchCriteria criteria, Pageable pageable) {
Assert.notNull(criteria, "Criteria must not be null");
String name = criteria.getName();
if (!StringUtils.hasLength(name)) {
return this.cityRepository.findAll(null);
}
String country = "";
int splitPos = name.lastIndexOf(",");
if (splitPos >= 0) {
country = name.substring(splitPos + 1);
name = name.substring(0, splitPos);
}
return this.cityRepository
.findByNameContainingAndCountryContainingAllIgnoringCase(name.trim(),
country.trim(), pageable);
}
@Override
public City getCity(String name, String country) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(country, "Country must not be null");
return this.cityRepository.findByNameAndCountryAllIgnoringCase(name, country);
}
@Override
public Page<HotelSummary> getHotels(City city, Pageable pageable) {
Assert.notNull(city, "City must not be null");
return this.hotelRepository.findByCity(city, pageable);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import java.util.List;
import sample.hibernate52.domain.City;
import sample.hibernate52.domain.Hotel;
import sample.hibernate52.domain.HotelSummary;
import sample.hibernate52.domain.RatingCount;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
interface HotelRepository extends Repository<Hotel, Long> {
Hotel findByCityAndName(City city, String name);
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
+ "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
@Query("select r.rating as rating, count(r) as count "
+ "from Review r where r.hotel = ?1 group by r.rating order by r.rating DESC")
List<RatingCount> findRatingCounts(Hotel hotel);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import sample.hibernate52.domain.City;
import sample.hibernate52.domain.Hotel;
import sample.hibernate52.domain.Review;
import sample.hibernate52.domain.ReviewDetails;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface HotelService {
Hotel getHotel(City city, String name);
Page<Review> getReviews(Hotel hotel, Pageable pageable);
Review getReview(Hotel hotel, int index);
Review addReview(Hotel hotel, ReviewDetails details);
ReviewsSummary getReviewSummary(Hotel hotel);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import sample.hibernate52.domain.City;
import sample.hibernate52.domain.Hotel;
import sample.hibernate52.domain.Rating;
import sample.hibernate52.domain.RatingCount;
import sample.hibernate52.domain.Review;
import sample.hibernate52.domain.ReviewDetails;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@Component("hotelService")
@Transactional
class HotelServiceImpl implements HotelService {
private final HotelRepository hotelRepository;
private final ReviewRepository reviewRepository;
public HotelServiceImpl(HotelRepository hotelRepository,
ReviewRepository reviewRepository) {
this.hotelRepository = hotelRepository;
this.reviewRepository = reviewRepository;
}
@Override
public Hotel getHotel(City city, String name) {
Assert.notNull(city, "City must not be null");
Assert.hasLength(name, "Name must not be empty");
return this.hotelRepository.findByCityAndName(city, name);
}
@Override
public Page<Review> getReviews(Hotel hotel, Pageable pageable) {
Assert.notNull(hotel, "Hotel must not be null");
return this.reviewRepository.findByHotel(hotel, pageable);
}
@Override
public Review getReview(Hotel hotel, int reviewNumber) {
Assert.notNull(hotel, "Hotel must not be null");
return this.reviewRepository.findByHotelAndIndex(hotel, reviewNumber);
}
@Override
public Review addReview(Hotel hotel, ReviewDetails details) {
Review review = new Review(hotel, 1, details);
return this.reviewRepository.save(review);
}
@Override
public ReviewsSummary getReviewSummary(Hotel hotel) {
List<RatingCount> ratingCounts = this.hotelRepository.findRatingCounts(hotel);
return new ReviewsSummaryImpl(ratingCounts);
}
private static class ReviewsSummaryImpl implements ReviewsSummary {
private final Map<Rating, Long> ratingCount;
public ReviewsSummaryImpl(List<RatingCount> ratingCounts) {
this.ratingCount = new HashMap<Rating, Long>();
for (RatingCount ratingCount : ratingCounts) {
this.ratingCount.put(ratingCount.getRating(), ratingCount.getCount());
}
}
@Override
public long getNumberOfReviewsWithRating(Rating rating) {
Long count = this.ratingCount.get(rating);
return count == null ? 0 : count;
}
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import sample.hibernate52.domain.Hotel;
import sample.hibernate52.domain.Review;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
interface ReviewRepository extends Repository<Review, Long> {
Page<Review> findByHotel(Hotel hotel, Pageable pageable);
Review findByHotelAndIndex(Hotel hotel, int index);
Review save(Review review);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import sample.hibernate52.domain.Rating;
public interface ReviewsSummary {
long getNumberOfReviewsWithRating(Rating rating);
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.web;
import sample.hibernate52.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SampleController {
@Autowired
private CityService cityService;
@GetMapping("/")
@ResponseBody
@Transactional(readOnly = true)
public String helloWorld() {
return this.cityService.getCity("Bath", "UK").getName();
}
}
spring.h2.console.enabled=true
logging.level.org.hibernate.SQL=debug
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52;
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
import org.junit.Before;
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.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Integration test to run the application.
*
* @author Oliver Gierke
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@SpringBootTest
// Enable JMX so we can test the MBeans (you can't do this in a properties file)
@TestPropertySource(properties = { "spring.jmx.enabled:true",
"spring.datasource.jmx-enabled:true" })
@ActiveProfiles("scratch")
// Separate profile for web tests to avoid clashing databases
public class SampleHibernate52ApplicationTests {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
@Test
public void testHome() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(content().string("Bath"));
}
@Test
public void testJmx() throws Exception {
assertThat(ManagementFactory.getPlatformMBeanServer()
.queryMBeans(new ObjectName("jpa.sample:type=ConnectionPool,*"), null))
.hasSize(1);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import sample.hibernate52.domain.City;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link CityRepository}.
*
* @author Oliver Gierke
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CityRepositoryIntegrationTests {
@Autowired
CityRepository repository;
@Test
public void findsFirstPageOfCities() {
Page<City> cities = this.repository.findAll(new PageRequest(0, 10));
assertThat(cities.getTotalElements()).isGreaterThan(20L);
}
}
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.hibernate52.service;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import sample.hibernate52.domain.City;
import sample.hibernate52.domain.Hotel;
import sample.hibernate52.domain.HotelSummary;
import sample.hibernate52.domain.Rating;
import sample.hibernate52.domain.RatingCount;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link HotelRepository}.
*
* @author Oliver Gierke
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class HotelRepositoryIntegrationTests {
@Autowired
CityRepository cityRepository;
@Autowired
HotelRepository repository;
@Test
public void executesQueryMethodsCorrectly() {
City city = this.cityRepository
.findAll(new PageRequest(0, 1, Direction.ASC, "name")).getContent()
.get(0);
assertThat(city.getName()).isEqualTo("Atlanta");
Page<HotelSummary> hotels = this.repository.findByCity(city,
new PageRequest(0, 10, Direction.ASC, "name"));
Hotel hotel = this.repository.findByCityAndName(city,
hotels.getContent().get(0).getName());
assertThat(hotel.getName()).isEqualTo("Doubletree");
List<RatingCount> counts = this.repository.findRatingCounts(hotel);
assertThat(counts).hasSize(1);
assertThat(counts.get(0).getRating()).isEqualTo(Rating.AVERAGE);
assertThat(counts.get(0).getCount()).isGreaterThan(1L);
}
}
spring.datasource.name=scratchdb
spring.jmx.default-domain=jpa.sample
\ No newline at end of file
/*
* Copyright 2012-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.orm.jpa.hibernate;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.hibernate.internal.util.StringHelper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Hibernate {@link org.hibernate.cfg.NamingStrategy} that follows Spring recommended
* naming conventions. Naming conventions implemented here are identical to
* {@link ImprovedNamingStrategy} with the exception that foreign key columns include the
* referenced column name.
*
* @author Phillip Webb
* @see "http://stackoverflow.com/questions/7689206/ejb3namingstrategy-vs-improvednamingstrategy-foreign-key-naming"
* @since 1.2.0
*/
@SuppressWarnings("serial")
public class SpringNamingStrategy extends ImprovedNamingStrategy {
@Override
public String foreignKeyColumnName(String propertyName, String propertyEntityName,
String propertyTableName, String referencedColumnName) {
String name = propertyTableName;
if (propertyName != null) {
name = StringHelper.unqualify(propertyName);
}
Assert.state(StringUtils.hasLength(name),
"Unable to generate foreignKeyColumnName");
return columnName(name) + "_" + referencedColumnName;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment