diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoCollectionUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoCollectionUtils.java
index e2e28bddd..83a8b3fb8 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoCollectionUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoCollectionUtils.java
@@ -20,9 +20,9 @@ package org.springframework.data.document.mongodb;
/**
* Helper class featuring helper methods for working with MongoDb collections.
*
- *
+ *
* Mainly intended for internal use within the framework.
- *
+ *
* @author Thomas Risberg
* @since 1.0
*/
@@ -37,13 +37,14 @@ public abstract class MongoCollectionUtils {
/**
* Obtains the collection name to use for the provided class
- *
- * @param entityClass
- * The class to determine the preferred collection name for
+ *
+ * @param entityClass The class to determine the preferred collection name for
* @return The preferred collection name
*/
public static String getPreferredCollectionName(Class> entityClass) {
- return entityClass.getSimpleName();
+ String name = entityClass.getSimpleName();
+ char firstChar = name.charAt(0);
+ return (String.valueOf(firstChar).toLowerCase() + name.substring(1));
}
}
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 879a99a9b..c3255e199 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
@@ -20,8 +20,10 @@ import static org.springframework.data.document.mongodb.query.Criteria.*;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -88,6 +90,11 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
private static final Log LOGGER = LogFactory.getLog(MongoTemplate.class);
private static final String ID = "_id";
+ private static final List ITERABLE_CLASSES = new ArrayList() {{
+ add(List.class.getName());
+ add(Collection.class.getName());
+ add(Iterator.class.getName());
+ }};
/*
* WriteConcern to be used for write operations if it has been specified. Otherwise
@@ -373,7 +380,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
public Void doInCollection(DBCollection collection) throws MongoException, DataAccessException {
collection.drop();
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Dropped collection ["+ collection.getFullName() + "]");
+ LOGGER.debug("Dropped collection [" + collection.getFullName() + "]");
}
return null;
}
@@ -475,6 +482,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.Object)
*/
public void insert(Object objectToSave) {
+ ensureNotIterable(objectToSave);
insert(determineEntityCollectionName(objectToSave), objectToSave);
}
@@ -482,9 +490,19 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
* @see org.springframework.data.document.mongodb.MongoOperations#insert(java.lang.String, java.lang.Object)
*/
public void insert(String collectionName, Object objectToSave) {
+ ensureNotIterable(objectToSave);
doInsert(collectionName, objectToSave, this.mongoConverter);
}
+ protected void ensureNotIterable(Object o) {
+ if (null != o) {
+ if (o.getClass().isArray() ||
+ ITERABLE_CLASSES.contains(o.getClass().getName())) {
+ throw new IllegalArgumentException("Cannot use a collection here.");
+ }
+ }
+ }
+
/**
* Prepare the collection before any processing is done using it. This allows a convenient way to apply
* settings like slaveOk() etc. Can be overridden in sub-classes.
@@ -613,21 +631,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
protected Object insertDBObject(String collectionName, final DBObject dbDoc) {
-
- // DATADOC-95: This will prevent null objects from being saved.
- // if (dbDoc.keySet().isEmpty()) {
- // return null;
- // }
-
- // TODO: Need to move this to more central place
- if (dbDoc.containsField("_id")) {
- if (dbDoc.get("_id") instanceof String) {
- ObjectId oid = convertIdValue(this.mongoConverter, dbDoc.get("_id"));
- if (oid != null) {
- dbDoc.put("_id", oid);
- }
- }
- }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("insert DBObject containing fields: " + dbDoc.keySet() + " in collection: " + collectionName);
}
@@ -645,22 +648,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
protected List insertDBObjectList(String collectionName, final List dbDocList) {
-
if (dbDocList.isEmpty()) {
return Collections.emptyList();
}
- // TODO: Need to move this to more central place
- for (DBObject dbDoc : dbDocList) {
- if (dbDoc.containsField("_id")) {
- if (dbDoc.get("_id") instanceof String) {
- ObjectId oid = convertIdValue(this.mongoConverter, dbDoc.get("_id"));
- if (oid != null) {
- dbDoc.put("_id", oid);
- }
- }
- }
- }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("insert list of DBObjects containing " + dbDocList.size() + " items");
}
@@ -690,20 +681,6 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
}
protected Object saveDBObject(String collectionName, final DBObject dbDoc) {
-
- if (dbDoc.keySet().isEmpty()) {
- return null;
- }
-
- // TODO: Need to move this to more central place
- if (dbDoc.containsField("_id")) {
- if (dbDoc.get("_id") instanceof String) {
- ObjectId oid = convertIdValue(this.mongoConverter, dbDoc.get("_id"));
- if (oid != null) {
- dbDoc.put("_id", oid);
- }
- }
- }
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("save DBObject containing fields: " + dbDoc.keySet());
}
@@ -824,9 +801,9 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DBObject dboq = mapper.getMappedObject(queryObject, entity);
WriteResult wr = null;
WriteConcern writeConcernToUse = prepareWriteConcern(writeConcern);
- if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("remove using query: " + queryObject + " in collection: " + collection.getName());
- }
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("remove using query: " + queryObject + " in collection: " + collection.getName());
+ }
if (writeConcernToUse == null) {
wr = collection.remove(dboq);
} else {
@@ -889,7 +866,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
DBCollection coll = db.createCollection(collectionName, collectionOptions);
// TODO: Emit a collection created event
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("Created collection [" + coll.getFullName() + "]");
+ LOGGER.debug("Created collection [" + coll.getFullName() + "]");
}
return coll;
}
@@ -1014,7 +991,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
if (idProp == null) {
throw new MappingException("No id property found for object of type " + entity.getType().getName());
}
-
+
ConversionService service = mongoConverter.getConversionService();
try {
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 8abc72a42..6d77dee5f 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
@@ -29,6 +29,11 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBObject;
+import com.mongodb.DBRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;
@@ -36,6 +41,7 @@ import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
+import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.data.document.mongodb.MongoDbFactory;
import org.springframework.data.document.mongodb.mapping.MongoPersistentEntity;
@@ -58,12 +64,6 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
-import com.mongodb.BasicDBList;
-import com.mongodb.BasicDBObject;
-import com.mongodb.DB;
-import com.mongodb.DBObject;
-import com.mongodb.DBRef;
-
/**
* {@link MongoConverter} that uses a {@link MappingContext} to do sophisticated mapping of domain objects to
* {@link DBObject}.
@@ -74,11 +74,11 @@ import com.mongodb.DBRef;
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
public static final String CUSTOM_TYPE_KEY = "_class";
-
+
private static final List> VALID_ID_TYPES = Arrays.asList(new Class>[]{ObjectId.class, String.class,
BigInteger.class, byte[].class});
protected static final Log log = LogFactory.getLog(MappingMongoConverter.class);
-
+
protected final MappingContext extends MongoPersistentEntity>, MongoPersistentProperty> mappingContext;
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
protected ApplicationContext applicationContext;
@@ -87,7 +87,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
/**
* Creates a new {@link MappingMongoConverter} given the new {@link MongoDbFactory} and {@link MappingContext}.
- *
+ *
* @param mongoDbFactory
* @param mappingContext
*/
@@ -188,41 +188,41 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
final List ctorParamNames = new ArrayList();
final MongoPersistentProperty idProperty = entity.getIdProperty();
-
+
ParameterValueProvider provider = new SpELAwareParameterValueProvider(spelExpressionParser, spelCtx) {
- @Override
- @SuppressWarnings("unchecked")
- public T getParameterValue(PreferredConstructor.Parameter parameter) {
-
- if (parameter.getKey() != null) {
- return super.getParameterValue(parameter);
- }
-
- String name = parameter.getName();
- TypeInformation type = parameter.getType();
- Class rawType = parameter.getRawType();
- String key = idProperty == null ? name : idProperty.getName().equals(name) ? idProperty.getFieldName() : name;
- Object obj = dbo.get(key);
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getParameterValue(PreferredConstructor.Parameter parameter) {
- ctorParamNames.add(name);
- if (obj instanceof DBRef) {
- return read(type, ((DBRef) obj).fetch());
- } else if (obj instanceof BasicDBList) {
- BasicDBList objAsDbList = (BasicDBList) obj;
- List> l = unwrapList(objAsDbList, type);
- return conversionService.convert(l, rawType);
- } else if (obj instanceof DBObject) {
- return read(type, ((DBObject) obj));
- } else if (null != obj && obj.getClass().isAssignableFrom(rawType)) {
- return (T) obj;
- } else if (null != obj) {
- return conversionService.convert(obj, rawType);
- }
+ if (parameter.getKey() != null) {
+ return super.getParameterValue(parameter);
+ }
+
+ String name = parameter.getName();
+ TypeInformation type = parameter.getType();
+ Class rawType = parameter.getRawType();
+ String key = idProperty == null ? name : idProperty.getName().equals(name) ? idProperty.getFieldName() : name;
+ Object obj = dbo.get(key);
+
+ ctorParamNames.add(name);
+ if (obj instanceof DBRef) {
+ return read(type, ((DBRef) obj).fetch());
+ } else if (obj instanceof BasicDBList) {
+ BasicDBList objAsDbList = (BasicDBList) obj;
+ List> l = unwrapList(objAsDbList, type);
+ return conversionService.convert(l, rawType);
+ } else if (obj instanceof DBObject) {
+ return read(type, ((DBObject) obj));
+ } else if (null != obj && obj.getClass().isAssignableFrom(rawType)) {
+ return (T) obj;
+ } else if (null != obj) {
+ return conversionService.convert(obj, rawType);
+ }
+
+ return null;
+ }
+ };
- return null;
- }
- };
-
final BeanWrapper, S> wrapper = BeanWrapper.create(entity, provider, conversionService);
// Set properties not already set in the constructor
@@ -325,19 +325,26 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
if (null == entity) {
throw new MappingException("No mapping metadata found for entity of type " + obj.getClass().getName());
}
-
+
final BeanWrapper, Object> wrapper = BeanWrapper.create(obj, conversionService);
// Write the ID
final MongoPersistentProperty idProperty = entity.getIdProperty();
if (!dbo.containsField("_id") && null != idProperty) {
- Object idObj;
- try {
- idObj = wrapper.getProperty(idProperty, Object.class, useFieldAccessOnly);
- } catch (IllegalAccessException e) {
- throw new MappingException(e.getMessage(), e);
- } catch (InvocationTargetException e) {
- throw new MappingException(e.getMessage(), e);
+ Object idObj = null;
+ Class>[] targetClasses = new Class>[]{ObjectId.class, Object.class};
+ for (int i = 0; i < targetClasses.length; i++) {
+ try {
+ idObj = wrapper.getProperty(idProperty, targetClasses[i], useFieldAccessOnly);
+ if (null != idObj) {
+ break;
+ }
+ } catch (ConversionException ignored) {
+ } catch (IllegalAccessException e) {
+ throw new MappingException(e.getMessage(), e);
+ } catch (InvocationTargetException e) {
+ throw new MappingException(e.getMessage(), e);
+ }
}
if (null != idObj) {
@@ -396,13 +403,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@SuppressWarnings({"unchecked"})
protected void writePropertyInternal(MongoPersistentProperty prop, Object obj, DBObject dbo) {
-
+
if (obj == null) {
return;
}
String name = prop.getFieldName();
-
+
if (prop.isCollection()) {
DBObject collectionInternal = writeCollectionInternal(prop, obj);
dbo.put(name, collectionInternal);
@@ -437,23 +444,23 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
writeInternal(obj, propDbObj, mappingContext.getPersistentEntity(prop.getTypeInformation()));
dbo.put(name, propDbObj);
}
-
+
@SuppressWarnings("unchecked")
protected DBObject writeCollectionInternal(MongoPersistentProperty property, Object obj) {
-
+
BasicDBList dbList = new BasicDBList();
Class> type = property.getType();
Collection