Announcement Announcement Module
Collapse
No announcement yet.
Problem with insertion of Map as generic type of domain object. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem with insertion of Map as generic type of domain object.

    Hi,

    I'm issuing a problem with the saving of a Map as generic type of one of my domain object.

    Here is an example.

    I have a generic domain object as :
    Code:
    public class A<T> {
     String valueType;
     private T value;
     public A (T value) {
      valueType = value.getClass().getName();
      this.value = value;
     }
    \\...
    }
    When I try this code :
    Code:
    Map<String,A<?>> objectToSave = new HashMap<String, A<?>>();
    objectToSave.put("test", new A<String>("testValue"));
    mongoTemplate.save(objectToSave,A_COL);
    Everything work as planned and if I query my database here is what I obtain :
    Code:
    {
            "_id" : ObjectId("4ea9098fd0abf79d588e4696"),
            "_class" : "java.util.HashMap",
            "test" : {
                    "valueType" : "java.lang.String",
                    "value" : "testValue",
                    "_class" : "foo.bar.A"
            }
    }
    But now if I insert the sameobject as value of my domain type like :
    Code:
    A<Map<String,A<?>>> a= new A<Map<String,A<?>>>(objectToSave);
    mongoTemplate.save(a,A_COL);
    Here is what is inserted in db :
    Code:
    {
            "_id" : ObjectId("4ea90998d0abf79d588e4697"),
            "_class" : "foo.bar.A",
            "valueType" : "java.util.HashMap",
            "value" : {
                    "_class" : "java.util.HashMap",
                    "threshold" : 12,
                    "loadFactor" : 0.75
            }
    }
    Where instead of having as value the items from the Map, I only have meta-information about my map...

    I don't know where this problem come from. I suppose it's from the object mapper of spring data mongodb...

    Thanks for any help,

  • #2
    A little help on this topic would be usefull.
    I didn't find out any solution.

    Thanks for any attempt

    Comment


    • #3
      Up!

      Up!

      Sorry to up this thread but this problem is quite blocking.
      Any idea ?

      Comment


      • #4
        Is there a chance you can add a quick test case to MappingMongoConverterUnitTests or simply drop the relevant snippet here so that I can start investigating what's going wrong here? I suspect the fact that you don't explicitly declare a typing class makes it impossible to discover generics at runtime as we can only lookup raw type information from the values given.

        Comment


        • #5
          I'm not quite sure of what is needed here but I'll provide what I can.

          Here is how to reproduce the bug. I tried by specifically setting the type of A, but this don't work either.

          I've added the id of the persisted element for more readability.
          Code:
                  @Autowired
          	protected transient MongoTemplate mongoTemplate;
          
          	/**
          	 * {@inheritDoc}
          	 */
          	@Override
          	public void save() {
          		List<B> bs = new ArrayList<B>();
          		B b = new B();
          		b.addA("test", new A<String>("testValue"));
          		b.addA("testInt", new A<Integer>(42));
          		bs.add(b);
          
          		C c = new C(Bs);
          
          		mongoTemplate.save(c, "cs");
          // id = 4ebbab5ad0ab5ef4ac6b0531
          
          		Map<String, A<String>> objectToSave = new HashMap<String, A<String>>();
          		objectToSave.put("test", new A<String>("testValue"));
          		mongoTemplate.save(objectToSave, "cs");
          // id = 4ebbae36d0ab5ef4ac6b0532
          
          		A<Map<String, A<String>>> a = new A<Map<String, A<String>>>(objectToSave);
          		mongoTemplate.save(a, "cs");
          // id = 4ebbae36d0ab5ef4ac6b0533
          	}
          C is an object having a list of B which has a Map of A and this map is persisted as expected
          Code:
          @Document
          public class C implements Serializable {
          
          	@Id
          	private ObjectId id;
          
          	private List<B> bs;
          
          	public C(List<B> bs) {
          		this.bs = bs;
          	}
          }
          The B domain object :
          Code:
          public class B implements Serializable {
          
          	private Map<String, A<?>> as;
          
          	public B(Map<String, A<?>> as) {
          		this.as = as;
          	}
          
          	public void addA(String aKey, A<?> a) {
          		as.put(aKey, a);
          	}
          }
          the A domain object :
          Code:
          public class A<T> implements Serializable {
          
          	private String valueType;
          	private T value;
          
          	public A(T value) {
          		this.valueType = value.getClass().getName();
          		this.value = value;
          	}
          }
          Code:
          { "_id" : ObjectId("4ebbab5ad0ab5ef4ac6b0531"), "_class" : "foo.bar.C", "bs" : [    {       "as" : {    "test" : {       "valueType" : "java.lang.String",       "value" : "testValue" },      
          "testInt" : {  "valueType" : "java.lang.Integer",      "value" : 42 } } } ] }
          { "_id" : ObjectId("4ebbae34d0ab5ef4ac6b0532"), "_class" : "java.util.HashMap", "test" : { "valueType" : "java.lang.String", "value" : "testValue", "_class" : "foo.bar.A" } }
          { "_id" : ObjectId("4ebbae36d0ab5ef4ac6b0533"), "_class" : "foo.bar.A", "valueType" : "java.util.HashMap", "value" : { "_class" : "java.util.HashMap", "threshold" : 12, "loadFactor"
          : 0.75 } }
          I hope this is sufficient. Otherwise don't hesitate to ask.

          And thanks for taking time to answer.
          Last edited by ogoletti; Nov 10th, 2011, 06:07 AM.

          Comment


          • #6
            https://jira.springsource.org/browse/DATAMONGO-329

            Comment


            • #7
              Should be fixed in the current build snapshot.

              Comment


              • #8
                It's working fine. Thanks a lot!

                Comment


                • #9
                  Saving a HashMap works fine, but reading the HashMap back in Java does not work. The object returned is of type java.lang.Object where it should be java.util.HashMap.
                  Before the patch a HashMap was saved with the element _class="java.util.HashMap" but without data. With this patch all map elements are saved in the mongo database but the _class element is missing. When I add it to the database manually, I am able to retrieve the HashMap using the spring-datat-mongo library.
                  Code:
                                  "fieldComplex" : {
                                          "value" : {
                                                  "_class" : "java.util.HashMap",
                                                  "elem1" : {
                                                          "valueType" : "java.lang.String",
                                                          "value" : "testValue1",
                                                          "_class" : "foo.bar.A"
                                                  }
                                                  "elem2" : {
                                                          "valueType" : "java.lang.String",
                                                          "value" : "testValue2",
                                                          "_class" : "foo.bar.A"
                                                  }
                                          },
                                          "valueType" : "java.util.HashMap"
                                  }
                  Can the _class be added again ?
                  Thanks

                  Comment


                  • #10
                    The same problem occurs with an ArrayList...
                    In fact, for each generic type saved, it seems that the mapping is not correctly done.
                    There should be a "_class" field with the corresponding class in order for the mapper to be able to map correctly the json.

                    In fact, adding this field by hand solves the problem and allows the mapper to do its work as expected.

                    Do I need to report this in JIRA?

                    Thanks for the help
                    Last edited by ogoletti; Dec 20th, 2011, 06:13 AM.

                    Comment


                    • #11
                      While this workaround works for a map to add "by hand" in mongodb the key "_class" and the value "java.util.HashMap". For an array it isn't possible.

                      The mapper don't even recognize the array structure of the json "[ ]". It should map it automatically to an ArrayList, without any problem.

                      Indeed in such a scenario :

                      Code:
                      final ArrayList<String> list = new ArrayList<String>();
                      list.add("foobar");
                      A<ArrayList<String>> a = new A<ArrayList<String>> (list);
                      mongoTemplate.save(a, "test");
                      final List<A> findAll = mongoTemplate.findAll(A.class, "test");
                      A.getValue() is only an unreadable Object!!!

                      even if the mongo json result is :
                      Code:
                      { "_id" : ObjectId("4ef1f49dc46a3d6b2d9269ef"), "_class" : "foo.bar.A", "valueType" : "java.util.ArrayList", "value" : [ "foobar" ] }
                      If the query is mapped on a BasicDBObject, the array is well recognized as a BasicDBList... so I don't understand why it is not mapped on an ArrayList.

                      Thanks for any help!

                      Comment

                      Working...
                      X