DATAJDBC-455 - Polishing.

Rename Dialect bean to jdbcDialect to avoid generic bean names. Require JdbcOperations in DialectResolver. Rename JdbcDialectResolver to DialectResolver for consistent naming with R2DBC the underlying type is a Dialect.

Tweak Javadoc and extend documentation with custom conversions include from Spring Data Commons. Extract MySQL identifier processing defaults into constant.

Original pull request: #202.
This commit is contained in:
Mark Paluch
2020-03-26 11:07:50 +01:00
parent 1c4ff416c9
commit ef02b6e9cd
10 changed files with 157 additions and 93 deletions

View File

@@ -0,0 +1,66 @@
[[jdbc.custom-converters]]
== Custom Conversions
Spring Data JDBC allows registration of custom converters to influence how values are mapped in the database.
Currently, converters are only applied on property-level.
[[jdbc.custom-converters.writer]]
=== Writing a Property by Using a Registered Spring Converter
The following example shows an implementation of a `Converter` that converts from a `Boolean` object to a `String` value:
[source,java]
----
import org.springframework.core.convert.converter.Converter;
@WritingConverter
public class BooleanToStringConverter implements Converter<Boolean, String> {
@Override
public String convert(Boolean source) {
return source != null && source ? "T" : "F";
}
}
----
There are a couple of things to notice here: `Boolean` and `String` are both simple types hence Spring Data requires a hint in which direction this converter should apply (reading or writing).
By annotating this converter with `@WritingConverter` you instruct Spring Data to write every `Boolean` property as `String` in the database.
[[jdbc.custom-converters.reader]]
=== Reading by Using a Spring Converter
The following example shows an implementation of a `Converter` that converts from a `String` to a `Boolean` value:
[source,java]
----
@ReadingConverter
public class StringToBooleanConverter implements Converter<String, Boolean> {
@Override
public Boolean convert(String source) {
return source != null && source.equalsIgnoreCase("T") ? Boolean.TRUE : Boolean.FALSE;
}
}
----
There are a couple of things to notice here: `String` and `Boolean` are both simple types hence Spring Data requires a hint in which direction this converter should apply (reading or writing).
By annotating this converter with `@ReadingConverter` you instruct Spring Data to convert every `String` value from the database that should be assigned to a `Boolean` property.
[[jdbc.custom-converters.configuration]]
=== Registering Spring Converters with the `JdbcConverter`
[source,java]
----
class MyJdbcConfiguration extends AbstractJdbcConfiguration {
// …
@Overwrite
@Bean
public JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(Arrays.asList(new BooleanToStringConverter(), new StringToBooleanConverter()));
}
}
----
include::{spring-data-commons-docs}/custom-conversions.adoc[leveloffset=+3]

View File

@@ -67,29 +67,28 @@ The Spring Data JDBC repositories support can be activated by an annotation thro
.Spring Data JDBC repositories using Java configuration
====
[source, java]
[source,java]
----
@Configuration
@EnableJdbcRepositories // <1>
class ApplicationConfig extends AbstractJdbcConfiguration { // <2>
@EnableJdbcRepositories // <1>
class ApplicationConfig extends AbstractJdbcConfiguration { // <2>
@Bean
public DataSource dataSource() { // <3>
@Bean
public DataSource dataSource() { // <3>
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean
NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) { // <4>
@Bean
NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) { // <4>
return new NamedParameterJdbcTemplate(dataSource);
}
return new NamedParameterJdbcTemplate(dataSource);
}
@Bean
TransactionManager transactionManager(DataSource dataSource) { // <5>
return new DataSourceTransactionManager(dataSource);
}
@Bean
TransactionManager transactionManager(DataSource dataSource) { // <5>
return new DataSourceTransactionManager(dataSource);
}
}
----
<1> `@EnableJdbcRepositories` creates implementations for interfaces derived from `Repository`
@@ -101,7 +100,7 @@ class ApplicationConfig extends AbstractJdbcConfiguration { // <2>
The configuration class in the preceding example sets up an embedded HSQL database by using the `EmbeddedDatabaseBuilder` API of `spring-jdbc`.
The `DataSource` is then used to set up `NamedParameterJdbcOperations` and a `TransactionManager.
We finally activate Spring Data JDBC repositories by using the `@EnableJdbcRepositories`.
We finally activate Spring Data JDBC repositories by using the `@EnableJdbcRepositories`.
If no base package is configured, it uses the package in which the configuration class resides.
Extending `AbstractJdbcConfiguration` ensures various beans get registered.
Overwriting its methods can be used to customize the setup (see below).
@@ -110,49 +109,15 @@ This configuration can be further simplified by using Spring Boot.
With Spring Boot a `DataSource` is sufficient once the starter `spring-boot-starter-data-jdbc` is included in the dependencies.
Everything else is done by Spring Boot.
There are a couple of things one might want to customize in this setup
You can register custom conversions which will be used when writing to or reading from the database by overwriting `jdbcCustomConversions` as demonstrated in the following example:
====
[source, java]
----
@Overwrite
@Bean
public JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(new JdbcCustomConversions(Arrays.asList(BooleanToStringConverter.INSTANCE, StringToBooleanConverter.INSTANCE)));
}
@WritingConverter
enum BooleanToStringConverter implements Converter<Boolean, String> {
INSTANCE;
@Override
public String convert(Boolean source) {
return source != null && source ? "T" : "F";
}
}
@ReadingConverter
enum StringToBooleanConverter implements Converter<String, Boolean> {
INSTANCE;
@Override
public Boolean convert(String source) {
return source != null && source.equalsIgnoreCase("T") ? Boolean.TRUE : Boolean.FALSE;
}
}
----
====
There are a couple of things one might want to customize in this setup.
Spring Data JDBC uses implementations of the interface `Dialect` to encapsulate behavior that is specific to a database or its JDBC driver.
By default the `AbstractJdbcConfiguration` tries to determine the database in use an register the correct `Dialect`.
This behavior can be changed by overwriting `dialect(NamedParameterJdbcOperations)`.
This behavior can be changed by overwriting `jdbcDialect(NamedParameterJdbcOperations)`.
Database vendors may provide an implementation of `JdbcDialectProvider` along with a matching entry in the `META-INF/spring-factories` file registering it for the key `org.springframework.data.jdbc.repository.config.JdbcDialectResolver$JdbcDialectProvider`.
The `JdbcDialectProvider` should detect the database and provide an appropriate `Dialect` implementation for it.
TIP: Dialects are resolved by [`JdbcDialectResolver`] from `JdbcOperations`, typically by inspecting `Connection`.
+ You can let Spring auto-discover your `Dialect` by registering a class that implements `org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider` through `META-INF/spring.factories`.
`DialectResolver` discovers dialect provider implementations from the class path using Spring's `SpringFactoriesLoader`.
[[jdbc.entity-persistence]]
== Persisting Entities
@@ -759,6 +724,8 @@ Spring Data JDBC uses the `EntityCallback` API for its auditing support and reac
| After an aggregate root gets created from a database `ResultSet` and all its property get set.
|===
include::jdbc-custom-conversions.adoc[]
[[jdbc.logging]]
== Logging