Announcement Announcement Module
Collapse
No announcement yet.
Spring mongo read conversion fails after bean modification Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring mongo read conversion fails after bean modification

    Sorry, but the new title should be :
    "Spring mongo read conversion fails for beans inside a map."

    I have a very strange situation where the read conversion fails after i persist the modified bean to mongodb. It causes *java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to kam.albert.lab.TestConversion$Person*

    So the errornous scenario is this :

    1. Create a SimpleObject and populate its map with a Person
    2. Store the simpleObject to mongo
    3. Find the simpleObject and get the Person instance from the map, which triggers *java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to kam.albert.lab.TestConversion$Person*

    So i assume, the read conversion for the Person seems to fail when reading the Person from inside a map, although the write conversion was successful when the first insertion happened. I can see in mongo that the data fields are correct as defined in the write converter.
    Also in another experiment, i put the Person not in the map, and all read and write conversion worked fine. It seems to be problematic when doing read-conversion only if we put this instance in a map.

    The source is provided below :

    Code:
        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");
        	}
        }
    And the test-conversion-context.xml

    Code:
        <?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>
    Last edited by albert_kam; Jul 15th, 2013, 04:53 AM.

  • #2
    Solved with hacks described in http://forum.springsource.org/showth...945#post450945

    Comment

    Working...
    X