Upgrade to Hibernate 5.1

Upgrade to Hibernate 5.1, whilst still retaining compatibility with
Hibernate 4.3. This commit introduces the following changes:

* Add SpringPhysicalNamingStrategy to provides lowercase/underscore
  table names support. This should be equivalent to the previous
  SpringNamingStrategy that was used with Hibernate 4. No
  ImplicitNamingStrategy is provided since the Hibernate 5 defaults
  appear to be roughly equivalent to the conventions used in Spring
  Boot 1.3
  spring.jpa.hibernate.naming.

* Migrate  `spring.jpa.hibernate.naming-strategy` to
  `spring.jpa.hibernate.naming.strategy` and provide additional
  properties for physical and implicit.

* Add `spring.jpa.hibernate.use-new-id-generator-mappings` property and
  default to `false` when on Hibernate 5 to retain back compatibility.

See gh-2763
pull/5535/merge
Phillip Webb 9 years ago
parent 7fc990a3cb
commit 0db1194007

@ -0,0 +1,54 @@
/*
* 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;
}
}

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,6 +23,7 @@ import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -31,6 +32,7 @@ import org.springframework.util.StringUtils;
* *
* @author Dave Syer * @author Dave Syer
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll
* @since 1.1.0 * @since 1.1.0
*/ */
@ConfigurationProperties(prefix = "spring.jpa") @ConfigurationProperties(prefix = "spring.jpa")
@ -125,12 +127,8 @@ public class JpaProperties {
public static class Hibernate { public static class Hibernate {
private static final String DEFAULT_NAMING_STRATEGY = "org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy"; private static final String USE_NEW_ID_GENERATOR_MAPPINGS = "hibernate.id."
+ "new_generator_mappings";
/**
* Naming strategy fully qualified name.
*/
private Class<?> namingStrategy;
/** /**
* DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto" * DDL mode. This is actually a shortcut for the "hibernate.hbm2ddl.auto"
@ -139,12 +137,25 @@ public class JpaProperties {
*/ */
private String ddlAuto; private String ddlAuto;
public Class<?> getNamingStrategy() { /**
return this.namingStrategy; * Use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. This is
* actually a shortcut for the "hibernate.id.new_generator_mappings" property.
* When not specified will default to "false" with Hibernate 5 for back
* compatibility.
*/
private Boolean useNewIdGeneratorMappings;
private final Naming naming = new Naming();
@Deprecated
@DeprecatedConfigurationProperty(replacement = "spring.jpa.hibernate.naming.strategy")
public String getNamingStrategy() {
return getNaming().getStrategy();
} }
public void setNamingStrategy(Class<?> namingStrategy) { @Deprecated
this.namingStrategy = namingStrategy; public void setNamingStrategy(String namingStrategy) {
getNaming().setStrategy(namingStrategy);
} }
public String getDdlAuto() { public String getDdlAuto() {
@ -155,13 +166,23 @@ public class JpaProperties {
this.ddlAuto = ddlAuto; this.ddlAuto = ddlAuto;
} }
public boolean isUseNewIdGeneratorMappings() {
return this.useNewIdGeneratorMappings;
}
public void setUseNewIdGeneratorMappings(boolean useNewIdGeneratorMappings) {
this.useNewIdGeneratorMappings = useNewIdGeneratorMappings;
}
public Naming getNaming() {
return this.naming;
}
private Map<String, String> getAdditionalProperties(Map<String, String> existing, private Map<String, String> getAdditionalProperties(Map<String, String> existing,
DataSource dataSource) { DataSource dataSource) {
Map<String, String> result = new HashMap<String, String>(existing); Map<String, String> result = new HashMap<String, String>(existing);
if (!existing.containsKey("hibernate." + "ejb.naming_strategy_delegator")) { applyNewIdGeneratorMappings(result);
result.put("hibernate.ejb.naming_strategy", getNaming().applyNamingStrategy(result);
getHibernateNamingStrategy(existing));
}
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);
@ -172,12 +193,15 @@ public class JpaProperties {
return result; return result;
} }
private String getHibernateNamingStrategy(Map<String, String> existing) { private void applyNewIdGeneratorMappings(Map<String, String> result) {
if (!existing.containsKey("hibernate." + "ejb.naming_strategy") if (this.useNewIdGeneratorMappings != null) {
&& this.namingStrategy != null) { result.put(USE_NEW_ID_GENERATOR_MAPPINGS,
return this.namingStrategy.getName(); this.useNewIdGeneratorMappings.toString());
}
else if (HibernateVersion.getRunning() == HibernateVersion.V5
&& !result.containsKey(USE_NEW_ID_GENERATOR_MAPPINGS)) {
result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "false");
} }
return DEFAULT_NAMING_STRATEGY;
} }
private String getOrDeduceDdlAuto(Map<String, String> existing, private String getOrDeduceDdlAuto(Map<String, String> existing,
@ -203,4 +227,96 @@ public class JpaProperties {
} }
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";
/**
* Hibernate 5 implicit naming strategy fully qualified name.
*/
private String implicitStrategy;
/**
* Hibernate 5 physical naming strategy fully qualified name.
*/
private String physicalStrategy;
/**
* Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate
* 5.
*/
private String strategy;
public String getImplicitStrategy() {
return this.implicitStrategy;
}
public void setImplicitStrategy(String implicitStrategy) {
this.implicitStrategy = implicitStrategy;
}
public String getPhysicalStrategy() {
return this.physicalStrategy;
}
public void setPhysicalStrategy(String physicalStrategy) {
this.physicalStrategy = physicalStrategy;
}
public String getStrategy() {
return this.strategy;
}
public void setStrategy(String 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) {
applyHibernate5NamingStrategy(properties,
"hibernate.implicit_naming_strategy", this.implicitStrategy, null);
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) {
properties.put(key, strategy);
}
else if (defaultStrategy != null && !properties.containsKey(key)) {
properties.put(key, defaultStrategy);
}
}
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;
}
}
} }

