Commit fe89af5e authored by Stephane Nicoll's avatar Stephane Nicoll

Polish contribution

Closes gh-7796
parent 24c83d12
...@@ -23,9 +23,8 @@ import org.springframework.orm.jpa.vendor.Database; ...@@ -23,9 +23,8 @@ import org.springframework.orm.jpa.vendor.Database;
* Mapper between {@link Database} and {@link DatabaseDriver}. * Mapper between {@link Database} and {@link DatabaseDriver}.
* *
* @author Eddú Meléndez * @author Eddú Meléndez
* @version 1.5.0
*/ */
public enum DatabasePlatform { enum DatabasePlatform {
DB2(Database.DB2, DatabaseDriver.DB2), DB2(Database.DB2, DatabaseDriver.DB2),
......
...@@ -41,8 +41,6 @@ import org.springframework.context.annotation.Bean; ...@@ -41,8 +41,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
...@@ -104,14 +102,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { ...@@ -104,14 +102,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
public JpaVendorAdapter jpaVendorAdapter() { public JpaVendorAdapter jpaVendorAdapter() {
AbstractJpaVendorAdapter adapter = createJpaVendorAdapter(); AbstractJpaVendorAdapter adapter = createJpaVendorAdapter();
adapter.setShowSql(this.properties.isShowSql()); adapter.setShowSql(this.properties.isShowSql());
try { adapter.setDatabase(this.properties.determineDatabase(this.dataSource));
String jdbcUrl = (String) JdbcUtils.extractDatabaseMetaData(this.dataSource,
"getURL");
adapter.setDatabase(this.properties.determineDatabase(jdbcUrl));
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
adapter.setDatabasePlatform(this.properties.getDatabasePlatform()); adapter.setDatabasePlatform(this.properties.getDatabasePlatform());
adapter.setGenerateDdl(this.properties.isGenerateDdl()); adapter.setGenerateDdl(this.properties.isGenerateDdl());
return adapter; return adapter;
......
...@@ -21,10 +21,15 @@ import java.util.Map; ...@@ -21,10 +21,15 @@ import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.NestedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -40,6 +45,8 @@ import org.springframework.util.StringUtils; ...@@ -40,6 +45,8 @@ import org.springframework.util.StringUtils;
@ConfigurationProperties(prefix = "spring.jpa") @ConfigurationProperties(prefix = "spring.jpa")
public class JpaProperties { public class JpaProperties {
private static final Log logger = LogFactory.getLog(JpaProperties.class);
/** /**
* Additional native properties to set on the JPA provider. * Additional native properties to set on the JPA provider.
*/ */
...@@ -55,7 +62,7 @@ public class JpaProperties { ...@@ -55,7 +62,7 @@ public class JpaProperties {
* Target database to operate on, auto-detected by default. Can be alternatively set * Target database to operate on, auto-detected by default. Can be alternatively set
* using the "databasePlatform" property. * using the "databasePlatform" property.
*/ */
private Database database = Database.DEFAULT; private Database database;
/** /**
* Initialize the schema on startup. * Initialize the schema on startup.
...@@ -128,17 +135,28 @@ public class JpaProperties { ...@@ -128,17 +135,28 @@ public class JpaProperties {
} }
/** /**
* Return the database form the jdbc url or the value for `spring.jpa.database`. * Determine the {@link Database} to use based on this configuration and the primary
* @param jdbcUrl the url from `spring.datasource.url` * {@link DataSource}.
* @param dataSource the auto-configured data source
* @return {@code Database} * @return {@code Database}
*/ */
public Database determineDatabase(String jdbcUrl) { public Database determineDatabase(DataSource dataSource) {
if (this.database != null) {
return this.database;
}
try {
String jdbcUrl = (String) JdbcUtils.extractDatabaseMetaData(dataSource,
"getURL");
DatabasePlatform databasePlatform = DatabasePlatform.fromDatabaseDriver( DatabasePlatform databasePlatform = DatabasePlatform.fromDatabaseDriver(
DatabaseDriver.fromJdbcUrl(jdbcUrl)); DatabaseDriver.fromJdbcUrl(jdbcUrl));
if (databasePlatform != null) { if (databasePlatform != null) {
return databasePlatform.getDatabase(); return databasePlatform.getDatabase();
} }
return this.database; }
catch (MetaDataAccessException ex) {
logger.warn("Unable to determine jdbc url from datasource", ex);
}
return Database.DEFAULT;
} }
public static class Hibernate { public static class Hibernate {
......
...@@ -64,10 +64,10 @@ public class CustomHibernateJpaAutoConfigurationTests { ...@@ -64,10 +64,10 @@ public class CustomHibernateJpaAutoConfigurationTests {
// Set up environment so we get a MySQL database but don't require server to be // Set up environment so we get a MySQL database but don't require server to be
// running... // running...
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.driverClassName:com.mysql.jdbc.Driver", "spring.datasource.database:mysql",
"spring.datasource.url:jdbc:mysql://localhost/nonexistent", "spring.datasource.url:jdbc:mysql://localhost/nonexistent",
"spring.datasource.initialize:false", "spring.jpa.database:MYSQL"); "spring.datasource.initialize:false", "spring.jpa.database:MYSQL");
this.context.register(TestConfiguration.class, MockDataSourceConfiguration.class, this.context.register(TestConfiguration.class, DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
HibernateJpaAutoConfiguration.class); HibernateJpaAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
...@@ -114,7 +114,6 @@ public class CustomHibernateJpaAutoConfigurationTests { ...@@ -114,7 +114,6 @@ public class CustomHibernateJpaAutoConfigurationTests {
@Test @Test
public void testDefaultDatabaseForH2() throws Exception { public void testDefaultDatabaseForH2() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.driverClassName:org.h2.Driver",
"spring.datasource.url:jdbc:h2:mem:testdb", "spring.datasource.url:jdbc:h2:mem:testdb",
"spring.datasource.initialize:false"); "spring.datasource.initialize:false");
this.context.register(TestConfiguration.class, DataSourceAutoConfiguration.class, this.context.register(TestConfiguration.class, DataSourceAutoConfiguration.class,
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.orm.jpa; package org.springframework.boot.autoconfigure.orm.jpa;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
...@@ -38,6 +40,8 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -38,6 +40,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.Assertions.entry;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/** /**
* Tests for {@link JpaProperties}. * Tests for {@link JpaProperties}.
...@@ -168,16 +172,36 @@ public class JpaPropertiesTests { ...@@ -168,16 +172,36 @@ public class JpaPropertiesTests {
} }
@Test @Test
public void determineH2DatabaseWhenJdbcUrlIsProvided() { public void determineDatabaseNoCheckIfDatabaseIsSet() throws SQLException {
JpaProperties properties = load(HibernateVersion.V5,
"spring.jpa.database=postgresql");
DataSource dataSource = mockStandaloneDataSource();
Database database = properties.determineDatabase(dataSource);
assertThat(database).isEqualTo(Database.POSTGRESQL);
verify(dataSource, never()).getConnection();
}
@Test
public void determineDatabaseWithKnownUrl() {
JpaProperties properties = load(HibernateVersion.V5); JpaProperties properties = load(HibernateVersion.V5);
Database database = properties.determineDatabase("jdbc:h2:mem:testdb"); Database database = properties.determineDatabase(
mockDataSource("jdbc:h2:mem:testdb"));
assertThat(database).isEqualTo(Database.H2); assertThat(database).isEqualTo(Database.H2);
} }
@Test @Test
public void determineDefaultDatabaseWhenJdbcUrlIsProvided() { public void determineDatabaseWithKnownUrlAndUserConfig() {
JpaProperties properties = load(HibernateVersion.V5, "spring.jpa.database=mysql");
Database database = properties.determineDatabase(
mockDataSource("jdbc:h2:mem:testdb"));
assertThat(database).isEqualTo(Database.MYSQL);
}
@Test
public void determineDatabaseWithUnknownUrl() {
JpaProperties properties = load(HibernateVersion.V5); JpaProperties properties = load(HibernateVersion.V5);
Database database = properties.determineDatabase("jdbc:unknown://localhost"); Database database = properties.determineDatabase(
mockDataSource("jdbc:unknown://localhost"));
assertThat(database).isEqualTo(Database.DEFAULT); assertThat(database).isEqualTo(Database.DEFAULT);
} }
...@@ -188,6 +212,21 @@ public class JpaPropertiesTests { ...@@ -188,6 +212,21 @@ public class JpaPropertiesTests {
return ds; return ds;
} }
private DataSource mockDataSource(String jdbcUrl) {
DataSource ds = mock(DataSource.class);
try {
DatabaseMetaData metadata = mock(DatabaseMetaData.class);
given(metadata.getURL()).willReturn(jdbcUrl);
Connection connection = mock(Connection.class);
given(connection.getMetaData()).willReturn(metadata);
given(ds.getConnection()).willReturn(connection);
}
catch (SQLException e) {
//Do nothing
}
return ds;
}
private JpaProperties load(HibernateVersion hibernateVersion, String... environment) { private JpaProperties load(HibernateVersion hibernateVersion, String... environment) {
HibernateVersion.setRunning(hibernateVersion); HibernateVersion.setRunning(hibernateVersion);
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
......
...@@ -1797,20 +1797,25 @@ annotation, e.g. ...@@ -1797,20 +1797,25 @@ annotation, e.g.
=== Configure JPA properties === Configure JPA properties
Spring Data JPA already provides some vendor-independent configuration options (e.g. Spring Data JPA already provides some vendor-independent configuration options (e.g.
for SQL logging) and Spring Boot exposes those, and a few more for hibernate as external for SQL logging) and Spring Boot exposes those, and a few more for hibernate as external
configuration properties. The most common options to set are: configuration properties. Some of them are automatically detected according to the context
so you shouldn't have to set them.
The `spring.jpa.hibernate.ddl-auto` is a special case in that it has different defaults
depending on whether you are using an embedded database (`create-drop`) or not (`none`).
The dialect to use is also automatically detected based on the current `DataSource` but
you can set `spring.jpa.database` yourself if you want to be explicit and bypass that
check on startup.
The most common options to set are:
[indent=0,subs="verbatim,quotes,attributes"] [indent=0,subs="verbatim,quotes,attributes"]
---- ----
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.database=H2
spring.jpa.show-sql=true spring.jpa.show-sql=true
---- ----
The `ddl-auto` setting is a special case in that it has different defaults depending on In addition all properties in `+spring.jpa.properties.*+` are passed through as normal JPA
whether you are using an embedded database (`create-drop`) or not (`none`). In addition properties (with the prefix stripped) when the local `EntityManagerFactory` is created.
all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties
(with the prefix stripped) when the local `EntityManagerFactory` is created.
Spring Boot provides a consistent naming strategy regardless of the Hibernate generation Spring Boot provides a consistent naming strategy regardless of the Hibernate generation
that you are using. If you are using Hibernate 4, you can customize it using that you are using. If you are using Hibernate 4, you can customize it using
......
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