Quantcast
Channel: Spring Community Forums - Data
Viewing all articles
Browse latest Browse all 297

Spring mongo read conversion fails after bean modification

$
0
0
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>


Viewing all articles
Browse latest Browse all 297

Trending Articles