DATAMONGO-2400 - Polishing.

Adapt to changes in commons. Add functional create method to MongoCustomConversions. Update Javadoc and reference documentation. Truncate precision for Java 11 build compatibility in tests.

Original pull request: #810.
This commit is contained in:
Mark Paluch
2020-02-07 12:32:38 +01:00
parent 3b6880edfd
commit e9d14f41a5
5 changed files with 72 additions and 52 deletions

View File

@@ -95,15 +95,16 @@ public abstract class MongoConfigurationSupport {
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
* {@link CustomConversions} will be registered with the
* {@link org.springframework.data.mongodb.core.convert.MappingMongoConverter} and {@link #mongoMappingContext()}.
* Returns an empty {@link MongoCustomConversions} instance by default. <br />
* <strong>NOTE:</strong> Use {@link #customConversionsConfiguration(MongoConverterConfigurationAdapter)} to configure
* MongoDB native simple types and register custom {@link Converter converters}.
* Returns an empty {@link MongoCustomConversions} instance by default.
* <p>
* <strong>NOTE:</strong> Use {@link #configureConverters(MongoConverterConfigurationAdapter)} to configure MongoDB
* native simple types and register custom {@link Converter converters}.
*
* @return must not be {@literal null}.
*/
@Bean
public CustomConversions customConversions() {
return new MongoCustomConversions(this::customConversionsConfiguration);
return MongoCustomConversions.create(this::configureConverters);
}
/**
@@ -111,17 +112,11 @@ public abstract class MongoConfigurationSupport {
*
* @param converterConfigurationAdapter never {@literal null}.
* @since 2.3
* @see MongoConverterConfigurationAdapter#useNativeDriverJavaTimeCodecs()
* @see MongoConverterConfigurationAdapter#useSpringDataJavaTimeCodecs()
*/
protected void customConversionsConfiguration(MongoConverterConfigurationAdapter converterConfigurationAdapter) {
protected void configureConverters(MongoConverterConfigurationAdapter converterConfigurationAdapter) {
/*
* In case you want to use the MongoDB Java Driver native Codecs for java.time types instead of the converters SpringData
* ships with, then you may want to call the following here.
*
* converterConfigurationAdapter.useNativeDriverJavaTimeCodecs()
*
* But please, be careful! LocalDate, LocalTime and LocalDateTime will be stored with different values by doing so.
*/
}
/**

View File

@@ -31,13 +31,11 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
import org.springframework.data.convert.JodaTimeConverters;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mapping.model.SimpleTypeHolder;
@@ -87,12 +85,17 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
* @param converters must not be {@literal null}.
*/
public MongoCustomConversions(List<?> converters) {
this(MongoConverterConfigurationAdapter.from(converters));
}
this(converterConfigurationAdapter -> {
converterConfigurationAdapter.useSpringDataJavaTimeCodecs();
converterConfigurationAdapter.registerConverters(converters);
});
/**
* Create a new {@link MongoCustomConversions} given {@link MongoConverterConfigurationAdapter}.
*
* @param conversionConfiguration must not be {@literal null}.
* @since 2.3
*/
protected MongoCustomConversions(MongoConverterConfigurationAdapter conversionConfiguration) {
super(conversionConfiguration.createConverterConfiguration());
}
/**
@@ -100,17 +103,15 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
* of configuring store specific capabilities by providing deferred hooks to what will be configured when creating the
* {@link org.springframework.data.convert.CustomConversions#CustomConversions(ConverterConfiguration) instance}.
*
* @param conversionConfiguration must not be {@literal null}.
* @param configurer must not be {@literal null}.
* @since 2.3
*/
public MongoCustomConversions(Consumer<MongoConverterConfigurationAdapter> conversionConfiguration) {
public static MongoCustomConversions create(Consumer<MongoConverterConfigurationAdapter> configurer) {
super(() -> {
MongoConverterConfigurationAdapter adapter = new MongoConverterConfigurationAdapter();
configurer.accept(adapter);
MongoConverterConfigurationAdapter adapter = new MongoConverterConfigurationAdapter();
conversionConfiguration.accept(adapter);
return adapter.createConverterConfiguration();
});
return new MongoCustomConversions(adapter);
}
@WritingConverter
@@ -152,14 +153,32 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
* List of {@literal java.time} types having different representation when rendered via the native
* {@link org.bson.codecs.Codec} than the Spring Data {@link Converter}.
*/
private static final List<Class<?>> JAVA_DRIVER_TIME_SIMPLE_TYPES = Arrays.asList(LocalDate.class, LocalTime.class,
LocalDateTime.class);
private static final Set<Class<?>> JAVA_DRIVER_TIME_SIMPLE_TYPES = new HashSet<>(
Arrays.asList(LocalDate.class, LocalTime.class, LocalDateTime.class));
private boolean useNativeDriverJavaTimeCodecs = false;
private List<Object> customConverters = new ArrayList<>();
private final List<Object> customConverters = new ArrayList<>();
/**
* Set wether or not to use the native MongoDB Java Driver {@link org.bson.codecs.Codec codes} for
* Create a {@link MongoConverterConfigurationAdapter} using the provided {@code converters} and our own codecs for
* JSR-310 types.
*
* @param converters must not be {@literal null}.
* @return
*/
public static MongoConverterConfigurationAdapter from(List<?> converters) {
Assert.notNull(converters, "Converters must not be null");
MongoConverterConfigurationAdapter converterConfigurationAdapter = new MongoConverterConfigurationAdapter();
converterConfigurationAdapter.useSpringDataJavaTimeCodecs();
converterConfigurationAdapter.registerConverters(converters);
return converterConfigurationAdapter;
}
/**
* Set whether or not to use the native MongoDB Java Driver {@link org.bson.codecs.Codec codes} for
* {@link org.bson.codecs.jsr310.LocalDateCodec LocalDate}, {@link org.bson.codecs.jsr310.LocalTimeCodec LocalTime}
* and {@link org.bson.codecs.jsr310.LocalDateTimeCodec LocalDateTime} using a {@link ZoneOffset#UTC}.
*
@@ -232,7 +251,9 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
*/
public MongoConverterConfigurationAdapter registerConverters(Collection<?> converters) {
Assert.notNull(converters, "Converters must not be null");
Assert.noNullElements(converters, "Converters must not be null nor contain null values!");
customConverters.addAll(converters);
return this;
}
@@ -246,23 +267,26 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus
/*
* We need to have those converters using UTC as the default ones would go on with the systemDefault.
*/
List<Object> converters = new ArrayList<>();
List<Object> converters = new ArrayList<>(STORE_CONVERTERS.size() + 3);
converters.add(DateToUtcLocalDateConverter.INSTANCE);
converters.add(DateToUtcLocalTimeConverter.INSTANCE);
converters.add(DateToUtcLocalDateTimeConverter.INSTANCE);
converters.addAll(STORE_CONVERTERS);
/*
* Right, good catch! We also need to make sure to remove default writing converters for java.time types.
*/
List<ConvertiblePair> skipConverterRegistrationFor = JAVA_DRIVER_TIME_SIMPLE_TYPES.stream() //
.map(it -> new ConvertiblePair(it, Date.class)) //
.collect(Collectors.toList()); //
StoreConversions storeConversions = StoreConversions
.of(new SimpleTypeHolder(new HashSet<>(JAVA_DRIVER_TIME_SIMPLE_TYPES), MongoSimpleTypes.HOLDER), converters);
.of(new SimpleTypeHolder(JAVA_DRIVER_TIME_SIMPLE_TYPES, MongoSimpleTypes.HOLDER), converters);
return new ConverterConfiguration(storeConversions, this.customConverters, skipConverterRegistrationFor);
return new ConverterConfiguration(storeConversions, this.customConverters, convertiblePair -> {
// Avoid default registrations
if (JAVA_DRIVER_TIME_SIMPLE_TYPES.contains(convertiblePair.getSourceType())
&& Date.class.isAssignableFrom(convertiblePair.getTargetType())) {
return false;
}
return true;
});
}
private enum DateToUtcLocalDateTimeConverter implements Converter<Date, LocalDateTime> {

View File

@@ -29,6 +29,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
@@ -39,6 +40,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.test.util.Client;
@@ -125,7 +127,7 @@ public class MappingMongoConverterTests {
configureConverterWithNativeJavaTimeCodec();
MongoCollection<Document> mongoCollection = client.getDatabase(DATABASE).getCollection("java-time-types");
Instant now = Instant.now();
Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
WithJavaTimeTypes source = WithJavaTimeTypes.withJavaTimeTypes(now);
source.id = "id-1";
@@ -138,9 +140,8 @@ public class MappingMongoConverterTests {
void configureConverterWithNativeJavaTimeCodec() {
converter = new MappingMongoConverter(dbRefResolver, mappingContext);
converter.setCustomConversions(new MongoCustomConversions(config -> {
config.useNativeDriverJavaTimeCodecs();
}));
converter.setCustomConversions(
MongoCustomConversions.create(MongoConverterConfigurationAdapter::useNativeDriverJavaTimeCodecs));
converter.afterPropertiesSet();
}

View File

@@ -1087,9 +1087,9 @@ public class MappingMongoConverterUnitTests {
void configureConverterWithNativeJavaTimeCodec() {
converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(new MongoCustomConversions(config -> {
config.useNativeDriverJavaTimeCodecs();
}));
converter.setCustomConversions(MongoCustomConversions
.create(MongoCustomConversions.MongoConverterConfigurationAdapter::useNativeDriverJavaTimeCodecs));
converter.afterPropertiesSet();
}

View File

@@ -1,3 +1,4 @@
[[mapping-chapter]]
= Mapping
@@ -290,10 +291,8 @@ public class GeoSpatialAppConfig extends AbstractMongoClientConfiguration {
return "com.bigbank.domain";
}
// the following are optional
@Override
void customConversionsConfiguration(MongoConverterConfigurationAdapter adapter) {
void configureConverters(MongoConverterConfigurationAdapter adapter) {
adapter.registerConverter(new org.springframework.data.mongodb.test.PersonReadConverter());
adapter.registerConverter(new org.springframework.data.mongodb.test.PersonWriteConverter());
@@ -310,11 +309,12 @@ public class GeoSpatialAppConfig extends AbstractMongoClientConfiguration {
`AbstractMongoClientConfiguration` requires you to implement methods that define a `com.mongodb.client.MongoClient` as well as provide a database name. `AbstractMongoClientConfiguration` also has a method named `getMappingBasePackage(…)` that you can override to tell the converter where to scan for classes annotated with the `@Document` annotation.
You can add additional converters to the converter by overriding the `customConversionsConfiguration` method.
MongoDB's native JSR-310 support can be enabled through `MongoConverterConfigurationAdapter.useNativeDriverJavaTimeCodecs()`.
Also shown in the preceding example is a `LoggingEventListener`, which logs `MongoMappingEvent` instances that are posted onto Spring's `ApplicationContextEvent` infrastructure.
NOTE: `AbstractMongoClientConfiguration` creates a `MongoTemplate` instance and registers it with the container under the name `mongoTemplate`.
Spring's MongoDB namespace lets you enable mapping functionality in XML, as the following example shows:
Spring's MongoDB namespace lets you enable mapping functionality in XML, as the following example shows:
.XML schema to configure MongoDB mapping support
====