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 52c361e11..a1514a474 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 @@ -61,6 +61,7 @@ import org.springframework.data.mapping.model.MappingException; import org.springframework.data.mapping.model.PersistentEntity; import org.springframework.data.mapping.model.PersistentProperty; import org.springframework.data.mapping.model.PreferredConstructor; +import org.springframework.data.util.ClassTypeInformation; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -205,9 +206,11 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext if (null != applicationContext) { spelCtx.setBeanResolver(new BeanFactoryResolver(applicationContext)); } - String[] keySet = dbo.keySet().toArray(new String[]{}); - for (String key : keySet) { - spelCtx.setVariable(key, dbo.get(key)); + if (!(dbo instanceof BasicDBList)) { + String[] keySet = dbo.keySet().toArray(new String[]{}); + for (String key : keySet) { + spelCtx.setVariable(key, dbo.get(key)); + } } final List ctorParamNames = new ArrayList(); @@ -215,18 +218,21 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext public Object getParameterValue(PreferredConstructor.Parameter parameter) { String name = parameter.getName(); Class type = parameter.getType(); + ClassTypeInformation typeInfo = new ClassTypeInformation(type); Object obj = dbo.get(name); + + ctorParamNames.add(name); if (obj instanceof DBRef) { - ctorParamNames.add(name); return read(type, ((DBRef) obj).fetch()); + } else if (obj instanceof BasicDBList) { + BasicDBList objAsDbList = (BasicDBList) obj; + List l = unwrapList(objAsDbList, type); + return conversionService.convert(l, parameter.getRawType()); } else if (obj instanceof DBObject) { - ctorParamNames.add(name); return read(type, ((DBObject) obj)); } else if (null != obj && obj.getClass().isAssignableFrom(type)) { - ctorParamNames.add(name); return obj; } else if (null != obj) { - ctorParamNames.add(name); return conversionService.convert(obj, type); } @@ -300,7 +306,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext if (null == entity) { // Must not have explictly added this entity yet - entity = mappingContext.addPersistentEntity(obj.getClass()); + entity = mappingContext.addPersistentEntity(obj.getClass()); if (null == entity) { // We can't map this entity for some reason throw new MappingException("Unable to map entity " + obj); @@ -310,7 +316,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext // Write the ID final PersistentProperty idProperty = entity.getIdProperty(); if (!dbo.containsField("_id") && null != idProperty) { - Object idObj = null; + Object idObj; try { idObj = MappingBeanHelper.getProperty(obj, idProperty, Object.class, useFieldAccessOnly); } catch (IllegalAccessException e) { @@ -327,13 +333,13 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } } - + // Write the properties entity.doWithProperties(new PropertyHandler() { public void doWithPersistentProperty(PersistentProperty prop) { String name = prop.getName(); Class type = prop.getType(); - Object propertyObj = null; + Object propertyObj; try { propertyObj = MappingBeanHelper.getProperty(obj, prop, type, useFieldAccessOnly); } catch (IllegalAccessException e) { @@ -355,7 +361,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext public void doWithAssociation(Association association) { PersistentProperty inverseProp = association.getInverse(); Class type = inverseProp.getType(); - Object propertyObj = null; + Object propertyObj; try { propertyObj = MappingBeanHelper.getProperty(obj, inverseProp, type, useFieldAccessOnly); } catch (IllegalAccessException e) { @@ -419,8 +425,25 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext DBRef dbRef = createDBRef(propObjItem, dbref); dbList.add(dbRef); } else if (type.isArray() && MappingBeanHelper.isSimpleType(type.getComponentType())) { - dbList.add(propObjItem); - } else if (MappingBeanHelper.isSimpleType(propObjItem.getClass())) { + dbList.add(propObjItem); + } else if (propObjItem instanceof List) { + List propObjColl = (List) propObjItem; + ClassTypeInformation typeInfo = new ClassTypeInformation(propObjItem.getClass()); + while (typeInfo.isCollectionLike()) { + typeInfo = new ClassTypeInformation(typeInfo.getComponentType().getType()); + } + if (MappingBeanHelper.isSimpleType(typeInfo.getType())) { + dbList.add(propObjColl); + } else { + BasicDBList propNestedDbList = new BasicDBList(); + for (Object propNestedObjItem : propObjColl) { + BasicDBObject propDbObj = new BasicDBObject(); + write(propNestedObjItem, propDbObj); + propNestedDbList.add(propDbObj); + } + dbList.add(propNestedDbList); + } + } else if (MappingBeanHelper.isSimpleType(propObjItem.getClass())) { dbList.add(propObjItem); } else { BasicDBObject propDbObj = new BasicDBObject(); @@ -558,15 +581,15 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext 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()); + List items = new LinkedList(); for (int i = 0; i < dbObjList.size(); i++) { Object dbObjItem = dbObjList.get(i); if (dbObjItem instanceof DBRef) { - items[i] = read(prop.getComponentType(), ((DBRef) dbObjItem).fetch()); + items.add(read(prop.getComponentType(), ((DBRef) dbObjItem).fetch())); } else if (dbObjItem instanceof DBObject) { - items[i] = read(prop.getComponentType(), (DBObject) dbObjItem); + items.add(read(prop.getComponentType(), (DBObject) dbObjItem)); } else { - items[i] = dbObjItem; + items.add(dbObjItem); } } List itemsToReturn = new LinkedList(); @@ -612,25 +635,23 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } + protected List unwrapList(BasicDBList dbList, Class targetType) { + List rootList = new LinkedList(); + for (int i = 0; i < dbList.size(); i++) { + Object obj = dbList.get(i); + if (obj instanceof BasicDBList) { + rootList.add(unwrapList((BasicDBList) obj, targetType)); + } else if (obj instanceof DBObject) { + rootList.add(read(targetType, (DBObject) obj)); + } else { + rootList.add(obj); + } + } + return rootList; + } + public void afterPropertiesSet() { initializeConverters(); } - protected class PersistentPropertyWrapper { - private final PersistentProperty property; - private final DBObject target; - - public PersistentPropertyWrapper(PersistentProperty property, DBObject target) { - this.property = property; - this.target = target; - } - - public PersistentProperty getProperty() { - return property; - } - - public DBObject getTarget() { - return target; - } - } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/LoggingEventListener.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/LoggingEventListener.java index cf37b14c0..6ba577458 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/LoggingEventListener.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/mapping/event/LoggingEventListener.java @@ -25,31 +25,34 @@ import org.apache.commons.logging.LogFactory; */ public class LoggingEventListener extends AbstractMappingEventListener { - private Log log = LogFactory.getLog(getClass()); + private Log log = LogFactory.getLog(getClass()); - @Override - public void onBeforeConvert(Object source) { - log.info("onBeforeConvert: " + source); - } + @Override + public void onBeforeConvert(Object source) { + log.info("onBeforeConvert: " + source); + } - @Override - public void onBeforeSave(Object source, DBObject dbo) { - log.info("onBeforeSave: " + source + ", " + dbo); - } + @Override + public void onBeforeSave(Object source, DBObject dbo) { + try { + log.info("onBeforeSave: " + source + ", " + dbo); + } catch (Throwable ignored) { + } + } - @Override - public void onAfterSave(Object source, DBObject dbo) { - log.info("onAfterSave: " + source + ", " + dbo); - } + @Override + public void onAfterSave(Object source, DBObject dbo) { + log.info("onAfterSave: " + source + ", " + dbo); + } - @Override - public void onAfterLoad(DBObject dbo) { - log.info("onAfterLoad: " + dbo); - } + @Override + public void onAfterLoad(DBObject dbo) { + log.info("onAfterLoad: " + dbo); + } - @Override - public void onAfterConvert(DBObject dbo, Object source) { - log.info("onAfterConvert: " + dbo + ", " + source); - } + @Override + public void onAfterConvert(DBObject dbo, Object source) { + log.info("onAfterConvert: " + dbo + ", " + source); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java index 4cbe0e56a..76859c95a 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/MappingTests.java @@ -54,6 +54,8 @@ public class MappingTests { "personmapproperty", "personpojo", "personcustomidname", + "personmultidimarrays", + "personmulticollection", "person1", "person2", "account" @@ -262,4 +264,39 @@ public class MappingTests { })); } + @Test + public void testMultiDimensionalArrayProperties() { + String[][] grid = new String[][]{ + new String[]{"1", "2", "3", "4"}, + new String[]{"5", "6", "7", "8"}, + new String[]{"9", "10", "11", "12"} + }; + PersonMultiDimArrays p = new PersonMultiDimArrays(123, "Multi", "Dimensional", grid); + + template.insert(p); + List result = template.find(new Query(Criteria.where("ssn").is(123)), PersonMultiDimArrays.class); + assertThat(result.size(), is(1)); + + assertThat(result.get(0).getGrid().length, is(3)); + } + + @Test + public void testMultiDimensionalCollectionProperties() { + List> grid = new ArrayList>(); + ArrayList inner = new ArrayList(); + inner.add("1"); + inner.add("2"); + inner.add("3"); + inner.add("4"); + grid.add(inner); + + PersonMultiCollection p = new PersonMultiCollection(321, "Multi Dim", "Collections", grid); + template.insert(p); + + List result = template.find(new Query(Criteria.where("ssn").is(321)), PersonMultiCollection.class); + assertThat(result.size(), is(1)); + + assertThat(result.get(0).getGrid().size(), is(1)); + } + } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMultiCollection.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMultiCollection.java new file mode 100644 index 000000000..7f45ec6c1 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMultiCollection.java @@ -0,0 +1,40 @@ +/* + * 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.List; + +/** + * @author Jon Brisbin + */ +public class PersonMultiCollection extends BasePerson { + + private List> grid; + + public PersonMultiCollection(Integer ssn, String firstName, String lastName, List> grid) { + super(ssn, firstName, lastName); + this.grid = grid; + } + + public List> getGrid() { + return grid; + } + + public void setGrid(List> grid) { + this.grid = grid; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMultiDimArrays.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMultiDimArrays.java new file mode 100644 index 000000000..68cd3d6a8 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMultiDimArrays.java @@ -0,0 +1,38 @@ +/* + * 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; + +/** + * @author Jon Brisbin + */ +public class PersonMultiDimArrays extends BasePerson { + + private String[][] grid; + + public PersonMultiDimArrays(Integer ssn, String firstName, String lastName, String[][] grid) { + super(ssn, firstName, lastName); + this.grid = grid; + } + + public String[][] getGrid() { + return grid; + } + + public void setGrid(String[][] grid) { + this.grid = grid; + } +}