From 611793d5c79cf76980b586dabe2f86a8327a8890 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 17 Mar 2011 09:36:01 +0100 Subject: [PATCH 1/7] Improved handling of custom converters in SimpleMongoConverter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicitly remove converter for Object -> String on instance creation which allows us to get rid of the ugly SimpleToStringSuppressingGenericConversionService. writeCompoundValue(…) now asks the ConversionService whether it can convert the value to be written into one of Mongos native primitive types and rather delegates to the service instead of recursively writing the value itself. --- spring-data-mongodb/pom.xml | 7 ++ .../mongodb/convert/SimpleMongoConverter.java | 59 ++++++------- .../mongodb/SimpleMongoConverterTests.java | 84 ++++++++++++++++++- 3 files changed, 114 insertions(+), 36 deletions(-) diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 0d7fb7449..7d8e59dd5 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -152,6 +152,13 @@ junit test + + + joda-time + joda-time + 1.6 + test + diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java index 404226d45..11661eed6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/SimpleMongoConverter.java @@ -32,12 +32,9 @@ import org.bson.types.ObjectId; import org.springframework.beans.BeanUtils; import org.springframework.core.CollectionFactory; import org.springframework.core.convert.ConversionFailedException; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.core.convert.converter.ConditionalGenericConverter; +import org.springframework.core.convert.ConversionService; 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.MongoPropertyDescriptors.MongoPropertyDescriptor; @@ -54,6 +51,7 @@ import org.springframework.util.comparator.CompoundComparator; public class SimpleMongoConverter implements MongoConverter { private static final Log LOG = LogFactory.getLog(SimpleMongoConverter.class); + private static final List> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class, DBObject.class); private static final Set SIMPLE_TYPES; static { @@ -112,8 +110,8 @@ public class SimpleMongoConverter implements MongoConverter { * Creates a {@link SimpleMongoConverter}. */ public SimpleMongoConverter() { - this.conversionService = new SimpleToStringSuppressingGenericConversionService(); - ConversionServiceFactory.addDefaultConverters(conversionService); + this.conversionService = ConversionServiceFactory.createDefaultConversionService(); + this.conversionService.removeConvertible(Object.class, String.class); initializeConverters(); } @@ -123,12 +121,10 @@ public class SimpleMongoConverter implements MongoConverter { */ protected void initializeConverters() { - conversionService.addConverter(ObjectIdToStringConverter.INSTANCE); conversionService.addConverter(StringToObjectIdConverter.INSTANCE); conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE); conversionService.addConverter(BigIntegerToIdConverter.INSTANCE); - } /** @@ -237,15 +233,32 @@ public class SimpleMongoConverter implements MongoConverter { return; } - if (conversionService.canConvert(value.getClass(), String.class)) { - dbo.put(keyToUse, conversionService.convert(value, String.class)); + Class customTargetType = getCustomTargetType(value); + if (customTargetType != null) { + dbo.put(keyToUse, conversionService.convert(value, customTargetType)); return; } DBObject nestedDbo = new BasicDBObject(); write(value, nestedDbo); dbo.put(keyToUse, nestedDbo); - + } + + /** + * Returns whether the {@link ConversionService} has a custom {@link Converter} registered that can convert the given + * object into one of the types supported by MongoDB. + * + * @param obj + * @return + */ + private Class getCustomTargetType(Object obj) { + + for (Class mongoType : MONGO_TYPES) { + if (conversionService.canConvert(obj.getClass(), mongoType)) { + return mongoType; + } + } + return null; } /** @@ -510,30 +523,6 @@ public class SimpleMongoConverter implements MongoConverter { public ObjectId convertObjectId(Object id) { return conversionService.convert(id, ObjectId.class); } - - private static class SimpleToStringSuppressingGenericConversionService extends GenericConversionService { - - private static final Set REFERENCE = Collections.singleton(new ConvertiblePair(Object.class, String.class)); - - /* (non-Javadoc) - * @see org.springframework.core.convert.support.GenericConversionService#getConverter(org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor) - */ - @Override - protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { - - GenericConverter converter = super.getConverter(sourceType, targetType); - - if (converter instanceof ConditionalGenericConverter) { - - Set convertibleTypes = ((ConditionalGenericConverter) converter).getConvertibleTypes(); - if (REFERENCE.equals(convertibleTypes)) { - return null; - } - } - - return converter; - } - } /** * Simple singleton to convert {@link ObjectId}s to their {@link String} representation. diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java index 892f1b3e5..4ca57c3ae 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/SimpleMongoConverterTests.java @@ -21,15 +21,22 @@ import static org.junit.Assert.*; import java.lang.reflect.Field; import java.math.BigInteger; 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 com.mongodb.BasicDBObject; import com.mongodb.DBObject; import com.mongodb.util.JSON; + +import org.hamcrest.CoreMatchers; +import org.joda.time.LocalDate; import org.junit.Before; 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.SimpleMongoConverter; @@ -292,10 +299,50 @@ public class SimpleMongoConverterTests { (DBObject) JSON.parse("{\"_id\" : {\"$oid\" : \"4d24809660413b687f5d323e\" }}")); assertThat(result.getId().toString(16), is("4d24809660413b687f5d323e")); } + + @Test + public void convertsAddressCorrectly() { + + Address address = new Address(); + address.city = "New York"; + address.street = "Broadway"; + + DBObject dbObject = new BasicDBObject(); + + converter.write(address, dbObject); + + assertThat(dbObject.get("city").toString(), is("New York")); + assertThat(dbObject.get("street").toString(), is("Broadway")); + + Address result = converter.read(Address.class, dbObject); + assertThat(result.city, is("New York")); + assertThat(result.street, is("Broadway")); + } + + @Test + public void convertsJodaTimeTypesCorrectly() { + + Set> converters = new HashSet>(); + converters.add(new LocalDateToDateConverter()); + converters.add(new DateToLocalDateConverter()); + + converter.setConverters(converters); + + AnotherPerson person = new AnotherPerson(); + person.birthDate = new LocalDate(); + + DBObject dbObject = new BasicDBObject(); + converter.write(person, dbObject); + + assertTrue(dbObject.get("birthDate") instanceof Date); + + AnotherPerson result = converter.read(AnotherPerson.class, dbObject); + assertThat(result.getBirthDate(), is(notNullValue())); + } private void assertListOfStringAndLong(List> types) { - assertThat(types.size(), is(2)); + assertThat(types.size(), CoreMatchers.is(2)); assertEquals(String.class, types.get(0)); assertEquals(Long.class, types.get(1)); } @@ -347,4 +394,39 @@ public class SimpleMongoConverterTests { return id; } } + + public static class Address { + String street; + String city; + + public String getStreet() { + return street; + } + + public String getCity() { + return city; + } + } + + public static class AnotherPerson { + LocalDate birthDate; + + public LocalDate getBirthDate() { + return birthDate; + } + } + + private class LocalDateToDateConverter implements Converter { + + public Date convert(LocalDate source) { + return source.toDateMidnight().toDate(); + } + } + + private class DateToLocalDateConverter implements Converter { + + public LocalDate convert(Date source) { + return new LocalDate(source.getTime()); + } + } } From 4629ebdcfe0524930438fc5e87489360bd218bae Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 17 Mar 2011 09:44:14 +0100 Subject: [PATCH 2/7] Tweaked MappingMongoConverter to prefer custom Converters. Before recursively converting values itself, MappingMongoConverter now checks whether the underlying ConversionService can convert the value to be converted into a Mongo basic type itself. --- .../convert/MappingMongoConverter.java | 67 +++++++++-- .../MappingMongoConverterUnitTests.java | 106 ++++++++++++++++++ 2 files changed, 162 insertions(+), 11 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java index 3de89b155..669d5b8ad 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java @@ -41,6 +41,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.ConversionServiceFactory; import org.springframework.core.convert.support.GenericConversionService; @@ -63,6 +64,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; public class MappingMongoConverter implements MongoConverter, ApplicationContextAware { private static final String CUSTOM_TYPE_KEY = "_class"; + private static final List> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class, DBObject.class); protected static final Log log = LogFactory.getLog(MappingMongoConverter.class); protected GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); @@ -377,7 +379,14 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext this.applicationContext = applicationContext; } + /** + * Registers converters for {@link ObjectId} handling, removes plain {@link #toString()} converter and promotes the + * configured {@link ConversionService} to {@link MappingBeanHelper}. + */ protected void initializeConverters() { + + this.conversionService.removeConvertible(Object.class, String.class); + if (!conversionService.canConvert(ObjectId.class, String.class)) { conversionService.addConverter(ObjectIdToStringConverter.INSTANCE); conversionService.addConverter(StringToObjectIdConverter.INSTANCE); @@ -386,13 +395,17 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE); conversionService.addConverter(BigIntegerToIdConverter.INSTANCE); } + + MappingBeanHelper.setConversionService(conversionService); } @SuppressWarnings({"unchecked"}) protected void writePropertyInternal(PersistentProperty prop, Object obj, DBObject dbo) { org.springframework.data.document.mongodb.mapping.DBRef dbref = prop.getField() .getAnnotation(org.springframework.data.document.mongodb.mapping.DBRef.class); + String name = prop.getName(); + if (prop.isCollection()) { Class type = prop.getType(); BasicDBList dbList = new BasicDBList(); @@ -408,20 +421,52 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } dbo.put(name, dbList); - } else if (null != obj && obj instanceof Map) { + return; + } + + if (null != obj && obj instanceof Map) { BasicDBObject mapDbObj = new BasicDBObject(); writeMapInternal((Map) obj, mapDbObj); dbo.put(name, mapDbObj); - } else { - if (null != dbref) { - DBRef dbRef = createDBRef(obj, dbref); - dbo.put(name, dbRef); - } else { - BasicDBObject propDbObj = new BasicDBObject(); - write(obj, propDbObj, mappingContext.getPersistentEntity(prop.getTypeInformation())); - dbo.put(name, propDbObj); + return; + } + + if (null != dbref) { + DBObject dbRefObj = createDBRef(obj, dbref); + if (null != dbRefObj) { + dbo.put(name, dbRefObj); + return; } } + + Class basicTargetType = getCustomTargetType(obj); + + if (basicTargetType != null) { + dbo.put(name, conversionService.convert(obj, basicTargetType)); + return; + } + + BasicDBObject propDbObj = new BasicDBObject(); + write(obj, propDbObj, mappingContext.getPersistentEntity(prop.getTypeInformation())); + dbo.put(name, propDbObj); + + } + + /** + * Returns whether the {@link ConversionService} has a custom {@link Converter} registered that can convert the given + * object into one of the types supported by MongoDB. + * + * @param obj + * @return + */ + private Class getCustomTargetType(Object obj) { + + for (Class mongoType : MONGO_TYPES) { + if (conversionService.canConvert(obj.getClass(), mongoType)) { + return mongoType; + } + } + return null; } protected void writeMapInternal(Map obj, DBObject dbo) { @@ -510,7 +555,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext continue; } if (null != entry.getValue() && entry.getValue() instanceof DBObject) { - m.put(entry.getKey(), read((null != toType ? toType : prop.getTypeInformation().getMapValueType()), (DBObject) entry.getValue())); + m.put(entry.getKey(), read((null != toType ? toType : prop.getMapValueType()), (DBObject) entry.getValue())); } else { m.put(entry.getKey(), entry.getValue()); } @@ -518,7 +563,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext return m; } else if (prop.isArray() && dbObj instanceof BasicDBObject && ((DBObject) dbObj).keySet().size() == 0) { // It's empty - return Array.newInstance(prop.getType().getComponentType(), 0); + return Array.newInstance(prop.getComponentType(), 0); } else if (prop.isCollection() && dbObj instanceof BasicDBList) { BasicDBList dbObjList = (BasicDBList) dbObj; Object[] items = (Object[]) Array.newInstance(prop.getComponentType(), dbObjList.size()); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java new file mode 100644 index 000000000..b8bcb460b --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java @@ -0,0 +1,106 @@ +package org.springframework.data.document.mongodb.mapping; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import org.joda.time.LocalDate; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.document.mongodb.convert.MappingMongoConverter; +import org.springframework.data.mapping.BasicMappingContext; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + +/** + * Unit tests for {@link MappingMongoConverter}. + * + * @author Oliver Gierke + */ +@RunWith(MockitoJUnitRunner.class) +public class MappingMongoConverterUnitTests { + + MappingMongoConverter converter; + BasicMappingContext mappingContext; + + @Mock + ApplicationContext applicationContext; + + @Before + public void setUp() { + mappingContext = new BasicMappingContext(); + mappingContext.setApplicationContext(applicationContext); + converter = new MappingMongoConverter(mappingContext); + } + + @Test + public void convertsAddressCorrectly() { + + Address address = new Address(); + address.city = "New York"; + address.street = "Broadway"; + + DBObject dbObject = new BasicDBObject(); + + converter.write(address, dbObject); + + assertThat(dbObject.get("city").toString(), is("New York")); + assertThat(dbObject.get("street").toString(), is("Broadway")); + } + + @Test + public void convertsJodaTimeTypesCorrectly() { + + List> converters = new ArrayList>(); + converters.add(new LocalDateToDateConverter()); + converters.add(new DateToLocalDateConverter()); + + List> customSimpleTypes = new ArrayList>(); + customSimpleTypes.add(LocalDate.class); + mappingContext.setCustomSimpleTypes(customSimpleTypes); + + converter = new MappingMongoConverter(mappingContext, converters); + + Person person = new Person(); + person.birthDate = new LocalDate(); + + DBObject dbObject = new BasicDBObject(); + converter.write(person, dbObject); + + assertTrue(dbObject.get("birthDate") instanceof Date); + + Person result = converter.read(Person.class, dbObject); + assertThat(result.birthDate, is(notNullValue())); + } + + + public static class Address { + String street; + String city; + } + + public static class Person { + LocalDate birthDate; + } + + private class LocalDateToDateConverter implements Converter { + + public Date convert(LocalDate source) { + return source.toDateMidnight().toDate(); + } + } + + private class DateToLocalDateConverter implements Converter { + + public LocalDate convert(Date source) { + return new LocalDate(source.getTime()); + } + } +} From c4701d18f60391558657aa286bd033a3f16cd4ae Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 17 Mar 2011 10:10:34 +0100 Subject: [PATCH 3/7] Tweaked unit test to use mock ApplicationContext. --- .../mongodb/mapping/GenericMappingTests.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java index d8dca29ab..539aabcac 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/GenericMappingTests.java @@ -25,24 +25,32 @@ import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.context.ApplicationContext; import org.springframework.data.document.mongodb.convert.MappingMongoConverter; import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.mapping.BasicMappingContext; -import org.springframework.data.mapping.model.MappingContext; /** * Unit tests for testing the mapping works with generic types. * * @author Oliver Gierke */ +@RunWith(MockitoJUnitRunner.class) public class GenericMappingTests { - MappingContext context; + BasicMappingContext context; MongoConverter converter; + + @Mock + ApplicationContext applicationContext; @Before public void setUp() { context = new BasicMappingContext(new MongoMappingConfigurationBuilder(null)); + context.setApplicationContext(applicationContext); context.addPersistentEntity(StringWrapper.class); converter = new MappingMongoConverter(context); } From 30e4c4330beec43fd6959100b1adf1018c46c6a0 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 17 Mar 2011 10:31:08 +0100 Subject: [PATCH 4/7] Tweaks after merging Jon's latest changes. --- .../document/mongodb/convert/MappingMongoConverter.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java index 669d5b8ad..a189640a8 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java @@ -22,6 +22,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -59,7 +60,11 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; /** + * {@link MongoConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to + * {@link DBObject}. + * * @author Jon Brisbin + * @author Oliver Gierke */ public class MappingMongoConverter implements MongoConverter, ApplicationContextAware { @@ -432,7 +437,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } if (null != dbref) { - DBObject dbRefObj = createDBRef(obj, dbref); + DBRef dbRefObj = createDBRef(obj, dbref); if (null != dbRefObj) { dbo.put(name, dbRefObj); return; From 49e3f2b8c7070e32f87d09a973f038f26f11b1e9 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 17 Mar 2011 14:34:36 +0100 Subject: [PATCH 5/7] Improved handling of custom converters. On COnverter registration we now keep track of the types the converter can register and only apply custom conversion if we had discovered a custom converter initially. --- .../convert/MappingMongoConverter.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java index a189640a8..886fbdf5d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -42,6 +43,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.core.GenericTypeResolver; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.ConversionServiceFactory; @@ -72,7 +74,8 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext private static final List> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class, DBObject.class); protected static final Log log = LogFactory.getLog(MappingMongoConverter.class); - protected GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); + protected final GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); + protected final Map, Class> customTypeMapping = new HashMap, Class>(); protected SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); protected MappingContext mappingContext; protected ApplicationContext applicationContext; @@ -94,12 +97,26 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext this.mappingContext = mappingContext; if (null != converters) { for (Converter c : converters) { + registerConverter(c); conversionService.addConverter(c); } } initializeConverters(); } + /** + * 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(Converter converter) { + Class[] arguments = GenericTypeResolver.resolveTypeArguments(converter.getClass(), Converter.class); + if (MONGO_TYPES.contains(arguments[1])) { + customTypeMapping.put(arguments[0], arguments[1]); + } + } + public MappingContext getMappingContext() { return mappingContext; } @@ -444,7 +461,8 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } - Class basicTargetType = getCustomTargetType(obj); + // Lookup potential custom target type + Class basicTargetType = customTypeMapping.get(obj.getClass()); if (basicTargetType != null) { dbo.put(name, conversionService.convert(obj, basicTargetType)); @@ -457,23 +475,6 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } - /** - * Returns whether the {@link ConversionService} has a custom {@link Converter} registered that can convert the given - * object into one of the types supported by MongoDB. - * - * @param obj - * @return - */ - private Class getCustomTargetType(Object obj) { - - for (Class mongoType : MONGO_TYPES) { - if (conversionService.canConvert(obj.getClass(), mongoType)) { - return mongoType; - } - } - return null; - } - protected void writeMapInternal(Map obj, DBObject dbo) { for (Map.Entry entry : obj.entrySet()) { Object key = entry.getKey(); From 6540c234130d65891a07d123f1c74dcc0d8bd8f7 Mon Sep 17 00:00:00 2001 From: Jon Brisbin Date: Thu, 17 Mar 2011 11:57:07 -0500 Subject: [PATCH 6/7] Added event handling capabilities based on Spring 2.0 ApplicationEvent abstractions. Publishes events into the current ApplicationContext to expose internal mapping events to listeners declared in the current ApplicationContext. --- .../data/document/mongodb/MongoTemplate.java | 47 ++++++++++++++++-- .../convert/MappingMongoConverter.java | 25 ++++------ .../mongodb/event/CollectionCreatedEvent.java | 42 ++++++++++++++++ .../document/mongodb/event/EventType.java | 27 ++++++++++ .../document/mongodb/event/InsertEvent.java | 42 ++++++++++++++++ .../document/mongodb/event/SaveEvent.java | 42 ++++++++++++++++ .../mongodb/event/WriteResultEvent.java | 35 +++++++++++++ .../mapping/event/MongoMappingEvent.java | 49 +++++++++++++++++++ .../mongodb/mapping/InsertEventListener.java | 43 ++++++++++++++++ .../MappingMongoConverterUnitTests.java | 16 ++++++ .../mongodb/mapping/MappingTests.java | 14 +++++- .../src/test/resources/mapping.xml | 1 + 12 files changed, 362 insertions(+), 21 deletions(-) create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/CollectionCreatedEvent.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/EventType.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/InsertEvent.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/SaveEvent.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/WriteResultEvent.java create mode 100644 spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/MongoMappingEvent.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/InsertEventListener.java diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java index 43054b705..1b9b39acb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java @@ -22,6 +22,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingDeque; import com.mongodb.BasicDBObject; import com.mongodb.CommandResult; @@ -37,9 +41,13 @@ import com.mongodb.util.JSON; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bson.types.ObjectId; +import org.springframework.beans.BeansException; import org.springframework.beans.ConfigurablePropertyAccessor; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; import org.springframework.core.convert.ConversionFailedException; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; @@ -47,6 +55,9 @@ import org.springframework.data.document.mongodb.MongoPropertyDescriptors.MongoP import org.springframework.data.document.mongodb.convert.MappingMongoConverter; import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.document.mongodb.convert.SimpleMongoConverter; +import org.springframework.data.document.mongodb.event.CollectionCreatedEvent; +import org.springframework.data.document.mongodb.event.InsertEvent; +import org.springframework.data.document.mongodb.event.SaveEvent; import org.springframework.data.document.mongodb.query.IndexDefinition; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.document.mongodb.query.Update; @@ -61,7 +72,7 @@ import org.springframework.util.Assert; * @author Mark Pollack * @author Oliver Gierke */ -public class MongoTemplate implements InitializingBean, MongoOperations { +public class MongoTemplate implements InitializingBean, MongoOperations, ApplicationContextAware { private static final Log LOGGER = LogFactory.getLog(MongoTemplate.class); @@ -87,7 +98,9 @@ public class MongoTemplate implements InitializingBean, MongoOperations { private String databaseName; private String username; private String password; - + private ApplicationContext applicationContext; + private ExecutorService eventPublishers = Executors.newCachedThreadPool(); + private BlockingDeque eventQueue = new LinkedBlockingDeque(); /** * Constructor used for a basic template configuration @@ -173,6 +186,9 @@ public class MongoTemplate implements InitializingBean, MongoOperations { } } + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } /** * Sets the username to use to connect to the Mongo database @@ -548,6 +564,9 @@ public class MongoTemplate implements InitializingBean, MongoOperations { writer.write(objectToSave, dbDoc); Object id = insertDBObject(collectionName, dbDoc); populateIdIfNecessary(objectToSave, id); + if (null != applicationContext) { + eventQueue.add(new InsertEvent(collectionName, dbDoc)); + } } /* (non-Javadoc) @@ -621,6 +640,9 @@ public class MongoTemplate implements InitializingBean, MongoOperations { writer.write(objectToSave, dbDoc); ObjectId id = saveDBObject(collectionName, dbDoc); populateIdIfNecessary(objectToSave, id); + if (null != applicationContext) { + eventQueue.add(new SaveEvent(collectionName, dbDoc)); + } } @@ -806,7 +828,11 @@ public class MongoTemplate implements InitializingBean, MongoOperations { protected DBCollection doCreateCollection(final String collectionName, final DBObject collectionOptions) { return execute(new DbCallback() { public DBCollection doInDB(DB db) throws MongoException, DataAccessException { - return db.createCollection(collectionName, collectionOptions); + DBCollection coll = db.createCollection(collectionName, collectionOptions); + if (null != applicationContext) { + eventQueue.add(new CollectionCreatedEvent(collectionName, collectionOptions)); + } + return coll; } }); } @@ -1043,6 +1069,21 @@ public class MongoTemplate implements InitializingBean, MongoOperations { ((MappingMongoConverter) mongoConverter).setMongo(mongo); ((MappingMongoConverter) mongoConverter).setDefaultDatabase(databaseName); } + if (null != applicationContext) { + eventPublishers.submit(new Runnable() { + public void run() { + while (true) { + ApplicationEvent event = null; + try { + event = eventQueue.take(); + applicationContext.publishEvent(event); + } catch (InterruptedException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + }); + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java index 886fbdf5d..000531d95 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/convert/MappingMongoConverter.java @@ -64,13 +64,14 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; /** * {@link MongoConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to * {@link DBObject}. - * + * * @author Jon Brisbin * @author Oliver Gierke */ public class MappingMongoConverter implements MongoConverter, ApplicationContextAware { private static final String CUSTOM_TYPE_KEY = "_class"; + @SuppressWarnings({"unchecked"}) private static final List> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class, DBObject.class); protected static final Log log = LogFactory.getLog(MappingMongoConverter.class); @@ -107,7 +108,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext /** * 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(Converter converter) { @@ -352,13 +353,6 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext entity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(PersistentProperty prop) { String name = prop.getName(); - if (null != idProperty && name.equals(idProperty.getName())) { - return; - } - if (prop.isAssociation()) { - return; - } - Class type = prop.getType(); Object propertyObj = null; try { @@ -406,9 +400,9 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext * configured {@link ConversionService} to {@link MappingBeanHelper}. */ protected void initializeConverters() { - + this.conversionService.removeConvertible(Object.class, String.class); - + if (!conversionService.canConvert(ObjectId.class, String.class)) { conversionService.addConverter(ObjectIdToStringConverter.INSTANCE); conversionService.addConverter(StringToObjectIdConverter.INSTANCE); @@ -417,7 +411,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext conversionService.addConverter(ObjectIdToBigIntegerConverter.INSTANCE); conversionService.addConverter(BigIntegerToIdConverter.INSTANCE); } - + MappingBeanHelper.setConversionService(conversionService); } @@ -425,11 +419,10 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext protected void writePropertyInternal(PersistentProperty prop, Object obj, DBObject dbo) { org.springframework.data.document.mongodb.mapping.DBRef dbref = prop.getField() .getAnnotation(org.springframework.data.document.mongodb.mapping.DBRef.class); - + String name = prop.getName(); - + Class type = prop.getType(); if (prop.isCollection()) { - Class type = prop.getType(); BasicDBList dbList = new BasicDBList(); Collection coll = (type.isArray() ? Arrays.asList((Object[]) obj) : (Collection) obj); for (Object propObjItem : coll) { @@ -472,7 +465,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext BasicDBObject propDbObj = new BasicDBObject(); write(obj, propDbObj, mappingContext.getPersistentEntity(prop.getTypeInformation())); dbo.put(name, propDbObj); - + } protected void writeMapInternal(Map obj, DBObject dbo) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/CollectionCreatedEvent.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/CollectionCreatedEvent.java new file mode 100644 index 000000000..a07356fc8 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/CollectionCreatedEvent.java @@ -0,0 +1,42 @@ +/* + * 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.event; + +import com.mongodb.DBObject; +import org.springframework.context.ApplicationEvent; + +/** + * @author Jon Brisbin + */ +public class CollectionCreatedEvent extends ApplicationEvent { + + private final DBObject options; + + public CollectionCreatedEvent(String collection, DBObject options) { + super(collection); + this.options = options; + } + + public String getCollection() { + return (String) super.getSource(); + } + + public DBObject getOptions() { + return options; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/EventType.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/EventType.java new file mode 100644 index 000000000..3cb5336ce --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/EventType.java @@ -0,0 +1,27 @@ +/* + * 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.event; + +/** + * @author Jon Brisbin + */ +public enum EventType { + COLLECTION_CREATED, + DOCUMENT_INSERTED, + DOCUMENT_UPDATED, + DOCUMENT_DELETED +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/InsertEvent.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/InsertEvent.java new file mode 100644 index 000000000..94121ff05 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/InsertEvent.java @@ -0,0 +1,42 @@ +/* + * 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.event; + +import com.mongodb.DBObject; +import org.springframework.context.ApplicationEvent; + +/** + * @author Jon Brisbin + */ +public class InsertEvent extends ApplicationEvent { + + private final String collection; + + public InsertEvent(String collection, DBObject dbo) { + super(dbo); + this.collection = collection; + } + + public String getCollection() { + return collection; + } + + public DBObject getDBObject() { + return (DBObject) source; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/SaveEvent.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/SaveEvent.java new file mode 100644 index 000000000..c9e40b765 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/SaveEvent.java @@ -0,0 +1,42 @@ +/* + * 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.event; + +import com.mongodb.DBObject; +import org.springframework.context.ApplicationEvent; + +/** + * @author Jon Brisbin + */ +public class SaveEvent extends ApplicationEvent { + + private final String collection; + + public SaveEvent(String collection, DBObject source) { + super(source); + this.collection = collection; + } + + public DBObject getDBObject() { + return (DBObject) source; + } + + public String getCollection() { + return collection; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/WriteResultEvent.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/WriteResultEvent.java new file mode 100644 index 000000000..bfbedc9c7 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/event/WriteResultEvent.java @@ -0,0 +1,35 @@ +/* + * 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.event; + +import com.mongodb.WriteResult; +import org.springframework.context.ApplicationEvent; + +/** + * @author Jon Brisbin + */ +public class WriteResultEvent extends ApplicationEvent { + + public WriteResultEvent(WriteResult result) { + super(result); + } + + public WriteResult getWriteResult() { + return (WriteResult) source; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/MongoMappingEvent.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/MongoMappingEvent.java new file mode 100644 index 000000000..f422a651c --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/MongoMappingEvent.java @@ -0,0 +1,49 @@ +/* + * 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.mapping.event; + +import org.springframework.context.ApplicationEvent; +import org.springframework.data.document.mongodb.event.EventType; +import org.springframework.data.mapping.model.PersistentEntity; + +/** + * @author Jon Brisbin + */ +public class MongoMappingEvent extends ApplicationEvent { + + private final EventType type; + private final PersistentEntity entity; + + public MongoMappingEvent(EventType type, PersistentEntity entity, T target) { + super(target); + this.type = type; + this.entity = entity; + } + + public EventType getType() { + return type; + } + + public PersistentEntity getEntity() { + return entity; + } + + @Override + public T getSource() { + return (T) super.getSource(); + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/InsertEventListener.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/InsertEventListener.java new file mode 100644 index 000000000..0e7f4a3ce --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/InsertEventListener.java @@ -0,0 +1,43 @@ +/* + * 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.mapping; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.data.document.mongodb.event.InsertEvent; + +/** + * @author Jon Brisbin + */ +public class InsertEventListener implements ApplicationListener { + + private Logger log = LoggerFactory.getLogger(getClass()); + private AtomicInteger counter = new AtomicInteger(0); + + public void onApplicationEvent(InsertEvent event) { + log.info("Got INSERT event: " + event); + counter.incrementAndGet(); + } + + public int getCount() { + return counter.get(); + } + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java index b8bcb460b..29f534393 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingMongoConverterUnitTests.java @@ -1,3 +1,19 @@ +/* + * 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.mapping; import static org.hamcrest.Matchers.*; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java index d87d043e5..b342afa90 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java @@ -16,8 +16,7 @@ package org.springframework.data.document.mongodb.mapping; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.ArrayList; @@ -30,6 +29,7 @@ import com.mongodb.DBObject; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.data.document.mongodb.MongoTemplate; import org.springframework.data.document.mongodb.convert.MappingMongoConverter; import org.springframework.data.document.mongodb.query.Criteria; @@ -45,12 +45,16 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration("classpath:mapping.xml") public class MappingTests { + @Autowired + ApplicationContext applicationContext; @Autowired MongoTemplate template; @Autowired BasicMappingContext mappingContext; @Autowired MappingMongoConverter mongoConverter; + @Autowired + InsertEventListener insertEventListener; @Test public void setUp() { @@ -144,6 +148,11 @@ public class MappingTests { assertNotNull(p.getId()); } + @Test + public void testEventHandling() { + assertThat(insertEventListener.getCount(), greaterThan(0)); + } + @Test public void testReadEntity() { List result = template.find(new Query(Criteria.where("ssn").is(123456789)), Person.class); @@ -151,4 +160,5 @@ public class MappingTests { assertThat(result.get(0).getAddress().getCountry(), is("USA")); assertThat(result.get(0).getAccounts(), notNullValue()); } + } diff --git a/spring-data-mongodb/src/test/resources/mapping.xml b/spring-data-mongodb/src/test/resources/mapping.xml index 010431b54..65ee2cfed 100644 --- a/spring-data-mongodb/src/test/resources/mapping.xml +++ b/spring-data-mongodb/src/test/resources/mapping.xml @@ -30,4 +30,5 @@ + From f0c4f3e75f2f7214f4754476f3eb02a3f5c55f01 Mon Sep 17 00:00:00 2001 From: Jon Brisbin Date: Thu, 17 Mar 2011 13:09:03 -0500 Subject: [PATCH 7/7] Drop back to using LinkedBlockingQueue because the Deque version is Java 6.0 --- .../springframework/data/document/mongodb/MongoTemplate.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java index 1b9b39acb..266f1ac23 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoTemplate.java @@ -22,10 +22,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.concurrent.BlockingDeque; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; import com.mongodb.BasicDBObject; import com.mongodb.CommandResult; @@ -100,7 +99,7 @@ public class MongoTemplate implements InitializingBean, MongoOperations, Applica private String password; private ApplicationContext applicationContext; private ExecutorService eventPublishers = Executors.newCachedThreadPool(); - private BlockingDeque eventQueue = new LinkedBlockingDeque(); + private LinkedBlockingQueue eventQueue = new LinkedBlockingQueue(); /** * Constructor used for a basic template configuration