DATAMONGO-550 - Fixed potential NullPointerExceptions in MongoTemplate.

Guarded access to results of mappingContext.getPersistentEntity(…) to prevent NullPointerExceptions in case the template is used with non-entity types like a plain DBObject. Added some custom logic for plain BasicDBObjects to get the _id field populated appropriately.
This commit is contained in:
Oliver Gierke
2012-10-15 11:00:12 -04:00
parent cabbe747f8
commit 66d98b355e
2 changed files with 53 additions and 6 deletions

View File

@@ -505,13 +505,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
public <T> T findById(Object id, Class<T> entityClass) { public <T> T findById(Object id, Class<T> entityClass) {
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass); return findById(id, entityClass, determineCollectionName(entityClass));
return findById(id, entityClass, persistentEntity.getCollection());
} }
public <T> T findById(Object id, Class<T> entityClass, String collectionName) { public <T> T findById(Object id, Class<T> entityClass, String collectionName) {
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass); MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(entityClass);
MongoPersistentProperty idProperty = persistentEntity.getIdProperty(); MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();
String idKey = idProperty == null ? ID : idProperty.getName(); String idKey = idProperty == null ? ID : idProperty.getName();
return doFindOne(collectionName, new BasicDBObject(idKey, id), null, entityClass); return doFindOne(collectionName, new BasicDBObject(idKey, id), null, entityClass);
} }
@@ -795,7 +794,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
assertUpdateableIdIfNotSet(objectToSave); assertUpdateableIdIfNotSet(objectToSave);
BasicDBObject dbDoc = new BasicDBObject(); DBObject dbDoc = new BasicDBObject();
maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave)); maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));
writer.write(objectToSave, dbDoc); writer.write(objectToSave, dbDoc);
@@ -982,7 +981,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
Assert.notNull(object); Assert.notNull(object);
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(object.getClass()); MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(object.getClass());
MongoPersistentProperty idProp = entity.getIdProperty(); MongoPersistentProperty idProp = entity == null ? null : entity.getIdProperty();
if (idProp == null) { if (idProp == null) {
throw new MappingException("No id property found for object of type " + entity.getType().getName()); throw new MappingException("No id property found for object of type " + entity.getType().getName());
@@ -1438,6 +1437,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
return; return;
} }
if (savedObject instanceof BasicDBObject) {
DBObject dbObject = (DBObject) savedObject;
dbObject.put(ID, id);
return;
}
MongoPersistentProperty idProp = getIdPropertyFor(savedObject.getClass()); MongoPersistentProperty idProp = getIdPropertyFor(savedObject.getClass());
if (idProp == null) { if (idProp == null) {
@@ -1555,7 +1560,8 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware {
} }
private MongoPersistentProperty getIdPropertyFor(Class<?> type) { private MongoPersistentProperty getIdPropertyFor(Class<?> type) {
return mappingContext.getPersistentEntity(type).getIdProperty(); MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(type);
return persistentEntity == null ? null : persistentEntity.getIdProperty();
} }
private <T> String determineEntityCollectionName(T obj) { private <T> String determineEntityCollectionName(T obj) {

View File

@@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.annotation.PersistenceConstructor;
@@ -63,6 +64,7 @@ import org.springframework.data.mongodb.core.query.Update;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection; import com.mongodb.DBCollection;
import com.mongodb.DBCursor; import com.mongodb.DBCursor;
import com.mongodb.DBObject; import com.mongodb.DBObject;
@@ -143,6 +145,7 @@ public class MongoTemplateTests {
template.dropCollection(TestClass.class); template.dropCollection(TestClass.class);
template.dropCollection(Sample.class); template.dropCollection(Sample.class);
template.dropCollection(MyPerson.class); template.dropCollection(MyPerson.class);
template.dropCollection("collection");
} }
@Test @Test
@@ -1352,6 +1355,44 @@ public class MongoTemplateTests {
template.save(null); template.save(null);
} }
/**
* @see DATAMONGO-550
*/
@Test
public void savesPlainDbObjectCorrectly() {
DBObject dbObject = new BasicDBObject("foo", "bar");
template.save(dbObject, "collection");
assertThat(dbObject.containsField("_id"), is(true));
}
/**
* @see DATAMONGO-550
*/
@Test(expected = InvalidDataAccessApiUsageException.class)
public void rejectsPlainObjectWithOutExplicitCollection() {
DBObject dbObject = new BasicDBObject("foo", "bar");
template.save(dbObject, "collection");
template.findById(dbObject.get("_id"), DBObject.class);
}
/**
* @see DATAMONGO-550
*/
@Test
public void readsPlainDbObjectById() {
DBObject dbObject = new BasicDBObject("foo", "bar");
template.save(dbObject, "collection");
DBObject result = template.findById(dbObject.get("_id"), DBObject.class, "collection");
assertThat(result.get("foo"), is(dbObject.get("foo")));
assertThat(result.get("_id"), is(dbObject.get("_id")));
}
static class MyId { static class MyId {
String first; String first;