diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 7a62deb42..8bf5f90c5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -176,8 +176,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Assert.notNull(path, "ObjectPath must not be null"); - return new ConversionContext(this, conversions, path, this::readDocument, this::readCollectionOrArray, this::readMap, - this::readDBRef, this::getPotentiallyConvertedSimpleRead); + return new ConversionContext(this, conversions, path, this::readDocument, this::readCollectionOrArray, + this::readMap, this::readDBRef, this::getPotentiallyConvertedSimpleRead); } /** @@ -393,18 +393,18 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App EntityProjection property = returnedTypeDescriptor.findProperty(name); if (property == null) { - return new ConversionContext(conversions, path, MappingMongoConverter.this::readDocument, collectionConverter, + return new ConversionContext(sourceConverter, conversions, path, MappingMongoConverter.this::readDocument, collectionConverter, mapConverter, dbRefConverter, elementConverter); } - return new ProjectingConversionContext(sourceConverter, conversions, path, collectionConverter, mapConverter, dbRefConverter, - elementConverter, property); + return new ProjectingConversionContext(sourceConverter, conversions, path, collectionConverter, mapConverter, + dbRefConverter, elementConverter, property); } @Override public ConversionContext withPath(ObjectPath currentPath) { - return new ProjectingConversionContext(sourceConverter, conversions, currentPath, collectionConverter, mapConverter, - dbRefConverter, elementConverter, returnedTypeDescriptor); + return new ProjectingConversionContext(sourceConverter, conversions, currentPath, collectionConverter, + mapConverter, dbRefConverter, elementConverter, returnedTypeDescriptor); } } @@ -935,8 +935,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App TypeInformation valueType = ClassTypeInformation.from(obj.getClass()); TypeInformation type = prop.getTypeInformation(); - if(conversions.hasPropertyValueConverter(prop)) { - accessor.put(prop, conversions.getPropertyValueConverter(prop).write(obj, new MongoConversionContext(prop, this))); + if (conversions.hasPropertyValueConverter(prop)) { + accessor.put(prop, + conversions.getPropertyValueConverter(prop).write(obj, new MongoConversionContext(prop, this))); return; } @@ -1270,8 +1271,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App private void writeSimpleInternal(@Nullable Object value, Bson bson, MongoPersistentProperty property) { DocumentAccessor accessor = new DocumentAccessor(bson); - if(conversions.hasPropertyValueConverter(property)) { - accessor.put(property, conversions.getPropertyValueConverter(property).write(value, new MongoConversionContext(property, this))); + if (conversions.hasPropertyValueConverter(property)) { + accessor.put(property, + conversions.getPropertyValueConverter(property).write(value, new MongoConversionContext(property, this))); return; } @@ -1916,9 +1918,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return null; } - if(context.conversions.hasPropertyValueConverter(property)) { - - return (T) context.conversions.getPropertyValueConverter(property).read(value, new MongoConversionContext(property, context.sourceConverter)); + if (context.conversions.hasPropertyValueConverter(property)) { + return (T) context.conversions.getPropertyValueConverter(property).read(value, + new MongoConversionContext(property, context.sourceConverter)); } return (T) context.convert(value, property.getTypeInformation()); @@ -2148,7 +2150,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App final ContainerValueConverter dbRefConverter; final ValueConverter elementConverter; - ConversionContext(MongoConverter sourceConverter, org.springframework.data.convert.CustomConversions customConversions, ObjectPath path, + ConversionContext(MongoConverter sourceConverter, + org.springframework.data.convert.CustomConversions customConversions, ObjectPath path, ContainerValueConverter documentConverter, ContainerValueConverter> collectionConverter, ContainerValueConverter mapConverter, ContainerValueConverter dbRefConverter, ValueConverter elementConverter) { @@ -2235,8 +2238,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Assert.notNull(currentPath, "ObjectPath must not be null"); - return new ConversionContext(sourceConverter, conversions, currentPath, documentConverter, collectionConverter, mapConverter, - dbRefConverter, elementConverter); + return new ConversionContext(sourceConverter, conversions, currentPath, documentConverter, collectionConverter, + mapConverter, dbRefConverter, elementConverter); } public ObjectPath getPath() { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java index 9a83832d4..b486a693a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConversionContext.java @@ -50,11 +50,7 @@ public class MongoConversionContext implements ValueConversionContext T read(@Nullable Object value, TypeInformation target) { - - if (!(value instanceof Bson)) { - return ValueConversionContext.super.read(value, target); - } - - return mongoConverter.read(target.getType(), (Bson) value); + return value instanceof Bson ? mongoConverter.read(target.getType(), (Bson) value) + : ValueConversionContext.super.read(value, target); } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoCustomConversions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoCustomConversions.java index 857852fe2..02d91fa08 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoCustomConversions.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoCustomConversions.java @@ -36,6 +36,7 @@ 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.data.convert.ConverterBuilder; import org.springframework.data.convert.PropertyValueConversions; import org.springframework.data.convert.PropertyValueConverter; import org.springframework.data.convert.PropertyValueConverterFactory; @@ -263,7 +264,8 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus } /** - * Add {@link Converter converters}, {@link ConverterFactory factories}, ... + * Add {@link Converter converters}, {@link ConverterFactory factories}, {@link ConverterBuilder.ConverterAware + * converter-aware objects}, and {@link GenericConverter generic converters}. * * @param converters must not be {@literal null} nor contain {@literal null} values. * @return this. @@ -307,6 +309,7 @@ public class MongoCustomConversions extends org.springframework.data.convert.Cus */ public MongoConverterConfigurationAdapter setPropertyValueConversions(PropertyValueConversions valueConversions) { + Assert.notNull(valueConversions, "PropertyValueConversions must not be null"); this.propertyValueConversions = valueConversions; return this; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoValueConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoValueConverter.java index 49b9021cc..c3c23770e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoValueConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoValueConverter.java @@ -18,11 +18,9 @@ package org.springframework.data.mongodb.core.convert; import org.springframework.data.convert.PropertyValueConverter; /** - * Pre typed {@link PropertyValueConverter} specific for the Data MongoDB module. - * + * MongoDB-specific {@link PropertyValueConverter} extension. + * * @author Christoph Strobl * @since 3.4 */ -public interface MongoValueConverter extends PropertyValueConverter { - -} +public interface MongoValueConverter extends PropertyValueConverter {} diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index e80f2ba29..518c72c3a 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -5,7 +5,7 @@ == What's New in Spring Data MongoDB 3.4 * Find and update ``Document``s via <>. -* Property specific <>. +* Property-specific <>. [[new-features.3.3]] == What's New in Spring Data MongoDB 3.3 diff --git a/src/main/asciidoc/reference/mongo-property-converters.adoc b/src/main/asciidoc/reference/mongo-property-converters.adoc index 66b0e1374..18dfc7b1c 100644 --- a/src/main/asciidoc/reference/mongo-property-converters.adoc +++ b/src/main/asciidoc/reference/mongo-property-converters.adoc @@ -1,13 +1,13 @@ [[mongo.property-converters]] == Property Converters - Mapping specific fields -Although to the <> already offers means to influence the representation of certain types within the target store it has its limitations when not all potential values of that type should be considered as a conversion targets. -Property based converters allow to specify conversion instructions on a per property basis either declarative, via `@ValueConverter`, or programmatic by registering a `PropertyValueConverter` for a specific field. +While <> already offers ways to influence the conversion and representation of certain types within the target store it has its limitations when only certain values or properties of a particular type should be considered for conversion. +Property-based converters allow configuring conversion rules on a per-property basis, either declarative, via `@ValueConverter`, or programmatic by registering a `PropertyValueConverter` for a specific property. -A `PropertyValueConverter` is responsible of transforming a given value into its store representation (write) and back (read) as shown in the snippet below. -Please mind the presence of the `ValueConversionContext` providing additional information, such as mapping metadata. +A `PropertyValueConverter` can transform a given value into its store representation (**write**) and back (**read**) as shown in the snippet below. +The additional `ValueConversionContext` provides additional information, such as mapping metadata and direct `read`/`write` methods. -.PropertyValueConverter +.A simple PropertyValueConverter ==== [source,java] ---- @@ -26,69 +26,75 @@ class ReversingValueConverter implements PropertyValueConverter +registrar.registerConverter(Address.class, "street", new PropertyValueConverter() { … }); <1> // type safe registration -registrar.registerConverter(Person.class, Person::getSsn()) <2> +registrar.registerConverter(Person.class, Person::getSsn()) <2> .writing(value -> encrypt(value)) .reading(value -> decrypt(value)); ---- + <1> Register a converter for the field identified by its name. <2> Type safe variant that allows to register a converter and its conversion functions. ==== [WARNING] ==== -Dot notation (eg. `registerConverter(Person.class, "address.street", ...)`) is *not* supported when registering converters. +Dot-notation (such as `registerConverter(Person.class, "address.street", …)`) nagivating across properties into subdocuments is *not* supported when registering converters. ==== +[[mongo.property-converters.value-conversions]] === MongoDB property value conversions The above sections outlined the purpose an overall structure of `PropertyValueConverters`. This section will focus on MongoDB specific aspects. -==== MongoValueConverter & MongoConversionContext +==== MongoValueConverter and MongoConversionContext -The `MongoValueConverter` offers a pre typed `PropertyValueConverter` interface leveraging the `MongoConversionContext`. +`MongoValueConverter` offers a pre typed `PropertyValueConverter` interface leveraging the `MongoConversionContext`. ==== MongoCustomConversions configuration -`MongoCustomConversions` are by default capable of dealing with declarative value converters depending on the configured `PropertyValueConverterFactory`. -The `MongoConverterConfigurationAdapter` is there to help set up programmatic value conversions or define the `PropertyValueConverterFactory` to be used. +`MongoCustomConversions` are by default capable of handling declarative value converters depending on the configured `PropertyValueConverterFactory`. +`MongoConverterConfigurationAdapter` is there to help set up programmatic value conversions or define the `PropertyValueConverterFactory` to be used. .Configuration Sample ==== @@ -97,10 +103,10 @@ The `MongoConverterConfigurationAdapter` is there to help set up programmatic va MongoCustomConversions.create(configurationAdapter -> { SimplePropertyValueConversions valueConversions = new SimplePropertyValueConversions(); - valueConversions.setConverterFactory(...); + valueConversions.setConverterFactory(…); valueConversions.setValueConverterRegistry(new PropertyValueConverterRegistrar() - .registerConverter(...) - .buildRegistry()); + .registerConverter(…) + .buildRegistry()); configurationAdapter.setPropertyValueConversions(valueConversions); });