From c365830b2cc11074ee31d222f70ef8f21be0eae5 Mon Sep 17 00:00:00 2001 From: "J. Brisbin" Date: Sat, 12 Mar 2011 20:03:23 -0600 Subject: [PATCH] Fixes for bug skipping fields in superclasses --- spring-data-mongodb/pom.xml | 1 - .../convert/MappingMongoConverter.java | 55 ++++++++++++--- .../document/mongodb/mapping/AccountPojo.java | 47 +++++++++++++ .../document/mongodb/mapping/BasePerson.java | 57 +++++++++++++++ .../mongodb/mapping/MappingTests.java | 49 +++++++++++-- .../data/document/mongodb/mapping/Person.java | 4 ++ .../mongodb/mapping/PersonCustomIdName.java | 70 +++++++++++++++++++ .../mongodb/mapping/PersonMapProperty.java | 52 ++++++++++++++ .../document/mongodb/mapping/PersonPojo.java | 68 ++++++++++++++++++ .../src/test/resources/mapping.xml | 16 ++--- 10 files changed, 396 insertions(+), 23 deletions(-) create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/AccountPojo.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/BasePerson.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonCustomIdName.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java create mode 100644 spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonPojo.java diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 5b8f79776..eadec1a70 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -36,7 +36,6 @@ org.springframework.data spring-data-document-core - 1.0.0.BUILD-SNAPSHOT org.springframework.data 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 9d429b993..52aba45af 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 @@ -24,6 +24,7 @@ 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.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -40,12 +41,9 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; /** * @author Jon Brisbin @@ -54,7 +52,6 @@ import java.util.concurrent.ConcurrentMap; public class MappingMongoConverter implements MongoConverter, ApplicationContextAware { protected static final Log log = LogFactory.getLog(MappingMongoConverter.class); - protected static final ConcurrentMap, Map> fieldsByName = new ConcurrentHashMap, Map>(); protected GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); protected SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); @@ -223,6 +220,13 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext if (null != applicationContext && autowirePersistentBeans) { applicationContext.getAutowireCapableBeanFactory().autowireBean(instance); } + if (instance instanceof InitializingBean) { + try { + ((InitializingBean) instance).afterPropertiesSet(); + } catch (Exception e) { + throw new MappingException(e.getMessage(), e); + } + } return instance; } @@ -281,7 +285,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } if (null != propertyObj) { if (prop.isComplexType()) { - writeObjectInternal(prop, propertyObj, dbo); + writePropertyInternal(prop, propertyObj, dbo); } else { dbo.put(name, propertyObj); } @@ -302,7 +306,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext throw new MappingException(e.getMessage(), e); } if (null != propertyObj) { - writeObjectInternal(inverseProp, propertyObj, dbo); + writePropertyInternal(inverseProp, propertyObj, dbo); } } }); @@ -323,7 +327,7 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } - protected void writeObjectInternal(PersistentProperty prop, Object obj, DBObject dbo) { + 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(); @@ -344,6 +348,10 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } dbo.put(name, dbList); + } else if (null != obj && obj instanceof Map) { + BasicDBObject mapDbObj = new BasicDBObject(); + writeMapInternal((Map) obj, mapDbObj); + dbo.put(name, mapDbObj); } else { if (null != dbref) { DBObject dbRefObj = createDBRef(obj, dbref); @@ -358,6 +366,26 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext } } + protected void writeMapInternal(Map obj, DBObject dbo) { + Set simpleTypes = MappingBeanHelper.getSimpleTypes(); + for (Map.Entry entry : obj.entrySet()) { + Object key = entry.getKey(); + Object val = entry.getValue(); + if (simpleTypes.contains(key.getClass().getName())) { + String simpleKey = conversionService.convert(key, String.class); + if (simpleTypes.contains(val.getClass().toString())) { + dbo.put(simpleKey, val); + } else { + DBObject newDbo = new BasicDBObject(); + write(val, newDbo); + dbo.put(simpleKey, newDbo); + } + } else { + throw new MappingException("Cannot use a complex object as a key value."); + } + } + } + protected DBObject createDBRef(Object target, org.springframework.data.document.mongodb.mapping.DBRef dbref) { PersistentEntity targetEntity = mappingContext.getPersistentEntity(target.getClass()); if (null == targetEntity || null == targetEntity.getIdProperty()) { @@ -404,7 +432,18 @@ public class MappingMongoConverter implements MongoConverter, ApplicationContext Object dbObj = from.get(name); if (dbObj instanceof DBObject) { Class type = prop.getType(); - if (type.isArray() && dbObj instanceof BasicDBObject && ((DBObject) dbObj).keySet().size() == 0) { + if (type.isAssignableFrom(Map.class) && dbObj instanceof DBObject) { + Map m = new LinkedHashMap(); + for (Map.Entry entry : ((Map) ((DBObject) dbObj).toMap()).entrySet()) { + if (null != entry.getValue() + && MappingBeanHelper.getSimpleTypes().contains(entry.getValue().getClass().getName())) { + m.put(entry.getKey(), entry.getValue()); + } else if (null != entry.getValue()) { + m.put(entry.getKey(), entry.getValue()); + } + } + return m; + } else if (type.isArray() && dbObj instanceof BasicDBObject && ((DBObject) dbObj).keySet().size() == 0) { // It's empty return Array.newInstance(type.getComponentType(), 0); } else if (prop.isCollection() && dbObj instanceof BasicDBList) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/AccountPojo.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/AccountPojo.java new file mode 100644 index 000000000..71b83875f --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/AccountPojo.java @@ -0,0 +1,47 @@ +/* + * 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 AccountPojo { + + private String type; + private Float balance; + + public AccountPojo(String type, Float balance) { + this.type = type; + this.balance = balance; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Float getBalance() { + return balance; + } + + public void setBalance(Float balance) { + this.balance = balance; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/BasePerson.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/BasePerson.java new file mode 100644 index 000000000..c3f32b8ef --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/BasePerson.java @@ -0,0 +1,57 @@ +/* + * 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 BasePerson { + + private Integer ssn; + private String firstName; + private String lastName; + + public BasePerson(Integer ssn, String firstName, String lastName) { + this.ssn = ssn; + this.firstName = firstName; + this.lastName = lastName; + } + + public Integer getSsn() { + return ssn; + } + + public void setSsn(Integer ssn) { + this.ssn = ssn; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} 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 78eaa2a2c..56d6bce2f 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 @@ -22,7 +22,6 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.document.mongodb.MongoTemplate; -import org.springframework.data.document.mongodb.convert.MongoConverter; import org.springframework.data.document.mongodb.query.Criteria; import org.springframework.data.document.mongodb.query.Query; import org.springframework.data.mapping.BasicMappingContext; @@ -30,7 +29,9 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -58,9 +59,47 @@ public class MappingTests { template.dropCollection("account"); } - @SuppressWarnings({"unchecked"}) @Test - public void testWrite() { + public void testPersonPojo() { + PersonPojo p = new PersonPojo(12345, "Person", "Pojo"); + template.insert(p); + + assertNotNull(p.getId()); + } + + @Test + public void testPersonWithCustomIdName() { + PersonCustomIdName p = new PersonCustomIdName(123456, "Custom", "Id"); + template.insert(p); + + List result = template.find(new Query(Criteria.where("ssn").is(123456)), PersonCustomIdName.class); + assertThat(result.size(), is(1)); + } + + @Test + public void testPersonMapProperty() { + PersonMapProperty p = new PersonMapProperty(1234567, "Map", "Property"); + Map accounts = new HashMap(); + + AccountPojo checking = new AccountPojo("checking", 1000.0f); + AccountPojo savings = new AccountPojo("savings", 10000.0f); + + accounts.put("checking", checking); + accounts.put("savings", savings); + p.setAccounts(accounts); + + template.insert(p); + assertNotNull(p.getId()); + + List result = template.find(new Query(Criteria.where("ssn").is(1234567)), PersonMapProperty.class); + assertThat(result.size(), is(1)); + assertThat(result.get(0).getAccounts().size(), is(2)); + assertNotNull(result.get(0).getAccounts().get("checking")); + } + + @Test + @SuppressWarnings({"unchecked"}) + public void testWriteEntity() { Person p = new Person(123456789, "John", "Doe", 37); Address addr = new Address(); @@ -84,9 +123,7 @@ public class MappingTests { } @Test - public void testRead() { - MongoConverter converter = template.getConverter(); - + public void testReadEntity() { List result = template.find(new Query(Criteria.where("ssn").is(123456789)), Person.class); assertThat(result.size(), is(1)); assertThat(result.get(0).getAddress().getCountry(), is("USA")); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java index 375c1ea60..e2f61d6e9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/Person.java @@ -16,9 +16,11 @@ package org.springframework.data.document.mongodb.mapping; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.annotation.Transient; +import org.springframework.data.document.mongodb.MongoTemplate; import org.springframework.data.document.mongodb.index.CompoundIndex; import org.springframework.data.document.mongodb.index.CompoundIndexes; import org.springframework.data.document.mongodb.index.Indexed; @@ -47,6 +49,8 @@ public class Person { @DBRef private List accounts; private T address; + @Autowired + private MongoTemplate mongoTemplate; public Person(Integer ssn, String firstName, String lastName, Integer age) { this.ssn = ssn; diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonCustomIdName.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonCustomIdName.java new file mode 100644 index 000000000..728e438d8 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonCustomIdName.java @@ -0,0 +1,70 @@ +/* + * 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 org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; + +/** + * @author Jon Brisbin + */ +public class PersonCustomIdName { + + @Id + private ObjectId customId; + private Integer ssn; + private String firstName; + private String lastName; + + public PersonCustomIdName(Integer ssn, String firstName, String lastName) { + this.ssn = ssn; + this.firstName = firstName; + this.lastName = lastName; + } + + public ObjectId getCustomId() { + return customId; + } + + public void setCustomId(ObjectId customId) { + this.customId = customId; + } + + public Integer getSsn() { + return ssn; + } + + public void setSsn(Integer ssn) { + this.ssn = ssn; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java new file mode 100644 index 000000000..417427727 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonMapProperty.java @@ -0,0 +1,52 @@ +/* + * 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 org.bson.types.ObjectId; + +import java.util.Map; + +/** + * @author Jon Brisbin + */ +@Document +public class PersonMapProperty extends BasePerson { + + private ObjectId id; + private Map accounts; + + public PersonMapProperty(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } + + public Map getAccounts() { + return accounts; + } + + public void setAccounts(Map accounts) { + this.accounts = accounts; + } + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonPojo.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonPojo.java new file mode 100644 index 000000000..d6d5968c6 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/mapping/PersonPojo.java @@ -0,0 +1,68 @@ +/* + * 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 org.bson.types.ObjectId; + +/** + * @author Jon Brisbin + */ +public class PersonPojo { + + private ObjectId id; + private Integer ssn; + private String firstName; + private String lastName; + + public PersonPojo(Integer ssn, String firstName, String lastName) { + this.ssn = ssn; + this.firstName = firstName; + this.lastName = lastName; + } + + public ObjectId getId() { + return id; + } + + public void setId(ObjectId id) { + this.id = id; + } + + public Integer getSsn() { + return ssn; + } + + public void setSsn(Integer ssn) { + this.ssn = ssn; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/spring-data-mongodb/src/test/resources/mapping.xml b/spring-data-mongodb/src/test/resources/mapping.xml index d6b68a1d9..010431b54 100644 --- a/spring-data-mongodb/src/test/resources/mapping.xml +++ b/spring-data-mongodb/src/test/resources/mapping.xml @@ -8,6 +8,14 @@ + + + + + + + + @@ -20,14 +28,6 @@ - - - - - - - -