@ -447,7 +447,29 @@
] ]
}, },
{ {
"name": "spring.jpa.hibernate.naming-strategy", "name": "spring.jpa.hibernate.naming.implicit-strategy",
"providers": [
{
"name": "class-reference",
"parameters": {
"target": "org.hibernate.boot.model.naming.ImplicitNamingStrategy"
}
}
]
},
{
"name": "spring.jpa.hibernate.naming.physical-strategy",
"providers": [
{
"name": "class-reference",
"parameters": {
"target": "org.hibernate.boot.model.naming.PhysicalNamingStrategy"
}
}
]
},
{
"name": "spring.jpa.hibernate.naming.strategy",
"providers": [ "providers": [
{ {
"name": "class-reference", "name": "class-reference",

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -26,6 +26,7 @@ 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.Test; import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
@ -49,6 +50,11 @@ import static org.assertj.core.api.Assertions.assertThat;
public class HibernateJpaAutoConfigurationTests public class HibernateJpaAutoConfigurationTests
extends AbstractJpaAutoConfigurationTests { extends AbstractJpaAutoConfigurationTests {
@After
public void cleanup() {
HibernateVersion.setRunning(null);
}
@Override @Override
protected Class<?> getAutoConfigureClass() { protected Class<?> getAutoConfigureClass() {
return HibernateJpaAutoConfiguration.class; return HibernateJpaAutoConfiguration.class;
@ -80,6 +86,7 @@ public class HibernateJpaAutoConfigurationTests
@Test @Test
public void testCustomNamingStrategy() throws Exception { public void testCustomNamingStrategy() throws Exception {
HibernateVersion.setRunning(HibernateVersion.V4);
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.jpa.hibernate.namingStrategy:" "spring.jpa.hibernate.namingStrategy:"
+ "org.hibernate.cfg.EJB3NamingStrategy"); + "org.hibernate.cfg.EJB3NamingStrategy");
@ -94,6 +101,7 @@ public class HibernateJpaAutoConfigurationTests
@Test @Test
public void testCustomNamingStrategyViaJpaProperties() throws Exception { public void testCustomNamingStrategyViaJpaProperties() throws Exception {
HibernateVersion.setRunning(HibernateVersion.V4);
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.jpa.properties.hibernate.ejb.naming_strategy:" "spring.jpa.properties.hibernate.ejb.naming_strategy:"
+ "org.hibernate.cfg.EJB3NamingStrategy"); + "org.hibernate.cfg.EJB3NamingStrategy");

@ -0,0 +1,176 @@
/*
* 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 java.sql.SQLException;
import java.util.Map;
import javax.sql.DataSource;
import org.hibernate.cfg.AvailableSettings;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link JpaProperties}.
*
* @author Stephane Nicoll
*/
public class JpaPropertiesTests {
private AnnotationConfigApplicationContext context;
@After
public void close() {
HibernateVersion.setRunning(null);
if (this.context != null) {
this.context.close();
}
}
@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
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties).doesNotContainKeys(
"hibernate.ejb.naming_strategy", "hibernate.implicit_naming_strategy");
assertThat(hibernateProperties).containsEntry(
"hibernate.physical_naming_strategy",
SpringPhysicalNamingStrategy.class.getName());
}
@Test
public void hibernate5CustomNamingStrategies() throws Exception {
JpaProperties properties = load(HibernateVersion.V5,
"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit",
"spring.jpa.hibernate.naming.physical-strategy:com.example.Physical");
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties).contains(
entry("hibernate.implicit_naming_strategy", "com.example.Implicit"),
entry("hibernate.physical_naming_strategy", "com.example.Physical"));
assertThat(hibernateProperties)
.doesNotContainKeys("hibernate.ejb.naming_strategy");
}
@Test
public void hibernate5CustomNamingStrategiesViaJpaProperties() throws Exception {
JpaProperties properties = load(HibernateVersion.V5,
"spring.jpa.properties.hibernate.implicit_naming_strategy:com.example.Implicit",
"spring.jpa.properties.hibernate.physical_naming_strategy:com.example.Physical");
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
// You can override them as we don't provide any default
assertThat(hibernateProperties).contains(
entry("hibernate.implicit_naming_strategy", "com.example.Implicit"),
entry("hibernate.physical_naming_strategy", "com.example.Physical"));
assertThat(hibernateProperties)
.doesNotContainKeys("hibernate.ejb.naming_strategy");
}
@Test
public void useNewIdGeneratorMappingsDefaultHibernate4() throws Exception {
JpaProperties properties = load(HibernateVersion.V4);
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
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties)
.containsEntry(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "false");
}
@Test
public void useNewIdGeneratorMappingsTrue() throws Exception {
JpaProperties properties = load(HibernateVersion.V5,
"spring.jpa.hibernate.use-new-id-generator-mappings:true");
Map<String, String> hibernateProperties = properties
.getHibernateProperties(mockStandaloneDataSource());
assertThat(hibernateProperties)
.containsEntry(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true");
}
@SuppressWarnings("unchecked")
private DataSource mockStandaloneDataSource() throws SQLException {
DataSource ds = mock(DataSource.class);
given(ds.getConnection()).willThrow(SQLException.class);
return ds;
}
private JpaProperties load(HibernateVersion hibernateVersion, String... environment) {
HibernateVersion.setRunning(hibernateVersion);
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment);
ctx.register(TestConfiguration.class);
ctx.refresh();
this.context = ctx;
JpaProperties properties = this.context.getBean(JpaProperties.class);
return properties;
}
@Configuration
@EnableConfigurationProperties(JpaProperties.class)
static class TestConfiguration {
}
}

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2013 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -65,6 +65,7 @@
<couchbase-cache-client.version>2.0.0</couchbase-cache-client.version> <couchbase-cache-client.version>2.0.0</couchbase-cache-client.version>
<crashub.version>1.3.2</crashub.version> <crashub.version>1.3.2</crashub.version>
<derby.version>10.12.1.1</derby.version> <derby.version>10.12.1.1</derby.version>
<dom4j.version>1.6.1</dom4j.version>
<dropwizard-metrics.version>3.1.2</dropwizard-metrics.version> <dropwizard-metrics.version>3.1.2</dropwizard-metrics.version>
<ehcache.version>2.10.1</ehcache.version> <ehcache.version>2.10.1</ehcache.version>
<embedded-mongo.version>1.50.2</embedded-mongo.version> <embedded-mongo.version>1.50.2</embedded-mongo.version>
@ -79,7 +80,7 @@
<h2.version>1.4.191</h2.version> <h2.version>1.4.191</h2.version>
<hamcrest.version>1.3</hamcrest.version> <hamcrest.version>1.3</hamcrest.version>
<hazelcast.version>3.6.1</hazelcast.version> <hazelcast.version>3.6.1</hazelcast.version>
<hibernate.version>4.3.11.Final</hibernate.version> <hibernate.version>5.1.0.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.5</hikaricp.version> <hikaricp.version>2.4.5</hikaricp.version>
<hikaricp-java6.version>2.3.13</hikaricp-java6.version> <hikaricp-java6.version>2.3.13</hikaricp-java6.version>
@ -806,6 +807,11 @@
<artifactId>de.flapdoodle.embed.mongo</artifactId> <artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>${embedded-mongo.version}</version> <version>${embedded-mongo.version}</version>
</dependency> </dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
<dependency> <dependency>
<groupId>io.dropwizard.metrics</groupId> <groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId> <artifactId>metrics-core</artifactId>

@ -16,7 +16,9 @@
package org.springframework.boot.orm.jpa.hibernate; package org.springframework.boot.orm.jpa.hibernate;
import org.hibernate.Hibernate;
import org.hibernate.cfg.ImprovedNamingStrategy; import org.hibernate.cfg.ImprovedNamingStrategy;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -31,7 +33,10 @@ import org.springframework.util.StringUtils;
* @author Phillip Webb * @author Phillip Webb
* @see "http://stackoverflow.com/questions/7689206/ejb3namingstrategy-vs-improvednamingstrategy-foreign-key-naming" * @see "http://stackoverflow.com/questions/7689206/ejb3namingstrategy-vs-improvednamingstrategy-foreign-key-naming"
* @since 1.2.0 * @since 1.2.0
* @deprecated since 1.4.0 since {@link NamingStrategy} is no longer used by
* {@link Hibernate}. Consider using {@link SpringPhysicalNamingStrategy}
*/ */
@Deprecated
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class SpringNamingStrategy extends ImprovedNamingStrategy { public class SpringNamingStrategy extends ImprovedNamingStrategy {

@ -0,0 +1,82 @@
/*
* 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 java.util.Locale;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
/**
* Hibernate {@link PhysicalNamingStrategy} that follows Spring recommended naming
* conventions.
*
* @author Phillip Webb
* @since 1.4.0
*/
public class SpringPhysicalNamingStrategy implements PhysicalNamingStrategy {
@Override
public Identifier toPhysicalCatalogName(Identifier name,
JdbcEnvironment jdbcEnvironment) {
return apply(name);
}
@Override
public Identifier toPhysicalSchemaName(Identifier name,
JdbcEnvironment jdbcEnvironment) {
return apply(name);
}
@Override
public Identifier toPhysicalTableName(Identifier name,
JdbcEnvironment jdbcEnvironment) {
return apply(name);
}
@Override
public Identifier toPhysicalSequenceName(Identifier name,
JdbcEnvironment jdbcEnvironment) {
return apply(name);
}
@Override
public Identifier toPhysicalColumnName(Identifier name,
JdbcEnvironment jdbcEnvironment) {
return apply(name);
}
private Identifier apply(Identifier name) {
if (name == null) {
return null;
}
StringBuilder text = new StringBuilder(name.getText().replace('.', '_'));
for (int i = 1; i < text.length() - 1; i++) {
if (isDashRequired(text.charAt(i - 1), text.charAt(i), text.charAt(i + 1))) {
text.insert(i++, '_');
}
}
return new Identifier(text.toString().toLowerCase(Locale.ROOT), name.isQuoted());
}
private boolean isDashRequired(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current)
&& Character.isLowerCase(after);
}
}

@ -0,0 +1,64 @@
/*
* 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.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.service.ServiceRegistry;
import org.junit.Before;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link SpringPhysicalNamingStrategy}.
*
* @author Phillip Webb
*/
public class SpringPhysicalNamingStrategyTests {
private Metadata metadata;
@Before
public void setup() throws Exception {
MetadataSources metadataSources = new MetadataSources();
metadataSources.addAnnotatedClass(TelephoneNumber.class);
StandardServiceRegistry serviceRegistry = getServiceRegistry(metadataSources);
this.metadata = metadataSources.getMetadataBuilder(serviceRegistry)
.applyPhysicalNamingStrategy(new SpringPhysicalNamingStrategy()).build();
}
private StandardServiceRegistry getServiceRegistry(MetadataSources metadataSources) {
ServiceRegistry registry = metadataSources.getServiceRegistry();
return new StandardServiceRegistryBuilder((BootstrapServiceRegistry) registry)
.applySetting(AvailableSettings.DIALECT, H2Dialect.class).build();
}
@Test
public void tableNameShouldBeLowercaseUnderscore() throws Exception {
PersistentClass binding = this.metadata
.getEntityBinding(TelephoneNumber.class.getName());
assertThat(binding.getTable().getQuotedName()).isEqualTo("telephone_number");
}
}

@ -0,0 +1,39 @@
/*
* 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 javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* Simple entity used in {@link SpringPhysicalNamingStrategyTests}.
*
* @author Phillip Webb
*/
@Entity
public class TelephoneNumber {
@Id
@GeneratedValue
Long id;
String areaCode;
String number;
}
Loading…
Cancel
Save