我有一个非常奇怪的情况,在我将修改后的 bean 持久化到 mongodb 后,读取转换失败。它导致java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to kam.albert.lab.TestConversion$Person
所以错误的场景是这样的:
- 创建一个 SimpleObject 并使用 Person 填充其地图
- 将 simpleObject 存储到 mongo
- 找到simpleObject并从map中获取Person实例,触发java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to kam.albert.lab.TestConversion$Person
所以我假设,从地图内部读取 Person 时,Person 的读取转换似乎失败,尽管在第一次插入发生时写入转换成功。我可以在 mongo 中看到数据字段是正确的,如写转换器中定义的那样。同样在另一个实验中,我将 Person 不在地图中,并且所有读写转换都运行良好。仅当我们将此实例放在地图中时才进行读取转换似乎是有问题的。来源如下:
package kam.albert.lab;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
@Component
public class TestConversion {
@Autowired private MongoOperations ops;
public static class Person {
private String firstName, lastName;
public Person(String first, String last) {
this.firstName = first;
this.lastName = last;
}
}
public static class PersonWriteConverter implements Converter<Person, DBObject> {
@Override
public DBObject convert(Person person) {
DBObject dbObject = new BasicDBObject();
dbObject.put("first", person.firstName);
dbObject.put("last", person.lastName);
return dbObject;
}
}
public static class PersonReadConverter implements Converter<DBObject, Person> {
@Override
public Person convert(DBObject dbo) {
return new Person((String)dbo.get("first"), (String)dbo.get("last"));
}
}
public static class SimpleObject {
private String id = UUID.randomUUID().toString();
private Map<Object, Object> map = new HashMap<>();
public SimpleObject addPerson(String first, String last) {
this.map.put(String.valueOf(this.map.size()), new Person(first, last));
return this;
}
}
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"test-conversion-context.xml"
);
TestConversion bean = ctx.getBean(TestConversion.class);
bean.cleanup();
String id = bean.testWrite();
bean.testRead(id);
bean.testUpdate(id); // this causes the read below to fail
bean.testRead(id);
}
private void cleanup() {
this.ops.dropCollection("testconv");
}
private String testWrite() {
SimpleObject simpleObject = new SimpleObject();
simpleObject.addPerson("albert", "kam");
this.ops.insert(simpleObject, "testconv");
return simpleObject.id;
}
private void testRead(String id) {
SimpleObject simpleObject = this.ops.findById(id, SimpleObject.class, "testconv");
System.out.println("read success : " + simpleObject.map);
}
private void testUpdate(String id) {
SimpleObject simpleObject = this.ops.findById(id, SimpleObject.class, "testconv");
Person person = (Person) simpleObject.map.get("0"); // this causes exception !
person.firstName = "a new first name";
// simpleObject.addPerson("new", "person"); // this is fine
Update update = new Update().set("map", simpleObject.map);
this.ops.updateFirst(Query.query(Criteria.where("_id").is(id)), update, "testconv");
}
}
和 test-conversion-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd
http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<!-- default id = mongo, host = localhost, and port = 27017 no nested options
for now -->
<mongo:mongo>
<mongo:options />
</mongo:mongo>
<!-- to translate any exceptions from @Repository annotated classes -->
<context:annotation-config />
<mongo:db-factory dbname="glasswing" mongo-ref="mongo" />
<util:constant id="writeConcern" static-field="com.mongodb.WriteConcern.SAFE" />
<util:constant id="writeResultChecking" static-field="org.springframework.data.mongodb.core.WriteResultChecking.EXCEPTION" />
<bean id="ops" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="mappingConverter" />
<property name="writeConcern" ref="writeConcern" />
<property name="writeResultChecking" ref="writeResultChecking" />
</bean>
<mongo:mapping-converter base-package="kam.albert.domain.converter">
<mongo:custom-converters>
<mongo:converter><bean class="kam.albert.lab.TestConversion.PersonWriteConverter" /></mongo:converter>
<mongo:converter><bean class="kam.albert.lab.TestConversion.PersonReadConverter" /></mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>
<context:spring-configured />
<context:load-time-weaver/>
<bean id="testConversion" class="kam.albert.lab.TestConversion" />
</beans>