Browse Source

DATACMNS-169 - Revised custom converter handling.

Registering custom converts now automatically declares the custom handled types simple by using the SimpleTypeHolder built up by the CustomConversions instance. All the custom converter lookup logic is now in CustomConversions and AbstractMongoConverter uses that over handling it itself.
pull/1/head
Oliver Gierke 15 years ago
parent
commit
8ac2ff6b81
  1. 80
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MappingMongoConverterParser.java
  2. 115
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/AbstractMongoConverter.java
  3. 260
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/CustomConversions.java
  4. 52
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java
  5. 7
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentProperty.java
  6. 35
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingContext.java
  7. 9
      spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/SimpleMongoMappingContext.java
  8. 6
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java
  9. 10
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java
  10. 15
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TestMongoConfiguration.java
  11. 95
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/convert/CustomConversionsUnitTests.java
  12. 12
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/convert/CustomConvertersUnitTests.java
  13. 3
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentPropertyUnitTests.java
  14. 20
      spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java
  15. 22
      spring-data-mongodb/src/test/resources/template-mapping.xml

80
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MappingMongoConverterParser.java

@ -30,6 +30,7 @@ import org.springframework.beans.factory.config.RuntimeBeanReference; @@ -30,6 +30,7 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
@ -37,6 +38,7 @@ import org.springframework.beans.factory.xml.ParserContext; @@ -37,6 +38,7 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.document.mongodb.convert.CustomConversions;
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
import org.springframework.data.document.mongodb.mapping.Document;
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
@ -64,20 +66,9 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { @@ -64,20 +66,9 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
registry.registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
}
BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext);
String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition);
try {
registry.getBeanDefinition(POST_PROCESSOR);
@ -93,12 +84,15 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { @@ -93,12 +84,15 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
if (!StringUtils.hasText(dbFactoryRef)) {
dbFactoryRef = DB_FACTORY;
}
// Converter
BeanDefinitionBuilder converterBuilder = BeanDefinitionBuilder.genericBeanDefinition(MappingMongoConverter.class);
converterBuilder.addConstructorArgReference(dbFactoryRef);
converterBuilder.addConstructorArgReference(ctxRef);
if (conversionsDefinition != null) {
converterBuilder.addPropertyValue("customConversions", conversionsDefinition);
}
try {
registry.getBeanDefinition(INDEX_HELPER);
@ -112,20 +106,62 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser { @@ -112,20 +106,62 @@ public class MappingMongoConverterParser extends AbstractBeanDefinitionParser {
registry.registerBeanDefinition(INDEX_HELPER, indexHelperBuilder.getBeanDefinition());
}
return converterBuilder.getBeanDefinition();
}
private String potentiallyCreateMappingContext(Element element, ParserContext parserContext, BeanDefinition conversionsDefinition) {
String ctxRef = element.getAttribute("mapping-context-ref");
if (!StringUtils.hasText(ctxRef)) {
BeanDefinitionBuilder mappingContextBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MongoMappingContext.class);
Set<String> classesToAdd = getInititalEntityClasses(element, mappingContextBuilder);
if (classesToAdd != null) {
mappingContextBuilder.addPropertyValue("initialEntitySet", classesToAdd);
}
if (conversionsDefinition != null) {
AbstractBeanDefinition simpleTypesDefinition = new GenericBeanDefinition();
simpleTypesDefinition.setFactoryBeanName("customConversions");
simpleTypesDefinition.setFactoryMethodName("getSimpleTypeHolder");
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
}
parserContext.getRegistry().registerBeanDefinition(MAPPING_CONTEXT, mappingContextBuilder.getBeanDefinition());
ctxRef = MAPPING_CONTEXT;
}
return ctxRef;
}
private BeanDefinition getCustomConversions(Element element, ParserContext parserContext) {
List<Element> customConvertersElements = DomUtils.getChildElementsByTagName(element, "custom-converters");
if (customConvertersElements.size() == 1) {
Element customerConvertersElement = customConvertersElements.get(0);
ManagedList<BeanMetadataElement> converterBeans = new ManagedList<BeanMetadataElement>();
List<Element> listenerElements = DomUtils.getChildElementsByTagName(customerConvertersElement, "converter");
if (listenerElements != null) {
for (Element listenerElement : listenerElements) {
List<Element> converterElements = DomUtils.getChildElementsByTagName(customerConvertersElement, "converter");
if (converterElements != null) {
for (Element listenerElement : converterElements) {
converterBeans.add(parseConverter(listenerElement, parserContext));
}
}
converterBuilder.addPropertyValue("customConverters", converterBeans);
BeanDefinitionBuilder conversionsBuilder = BeanDefinitionBuilder.rootBeanDefinition(CustomConversions.class);
conversionsBuilder.addConstructorArgValue(converterBeans);
AbstractBeanDefinition conversionsBean = conversionsBuilder.getBeanDefinition();
conversionsBean.setSource(parserContext.extractSource(element));
parserContext.getRegistry().registerBeanDefinition("customConversions", conversionsBean);
return conversionsBean;
}
return converterBuilder.getBeanDefinition();
return null;
}
public Set<String> getInititalEntityClasses(Element element, BeanDefinitionBuilder builder) {

115
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/AbstractMongoConverter.java

@ -16,72 +16,55 @@ @@ -16,72 +16,55 @@
package org.springframework.data.document.mongodb.convert;
import static org.springframework.data.mapping.MappingBeanHelper.isSimpleType;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionService;
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.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.BigIntegerToObjectIdConverter;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.ObjectIdToBigIntegerConverter;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.ObjectIdToStringConverter;
import org.springframework.data.document.mongodb.convert.ObjectIdConverters.StringToObjectIdConverter;
import org.springframework.data.mapping.MappingBeanHelper;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Base class for {@link MongoConverter} implementations. Sets up a {@link GenericConversionService} and populates basic
* converters. Allows registering {@link CustomConversions}.
*
* @author Jon Brisbin <jbrisbin@vmware.com>
* @author Oliver Gierke ogierke@vmware.com
*/
public abstract class AbstractMongoConverter implements MongoConverter, InitializingBean {
@SuppressWarnings({ "unchecked" })
private static final List<Class<?>> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class,
DBObject.class);
protected final GenericConversionService conversionService;
private final Set<ConvertiblePair> customTypeMapping = new HashSet<ConvertiblePair>();
protected CustomConversions conversions = new CustomConversions();
/**
* Creates a new {@link AbstractMongoConverter} using the given {@link GenericConversionService}.
*
* @param conversionService
*/
public AbstractMongoConverter(GenericConversionService conversionService) {
this.conversionService = conversionService == null ? ConversionServiceFactory.createDefaultConversionService()
: conversionService;
this.conversionService.removeConvertible(Object.class, String.class);
registerConverter(CustomToStringConverter.INSTANCE);
}
/**
* Add custom {@link Converter} or {@link ConverterFactory} instances to be used that will take presidence over
* metadata driven conversion between of objects to/from DBObject
* Registers the given custom conversions with the converter.
*
* @param converters
* @param conversions
*/
public void setCustomConverters(Set<?> converters) {
if (null != converters) {
for (Object c : converters) {
registerConverter(c);
}
}
public void setCustomConversions(CustomConversions conversions) {
this.conversions = conversions;
}
/**
@ -102,61 +85,10 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali @@ -102,61 +85,10 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
if (!conversionService.canConvert(BigInteger.class, ObjectId.class)) {
conversionService.addConverter(BigIntegerToObjectIdConverter.INSTANCE);
}
}
/**
* Inspects the given {@link Converter} for the types it can convert and registers the pair for custom type conversion
* in case the target type is a Mongo basic type.
*
* @param converter
*/
private void registerConverter(Object converter) {
if (converter instanceof GenericConverter) {
customTypeMapping.addAll(((GenericConverter) converter).getConvertibleTypes());
} else {
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
if (MONGO_TYPES.contains(arguments[1]) || MONGO_TYPES.contains(arguments[0])) {
customTypeMapping.add(new ConvertiblePair(arguments[0], arguments[1]));
}
}
boolean added = false;
if (converter instanceof Converter) {
this.conversionService.addConverter((Converter<?, ?>) converter);
added = true;
}
if (converter instanceof ConverterFactory) {
this.conversionService.addConverterFactory((ConverterFactory<?, ?>) converter);
added = true;
}
if (converter instanceof GenericConverter) {
this.conversionService.addConverter((GenericConverter) converter);
added = true;
}
if (!added) {
throw new IllegalArgumentException("Given set contains element that is neither Converter nor ConverterFactory!");
}
conversions.registerConvertersIn(conversionService);
}
protected Class<?> getCustomTarget(Class<?> source, Class<?> expectedTargetType) {
for (ConvertiblePair typePair : customTypeMapping) {
if (typePair.getSourceType().isAssignableFrom(source)) {
Class<?> targetType = typePair.getTargetType();
if (targetType.equals(expectedTargetType) || expectedTargetType == null) {
return targetType;
}
}
}
return null;
}
/*
* (non-Javadoc)
@ -179,7 +111,7 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali @@ -179,7 +111,7 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
return ((Enum<?>) obj).name();
}
if (null != obj && isSimpleType(obj.getClass())) {
if (null != obj && conversions.isSimpleType(obj.getClass())) {
// Doesn't need conversion
return obj;
}
@ -240,19 +172,4 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali @@ -240,19 +172,4 @@ public abstract class AbstractMongoConverter implements MongoConverter, Initiali
}
return newDbl;
}
private enum CustomToStringConverter implements GenericConverter {
INSTANCE;
public Set<ConvertiblePair> getConvertibleTypes() {
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class);
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source.toString();
}
}
}

260
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/CustomConversions.java

@ -0,0 +1,260 @@ @@ -0,0 +1,260 @@
/*
* Copyright (c) 2011 by the original author(s).
*
* 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.data.document.mongodb.convert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.springframework.core.GenericTypeResolver;
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.core.convert.support.GenericConversionService;
import org.springframework.data.mapping.SimpleTypeHolder;
import org.springframework.util.Assert;
import com.mongodb.DBObject;
/**
* Value object to capture custom conversion. That is essentially a {@link List} of converters and some additional logic
* around them. The converters are pretty much builds up two sets of types which Mongo basic types {@see #MONGO_TYPES}
* can be converted into and from. These types will be considered simple ones (which means they neither need deeper
* inspection nor nested conversion. Thus the {@link CustomConversions} also act as factory for {@link SimpleTypeHolder}.
*
* @author Oliver Gierke
*/
public class CustomConversions {
@SuppressWarnings({ "unchecked" })
private static final List<Class<?>> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class,
DBObject.class);
private final Set<ConvertiblePair> readingPairs;
private final Set<ConvertiblePair> writingPairs;
private final Set<Class<?>> customSimpleTypes;
private final SimpleTypeHolder simpleTypeHolder;
private final List<Object> converters;
/**
* Creates an empty {@link CustomConversions} object.
*/
CustomConversions() {
this(new ArrayList<Object>());
}
/**
* Creates a new {@link CustomConversions} instance registering the given converters.
*
* @param converters
*/
public CustomConversions(List<?> converters) {
Assert.notNull(converters);
this.readingPairs = new HashSet<ConvertiblePair>();
this.writingPairs = new HashSet<ConvertiblePair>();
this.customSimpleTypes = new HashSet<Class<?>>();
registerConversion(CustomToStringConverter.INSTANCE);
for (Object c : converters) {
registerConversion(c);
}
this.converters = new ArrayList<Object>();
this.converters.add(CustomToStringConverter.INSTANCE);
this.converters.addAll(converters);
this.simpleTypeHolder = new SimpleTypeHolder(customSimpleTypes, true);
}
/**
* Returns the underlying {@link SimpleTypeHolder}.
*
* @return
*/
public SimpleTypeHolder getSimpleTypeHolder() {
return simpleTypeHolder;
}
/**
* Returns whether the given type is considered to be simple.
*
* @param type
* @return
*/
public boolean isSimpleType(Class<?> type) {
return simpleTypeHolder.isSimpleType(type);
}
/**
* Populates the given {@link GenericConversionService} with the convertes registered.
*
* @param conversionService
*/
public void registerConvertersIn(GenericConversionService conversionService) {
for (Object converter : converters) {
boolean added = false;
if (converter instanceof Converter) {
conversionService.addConverter((Converter<?, ?>) converter);
added = true;
}
if (converter instanceof ConverterFactory) {
conversionService.addConverterFactory((ConverterFactory<?, ?>) converter);
added = true;
}
if (converter instanceof GenericConverter) {
conversionService.addConverter((GenericConverter) converter);
added = true;
}
if (!added) {
throw new IllegalArgumentException("Given set contains element that is neither Converter nor ConverterFactory!");
}
}
}
/**
* Registers a conversion for the given converter. Inspects either generics or the {@link ConvertiblePair}s returned
* by a {@link GenericConverter}.
*
* @param converter
*/
private void registerConversion(Object converter) {
if (converter instanceof GenericConverter) {
GenericConverter genericConverter = (GenericConverter) converter;
for (ConvertiblePair pair : genericConverter.getConvertibleTypes()) {
register(pair);
}
} else if (converter instanceof Converter){
Class<?>[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class);
register(new ConvertiblePair(arguments[0], arguments[1]));
} else {
throw new IllegalArgumentException("Unsupported Converter type!");
}
}
/**
* Registers the given {@link ConvertiblePair} as reading or writing pair depending on the type sides being basic
* Mongo types.
*
* @param pair
*/
private void register(ConvertiblePair pair) {
if (isMongoBasicType(pair.getSourceType())) {
readingPairs.add(pair);
customSimpleTypes.add(pair.getTargetType());
}
if (isMongoBasicType(pair.getTargetType())) {
writingPairs.add(pair);
customSimpleTypes.add(pair.getSourceType());
}
}
/**
* Returns the target type we can write an onject of the given source type to. The returned type might be a subclass
* oth the given expected type though. If {@code expexctedTargetType} is {@literal null} we will simply return the
* first target type matching or {@literal null} if noe conversion can be found.
*
* @param source must not be {@literal null}
* @param expectedTargetType
* @return
*/
public Class<?> getCustomWriteTarget(Class<?> source, Class<?> expectedTargetType) {
Assert.notNull(source);
return getCustomTarget(source, expectedTargetType, writingPairs);
}
/**
* Returns whether we have a custom conversion registered to read the given source into the given target type.
*
* @param source must not be {@literal null}
* @param expectedTargetType must not be {@literal null}
* @return
*/
public boolean hasCustomReadTarget(Class<?> source, Class<?> expectedTargetType) {
Assert.notNull(source);
Assert.notNull(expectedTargetType);
return getCustomTarget(source, expectedTargetType, readingPairs) != null;
}
/**
* Inspects the given {@link ConvertiblePair} for ones that have a source compatible type as source. Additionally
* checks assignabilty of the target type if one is given.
*
* @param source must not be {@literal null}
* @param expectedTargetType
* @param pairs must not be {@literal null}
* @return
*/
private static Class<?> getCustomTarget(Class<?> source, Class<?> expectedTargetType, Iterable<ConvertiblePair> pairs) {
Assert.notNull(source);
Assert.notNull(pairs);
for (ConvertiblePair typePair : pairs) {
if (typePair.getSourceType().isAssignableFrom(source)) {
Class<?> targetType = typePair.getTargetType();
if (expectedTargetType == null || targetType.isAssignableFrom(expectedTargetType)) {
return targetType;
}
}
}
return null;
}
/**
* Returns whether the given type is a type that Mongo can handle basically.
*
* @param type
* @return
*/
private static boolean isMongoBasicType(Class<?> type) {
return MONGO_TYPES.contains(type);
}
private enum CustomToStringConverter implements GenericConverter {
INSTANCE;
public Set<ConvertiblePair> getConvertibleTypes() {
ConvertiblePair localeToString = new ConvertiblePair(Locale.class, String.class);
ConvertiblePair booleanToString = new ConvertiblePair(Character.class, String.class);
return new HashSet<ConvertiblePair>(Arrays.asList(localeToString, booleanToString));
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return source.toString();
}
}
}

52
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.data.document.mongodb.convert;
import static org.springframework.data.mapping.MappingBeanHelper.*;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
@ -138,9 +136,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -138,9 +136,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
TypeInformation<? extends S> typeToUse = getMoreConcreteTargetType(dbo, type);
Class<? extends S> rawType = typeToUse.getType();
Class<?> customTarget = getCustomTarget(rawType, DBObject.class);
if (customTarget != null) {
if (conversions.hasCustomReadTarget(DBObject.class, rawType)) {
return conversionService.convert(dbo, rawType);
}
@ -279,7 +276,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -279,7 +276,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return;
}
boolean handledByCustomConverter = getCustomTarget(obj.getClass(), DBObject.class) != null;
boolean handledByCustomConverter = conversions.getCustomWriteTarget(obj.getClass(), DBObject.class) != null;
if (!handledByCustomConverter) {
dbo.put(CUSTOM_TYPE_KEY, obj.getClass().getName());
@ -301,7 +298,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -301,7 +298,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return;
}
Class<?> customTarget = getCustomTarget(obj.getClass(), DBObject.class);
Class<?> customTarget = conversions.getCustomWriteTarget(obj.getClass(), DBObject.class);
if (customTarget != null) {
DBObject result = conversionService.convert(obj, DBObject.class);
@ -374,7 +371,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -374,7 +371,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
throw new MappingException(e.getMessage(), e);
}
if (null != propertyObj) {
if (!isSimpleType(propertyObj.getClass())) {
if (!conversions.isSimpleType(propertyObj.getClass())) {
writePropertyInternal(prop, propertyObj, dbo);
} else {
writeSimpleInternal(prop.getFieldName(), propertyObj, dbo);
@ -437,7 +434,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -437,7 +434,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
// Lookup potential custom target type
Class<?> basicTargetType = getCustomTarget(obj.getClass(), null);
Class<?> basicTargetType = conversions.getCustomWriteTarget(obj.getClass(), null);
if (basicTargetType != null) {
dbo.put(name, conversionService.convert(obj, basicTargetType));
@ -516,7 +513,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -516,7 +513,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Class<?> elementType = element.getClass();
if (isSimpleType(elementType)) {
if (conversions.isSimpleType(elementType)) {
dbList.add(element);
} else if (element instanceof Collection || elementType.isArray()) {
dbList.add(createCollectionDBObject(componentType, asCollection(element)));
@ -535,11 +532,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -535,11 +532,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
for (Map.Entry<Object, Object> entry : obj.entrySet()) {
Object key = entry.getKey();
Object val = entry.getValue();
if (isSimpleType(key.getClass())) {
if (conversions.isSimpleType(key.getClass())) {
// Don't use conversion service here as removal of ObjectToString converter results in some primitive types not
// being convertable
String simpleKey = key.toString();
if (isSimpleType(val.getClass())) {
if (conversions.isSimpleType(val.getClass())) {
writeSimpleInternal(simpleKey, val, dbo);
} else {
DBObject newDbo = new BasicDBObject();
@ -602,7 +599,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -602,7 +599,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
*/
private void writeSimpleInternal(String key, Object value, DBObject dbObject) {
Class<?> customTarget = getCustomTarget(value.getClass(), null);
Class<?> customTarget = conversions.getCustomWriteTarget(value.getClass(), null);
Object valueToSet = null;
if (customTarget != null) {
@ -652,30 +649,29 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -652,30 +649,29 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
o = x.getValue(ctx);
} else {
Object dbObj = dbo.get(prop.getFieldName());
Object sourceValue = dbo.get(prop.getFieldName());
if (dbObj == null) {
if (sourceValue == null) {
return null;
}
Class<?> propertyType = prop.getType();
Class<?> customTarget = getCustomTarget(dbObj.getClass(), propertyType);
if (customTarget != null) {
return conversionService.convert(dbObj, propertyType);
if (conversions.hasCustomReadTarget(sourceValue.getClass(), propertyType)) {
return conversionService.convert(sourceValue, propertyType);
}
if (dbObj instanceof DBRef) {
dbObj = ((DBRef) dbObj).fetch();
if (sourceValue instanceof DBRef) {
sourceValue = ((DBRef) sourceValue).fetch();
}
if (dbObj instanceof DBObject) {
if (sourceValue instanceof DBObject) {
if (prop.isMap()) {
return readMap(prop.getTypeInformation(), (DBObject) dbObj);
} else if (prop.isArray() && dbObj instanceof BasicDBObject && ((DBObject) dbObj).keySet().size() == 0) {
return readMap(prop.getTypeInformation(), (DBObject) sourceValue);
} else if (prop.isArray() && sourceValue instanceof BasicDBObject && ((DBObject) sourceValue).keySet().size() == 0) {
// It's empty
return Array.newInstance(prop.getComponentType(), 0);
} else if (prop.isCollection() && dbObj instanceof BasicDBList) {
BasicDBList dbObjList = (BasicDBList) dbObj;
} else if (prop.isCollection() && sourceValue instanceof BasicDBList) {
BasicDBList dbObjList = (BasicDBList) sourceValue;
List<Object> items = new LinkedList<Object>();
for (int i = 0; i < dbObjList.size(); i++) {
Object dbObjItem = dbObjList.get(i);
@ -694,17 +690,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -694,17 +690,17 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return itemsToReturn;
}
Class<?> toType = findTypeToBeUsed((DBObject) dbObj);
Class<?> toType = findTypeToBeUsed((DBObject) sourceValue);
// It's a complex object, have to read it in
if (toType != null) {
dbo.removeField(CUSTOM_TYPE_KEY);
o = read(toType, (DBObject) dbObj);
o = read(toType, (DBObject) sourceValue);
} else {
o = read(mappingContext.getPersistentEntity(prop.getTypeInformation()), (DBObject) dbObj);
o = read(mappingContext.getPersistentEntity(prop.getTypeInformation()), (DBObject) sourceValue);
}
} else {
o = dbObj;
o = sourceValue;
}
}
return o;

7
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentProperty.java

@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
import org.springframework.data.mapping.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.SimpleTypeHolder;
import org.springframework.data.mapping.model.Association;
/**
@ -56,9 +57,11 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope @@ -56,9 +57,11 @@ public class BasicMongoPersistentProperty extends AnnotationBasedPersistentPrope
* @param field
* @param propertyDescriptor
* @param owner
* @param simpleTypeHolder
*/
public BasicMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor, MongoPersistentEntity<?> owner) {
super(field, propertyDescriptor, owner);
public BasicMongoPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
MongoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
if (isIdProperty() && field.isAnnotationPresent(FieldName.class)) {
LOG.warn(String.format("Invalid usage of %s on id property. Field name will not be considered!", FieldName.class));

35
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/MongoMappingContext.java

@ -18,12 +18,13 @@ package org.springframework.data.document.mongodb.mapping; @@ -18,12 +18,13 @@ package org.springframework.data.document.mongodb.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import org.bson.types.CodeWScope;
import org.bson.types.ObjectId;
import org.springframework.data.mapping.AbstractMappingContext;
import org.springframework.data.mapping.MappingBeanHelper;
import org.springframework.data.mapping.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
/**
@ -31,23 +32,33 @@ import org.springframework.data.util.TypeInformation; @@ -31,23 +32,33 @@ import org.springframework.data.util.TypeInformation;
* @author Oliver Gierke ogierke@vmware.com
*/
public class MongoMappingContext extends AbstractMappingContext<BasicMongoPersistentEntity<?>, MongoPersistentProperty> {
public MongoMappingContext() {
augmentSimpleTypes();
private static final Set<Class<?>> MONGO_SIMPLE_TYPES = new HashSet<Class<?>>();
static {
MONGO_SIMPLE_TYPES.add(com.mongodb.DBRef.class);
MONGO_SIMPLE_TYPES.add(ObjectId.class);
MONGO_SIMPLE_TYPES.add(CodeWScope.class);
MONGO_SIMPLE_TYPES.add(Character.class);
}
protected void augmentSimpleTypes() {
// Augment simpleTypes with MongoDB-specific classes
Set<Class<?>> simpleTypes = MappingBeanHelper.getSimpleTypes();
simpleTypes.add(com.mongodb.DBRef.class);
simpleTypes.add(ObjectId.class);
simpleTypes.add(CodeWScope.class);
simpleTypes.add(Character.class);
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.AbstractMappingContext#setSimpleTypeHolder(org.springframework.data.mapping.SimpleTypeHolder)
*/
@Override
public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) {
super.setSimpleTypeHolder(new SimpleTypeHolder(MONGO_SIMPLE_TYPES, simpleTypes));
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.MutablePersistentEntity, org.springframework.data.mapping.SimpleTypeHolder)
*/
@Override
public MongoPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
BasicMongoPersistentEntity<?> owner) {
return new BasicMongoPersistentProperty(field, descriptor, owner);
BasicMongoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
return new BasicMongoPersistentProperty(field, descriptor, owner, simpleTypeHolder);
}
/* (non-Javadoc)

9
spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/SimpleMongoMappingContext.java

@ -24,6 +24,7 @@ import org.springframework.data.document.mongodb.MongoCollectionUtils; @@ -24,6 +24,7 @@ import org.springframework.data.document.mongodb.MongoCollectionUtils;
import org.springframework.data.mapping.AbstractMappingContext;
import org.springframework.data.mapping.BasicPersistentEntity;
import org.springframework.data.mapping.AbstractPersistentProperty;
import org.springframework.data.mapping.SimpleTypeHolder;
import org.springframework.data.mapping.model.Association;
import org.springframework.data.util.TypeInformation;
@ -47,8 +48,8 @@ public class SimpleMongoMappingContext extends @@ -47,8 +48,8 @@ public class SimpleMongoMappingContext extends
*/
@Override
protected SimplePersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
SimpleMongoPersistentEntity<?> owner) {
return new SimplePersistentProperty(field, descriptor, owner);
SimpleMongoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
return new SimplePersistentProperty(field, descriptor, owner, simpleTypeHolder);
}
static class SimplePersistentProperty extends AbstractPersistentProperty<MongoPersistentProperty> implements
@ -63,8 +64,8 @@ public class SimpleMongoMappingContext extends @@ -63,8 +64,8 @@ public class SimpleMongoMappingContext extends
* @param propertyDescriptor
* @param information
*/
public SimplePersistentProperty(Field field, PropertyDescriptor propertyDescriptor, MongoPersistentEntity<?> owner) {
super(field, propertyDescriptor, owner);
public SimplePersistentProperty(Field field, PropertyDescriptor propertyDescriptor, MongoPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}
/* (non-Javadoc)

6
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoOperationsUnitTests.java

@ -20,8 +20,6 @@ import static org.junit.Assert.*; @@ -20,8 +20,6 @@ import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.bson.types.ObjectId;
@ -83,10 +81,6 @@ public abstract class MongoOperationsUnitTests { @@ -83,10 +81,6 @@ public abstract class MongoOperationsUnitTests {
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getMappingContext() {
return null;
}
@Override
public void setCustomConverters(Set<?> converters) {
}
};
}

10
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java

@ -29,11 +29,8 @@ import java.util.ArrayList; @@ -29,11 +29,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hamcrest.CoreMatchers;
import org.joda.time.LocalDate;
import org.junit.Before;
@ -41,6 +38,7 @@ import org.junit.Test; @@ -41,6 +38,7 @@ import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.document.mongodb.SomeEnumTest.NumberEnum;
import org.springframework.data.document.mongodb.SomeEnumTest.StringEnum;
import org.springframework.data.document.mongodb.convert.CustomConversions;
import org.springframework.data.document.mongodb.convert.SimpleMongoConverter;
import org.springframework.util.ReflectionUtils;
@ -48,6 +46,7 @@ import com.mongodb.BasicDBObject; @@ -48,6 +46,7 @@ import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
@SuppressWarnings("deprecation")
public class SimpleMongoConverterTests {
static final String SIMPLE_JSON = "{ \"map\" : { \"foo\" : 3 , \"bar\" : 4}, \"number\" : 15 }";
@ -329,11 +328,12 @@ public class SimpleMongoConverterTests { @@ -329,11 +328,12 @@ public class SimpleMongoConverterTests {
@Test
public void convertsJodaTimeTypesCorrectly() {
Set<Converter<?, ?>> converters = new HashSet<Converter<?, ?>>();
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new LocalDateToDateConverter());
converters.add(new DateToLocalDateConverter());
converter.setCustomConverters(converters);
converter.setCustomConversions(new CustomConversions(converters));
converter.afterPropertiesSet();
AnotherPerson person = new AnotherPerson();
person.birthDate = new LocalDate();

15
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/TestMongoConfiguration.java

@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
package org.springframework.data.document.mongodb;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import com.mongodb.Mongo;
import org.springframework.context.annotation.Bean;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.document.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.document.mongodb.convert.CustomConversions;
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
public class TestMongoConfiguration extends AbstractMongoConfiguration {
@ -16,6 +16,7 @@ public class TestMongoConfiguration extends AbstractMongoConfiguration { @@ -16,6 +16,7 @@ public class TestMongoConfiguration extends AbstractMongoConfiguration {
return "database";
}
@Override
@Bean
public Mongo mongo() throws Exception {
return new Mongo("localhost", 27017);
@ -28,10 +29,10 @@ public class TestMongoConfiguration extends AbstractMongoConfiguration { @@ -28,10 +29,10 @@ public class TestMongoConfiguration extends AbstractMongoConfiguration {
@Override
protected void afterMappingMongoConverterCreation(MappingMongoConverter converter) {
Set<Converter<?, ?>> converterList = new HashSet<Converter<?, ?>>();
converterList.add(new org.springframework.data.document.mongodb.PersonReadConverter());
converterList.add(new org.springframework.data.document.mongodb.PersonWriteConverter());
converter.setCustomConverters(converterList);
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new org.springframework.data.document.mongodb.PersonReadConverter());
converters.add(new org.springframework.data.document.mongodb.PersonWriteConverter());
converter.setCustomConversions(new CustomConversions(converters));
}

95
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/convert/CustomConversionsUnitTests.java

@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
package org.springframework.data.document.mongodb.convert;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import java.util.Arrays;
import java.util.Locale;
import java.util.UUID;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.GenericConversionService;
/**
* Unit tests for {@link CustomConversions}.
*
* @author Oliver Gierke
*/
public class CustomConversionsUnitTests {
@Test
@SuppressWarnings("unchecked")
public void findsBasicReadAndWriteConversions() {
CustomConversions conversions = new CustomConversions(Arrays.asList(UuidToStringConverter.INSTANCE,
StringToUUIDConverter.INSTANCE));
assertThat(conversions.getCustomWriteTarget(UUID.class, null), is(typeCompatibleWith(String.class)));
assertThat(conversions.getCustomWriteTarget(String.class, null), is(nullValue()));
assertThat(conversions.hasCustomReadTarget(String.class, UUID.class), is(true));
assertThat(conversions.hasCustomReadTarget(String.class, Locale.class), is(false));
}
@Test
@SuppressWarnings("unchecked")
public void considersSubtypesCorrectly() {
CustomConversions conversions = new CustomConversions(Arrays.asList(
NumberToStringConverter.INSTANCE, StringToNumberConverter.INSTANCE));
assertThat(conversions.getCustomWriteTarget(Long.class, null), is(typeCompatibleWith(String.class)));
assertThat(conversions.hasCustomReadTarget(String.class, Long.class), is(true));
}
@Test
public void considersTypesWeRegisteredConvertersForAsSimple() {
CustomConversions conversions = new CustomConversions( Arrays.asList(UuidToStringConverter.INSTANCE));
assertThat(conversions.isSimpleType(UUID.class), is(true));
}
@Test
public void populatesConversionServiceCorrectly() {
GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
assertThat(conversionService.canConvert(String.class, UUID.class), is(false));
CustomConversions conversions = new CustomConversions(
Arrays.asList(StringToUUIDConverter.INSTANCE));
conversions.registerConvertersIn(conversionService);
assertThat(conversionService.canConvert(String.class, UUID.class), is(true));
}
enum UuidToStringConverter implements Converter<UUID, String> {
INSTANCE;
public String convert(UUID source) {
return source.toString();
}
}
enum StringToUUIDConverter implements Converter<String, UUID> {
INSTANCE;
public UUID convert(String source) {
return UUID.fromString(source);
}
}
enum NumberToStringConverter implements Converter<Number, String> {
INSTANCE;
public String convert(Number source) {
return source.toString();
}
}
enum StringToNumberConverter implements Converter<String, Number> {
INSTANCE;
public Number convert(String source) {
return 0L;
}
}
}

12
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/convert/CustomConvertersUnitTests.java

@ -61,15 +61,19 @@ public class CustomConvertersUnitTests { @@ -61,15 +61,19 @@ public class CustomConvertersUnitTests {
@SuppressWarnings("unchecked")
public void setUp() throws Exception {
when(barToDBObjectConverter.convert(any(Bar.class))).thenReturn(new BasicDBObject());
when(dbObjectToBarConverter.convert(any(DBObject.class))).thenReturn(new Bar());
CustomConversions conversions = new CustomConversions(Arrays.asList(barToDBObjectConverter, dbObjectToBarConverter));
context = new MongoMappingContext();
context.setInitialEntitySet(new HashSet<Class<?>>(Arrays.asList(Foo.class, Bar.class)));
context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
context.afterPropertiesSet();
when(barToDBObjectConverter.convert(any(Bar.class))).thenReturn(new BasicDBObject());
when(dbObjectToBarConverter.convert(any(DBObject.class))).thenReturn(new Bar());
converter = new MappingMongoConverter(mongoDbFactory, context);
converter.setCustomConverters(new HashSet<Object>(Arrays.asList(barToDBObjectConverter, dbObjectToBarConverter)));
converter.setCustomConversions(conversions);
converter.afterPropertiesSet();
}
@Test

3
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/BasicMongoPersistentPropertyUnitTests.java

@ -22,6 +22,7 @@ import java.lang.reflect.Field; @@ -22,6 +22,7 @@ import java.lang.reflect.Field;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.annotation.Id;
import org.springframework.data.mapping.SimpleTypeHolder;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.util.ReflectionUtils;
@ -62,7 +63,7 @@ public class BasicMongoPersistentPropertyUnitTests { @@ -62,7 +63,7 @@ public class BasicMongoPersistentPropertyUnitTests {
}
private MongoPersistentProperty getPropertyFor(Field field) {
return new BasicMongoPersistentProperty(field, null, entity);
return new BasicMongoPersistentProperty(field, null, entity, new SimpleTypeHolder());
}
class Person {

20
spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java

@ -25,13 +25,10 @@ import java.util.Arrays; @@ -25,13 +25,10 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Test;
@ -40,6 +37,7 @@ import org.mockito.Mock; @@ -40,6 +37,7 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.document.mongodb.MongoDbFactory;
import org.springframework.data.document.mongodb.convert.CustomConversions;
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
import com.mongodb.BasicDBList;
@ -61,8 +59,12 @@ public class MappingMongoConverterUnitTests { @@ -61,8 +59,12 @@ public class MappingMongoConverterUnitTests {
@Before
public void setUp() {
mappingContext = new MongoMappingContext();
mappingContext.afterPropertiesSet();
converter = new MappingMongoConverter(factory, mappingContext);
converter.afterPropertiesSet();
}
@Test
@ -83,16 +85,15 @@ public class MappingMongoConverterUnitTests { @@ -83,16 +85,15 @@ public class MappingMongoConverterUnitTests {
@Test
public void convertsJodaTimeTypesCorrectly() {
Set<Converter<?, ?>> converters = new HashSet<Converter<?, ?>>();
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new LocalDateToDateConverter());
converters.add(new DateToLocalDateConverter());
List<Class<?>> customSimpleTypes = new ArrayList<Class<?>>();
customSimpleTypes.add(LocalDate.class);
mappingContext.setCustomSimpleTypes(customSimpleTypes);
CustomConversions conversions = new CustomConversions(converters);
mappingContext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
converter = new MappingMongoConverter(factory, mappingContext);
converter.setCustomConverters(converters);
converter.setCustomConversions(conversions);
converter.afterPropertiesSet();
Person person = new Person();
@ -343,6 +344,7 @@ public class MappingMongoConverterUnitTests { @@ -343,6 +344,7 @@ public class MappingMongoConverterUnitTests {
}
@Test
@SuppressWarnings("unchecked")
public void writesNestedCollectionsCorrectly() {
CollectionWrapper wrapper = new CollectionWrapper();

22
spring-data-mongodb/src/test/resources/template-mapping.xml

@ -12,15 +12,23 @@ @@ -12,15 +12,23 @@
<bean id="mappingConverter1" class="org.springframework.data.document.mongodb.convert.MappingMongoConverter">
<constructor-arg ref="mongoDbFactory" />
<constructor-arg ref="mappingContext" />
<property name="customConverters">
<list>
<bean class="org.springframework.data.document.mongodb.PersonReadConverter"/>
<bean class="org.springframework.data.document.mongodb.PersonWriteConverter"/>
</list>
</property>
<property name="customConversions" ref="conversions" />
</bean>
<bean id="mappingContext" class="org.springframework.data.document.mongodb.mapping.MongoMappingContext"/>
<bean id="mappingContext" class="org.springframework.data.document.mongodb.mapping.MongoMappingContext">
<property name="simpleTypeHolder">
<bean factory-bean="conversions" factory-method="getSimpleTypeHolder" />
</property>
</bean>
<bean id="conversions" class="org.springframework.data.document.mongodb.convert.CustomConversions">
<constructor-arg>
<list>
<bean class="org.springframework.data.document.mongodb.PersonReadConverter" />
<bean class="org.springframework.data.document.mongodb.PersonWriteConverter" />
</list>
</constructor-arg>
</bean>
<bean id="mongoTemplate1" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>

Loading…
Cancel
Save