Merge remote branch 'origin/master'
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,4 +30,5 @@
|
||||
|
||||
<bean class="org.springframework.data.document.mongodb.MongoExceptionTranslator"/>
|
||||
|
||||
<bean id="insertEventListener" class="org.springframework.data.document.mongodb.mapping.InsertEventListener"/>
|
||||
</beans>
|
||||
|
||||
Reference in New Issue
Block a user