Merge remote branch 'origin/master'

This commit is contained in:
Mark Pollack
2011-03-17 15:36:39 -04:00
16 changed files with 646 additions and 63 deletions

View File

@@ -152,6 +152,13 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -22,6 +22,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
@@ -37,9 +40,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 +54,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 +71,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 +97,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 LinkedBlockingQueue<ApplicationEvent> eventQueue = new LinkedBlockingQueue<ApplicationEvent>();
/**
* Constructor used for a basic template configuration
@@ -173,6 +185,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 +563,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 +639,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 +827,11 @@ public class MongoTemplate implements InitializingBean, MongoOperations {
protected DBCollection doCreateCollection(final String collectionName, final DBObject collectionOptions) {
return execute(new DbCallback<DBCollection>() {
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 +1068,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);
}
}
}
});
}
}

View File

@@ -22,6 +22,8 @@ import java.math.BigInteger;
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;
@@ -41,6 +43,8 @@ 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;
import org.springframework.core.convert.support.GenericConversionService;
@@ -58,14 +62,21 @@ 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 <jbrisbin@vmware.com>
* @author Oliver Gierke
*/
public class MappingMongoConverter implements MongoConverter, ApplicationContextAware {
private static final String CUSTOM_TYPE_KEY = "_class";
@SuppressWarnings({"unchecked"})
private static final List<Class<?>> 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<?>, Class<?>> customTypeMapping = new HashMap<Class<?>, Class<?>>();
protected SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
protected MappingContext mappingContext;
protected ApplicationContext applicationContext;
@@ -87,12 +98,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;
}
@@ -328,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 {
@@ -377,7 +395,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,15 +411,18 @@ 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();
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) {
@@ -408,20 +436,36 @@ 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<Object, Object>) 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) {
DBRef dbRefObj = createDBRef(obj, dbref);
if (null != dbRefObj) {
dbo.put(name, dbRefObj);
return;
}
}
// Lookup potential custom target type
Class<?> basicTargetType = customTypeMapping.get(obj.getClass());
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);
}
protected void writeMapInternal(Map<Object, Object> obj, DBObject dbo) {
@@ -510,7 +554,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 +562,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());

View File

@@ -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<Class<?>> MONGO_TYPES = Arrays.asList(Number.class, Date.class, String.class, DBObject.class);
private static final Set<String> 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<ConvertiblePair> 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<ConvertiblePair> convertibleTypes = ((ConditionalGenericConverter) converter).getConvertibleTypes();
if (REFERENCE.equals(convertibleTypes)) {
return null;
}
}
return converter;
}
}
/**
* Simple singleton to convert {@link ObjectId}s to their {@link String} representation.

View File

@@ -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 <jbrisbin@vmware.com>
*/
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;
}
}

View File

@@ -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 <jbrisbin@vmware.com>
*/
public enum EventType {
COLLECTION_CREATED,
DOCUMENT_INSERTED,
DOCUMENT_UPDATED,
DOCUMENT_DELETED
}

View File

@@ -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 <jbrisbin@vmware.com>
*/
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;
}
}

View File

@@ -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 <jbrisbin@vmware.com>
*/
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;
}
}

View File

@@ -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 <jbrisbin@vmware.com>
*/
public class WriteResultEvent extends ApplicationEvent {
public WriteResultEvent(WriteResult result) {
super(result);
}
public WriteResult getWriteResult() {
return (WriteResult) source;
}
}

View File

@@ -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 <jbrisbin@vmware.com>
*/
public class MongoMappingEvent<T> extends ApplicationEvent {
private final EventType type;
private final PersistentEntity<T> entity;
public MongoMappingEvent(EventType type, PersistentEntity<T> entity, T target) {
super(target);
this.type = type;
this.entity = entity;
}
public EventType getType() {
return type;
}
public PersistentEntity<T> getEntity() {
return entity;
}
@Override
public T getSource() {
return (T) super.getSource();
}
}

View File

@@ -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<Converter<?, ?>> converters = new HashSet<Converter<?,?>>();
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<Class<?>> 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<LocalDate, Date> {
public Date convert(LocalDate source) {
return source.toDateMidnight().toDate();
}
}
private class DateToLocalDateConverter implements Converter<Date, LocalDate> {
public LocalDate convert(Date source) {
return new LocalDate(source.getTime());
}
}
}

View File

@@ -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);
}

View File

@@ -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 <jbrisbin@vmware.com>
*/
public class InsertEventListener implements ApplicationListener<InsertEvent> {
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();
}
}

View File

@@ -0,0 +1,122 @@
/*
* 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.*;
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<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);
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<LocalDate, Date> {
public Date convert(LocalDate source) {
return source.toDateMidnight().toDate();
}
}
private class DateToLocalDateConverter implements Converter<Date, LocalDate> {
public LocalDate convert(Date source) {
return new LocalDate(source.getTime());
}
}
}

View File

@@ -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<Person> 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());
}
}

View File

@@ -30,4 +30,5 @@
<bean class="org.springframework.data.document.mongodb.MongoExceptionTranslator"/>
<bean id="insertEventListener" class="org.springframework.data.document.mongodb.mapping.InsertEventListener"/>
</beans>