Search code examples
javamongodbmorphia

Morphia List<Map<String,Object>>> return Embedded element isn't a DBObject on find operation


I have tried to do something like this:

package org.dnylabs.kosh.data;

import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Id;
import com.mongodb.Mongo;
import com.mongodb.MongoException;

@Entity
public class Temp {
    @Id String _id;
    List<Map<String,Object>> strings;

    public Temp(){
        strings=new LinkedList<Map<String,Object>>();
    }


    public static void main(String []args) throws UnknownHostException, MongoException{
        Mongo mongo=null;
        Morphia morphia=null;
        Datastore ds=null;
        mongo = new Mongo();
        morphia = new Morphia();
        morphia.map(Temp.class);
        ds = morphia.createDatastore(mongo, "test");
        Temp t = new Temp();
        t._id ="hi";
        Map<String, Object> m = new HashMap<String, Object>();
        m.put("Hi","1");
        m.put("Hi2",2);
        t.strings.add(m);
        ds.save(t);
        t=ds.get(t);
        ds.ensureIndexes();
    }
}

When I try to do a findAll(9 operation I get this exception:

Caused by: java.lang.RuntimeException: org.mongodb.morphia.mapping.MappingException: Embedded element isn't a DBObject! How can it be that is a class java.lang.String
at org.mongodb.morphia.mapping. here`dedMapper.fromDBObject(EmbeddedMapper.java:172)
at org.mongodb.morphia.mapping.Mapper.readMappedField(Mapper.java:602)
at org.mongodb.morphia.mapping.Mapper.fromDb(Mapper.java:559)
at org.mongodb.morphia.mapping.EmbeddedMapper.readMapOrCollectionOrEntity(EmbeddedMapper.java:256)
at org.mongodb.morphia.mapping.EmbeddedMapper.readCollection(EmbeddedMapper.java:203)
at org.mongodb.morphia.mapping.EmbeddedMapper.fromDBObject(EmbeddedMapper.java:144)
... 16 more

After numerous attempts I have found that the problem is the grafted map.

Can anyone help me understand where I'm wrong? The statement seems correct.


Solution

  • Morphia sees Map as a DB reference to another document rather than seeing it as an embedded class and treating as a document. The solution would be to annotate the Map @Embedded, but this is not possible as you can't edit the Map class.

    There is a way to achieve something similar to what you are trying by creating another class and defining the Map as a property of this class and annotate it as @Embedded.

    Change the Temp class:

    public class Temp {
        @Id String _id;
    
        @Embedded // CHANGE HERE
        List<MapProxy> strings; // CHANGE HERE
    
        public Temp(){
            strings=new LinkedList<MapProxy>(); // CHANGE HERE
        }
    
        public static void main(String...args) throws UnknownHostException, MongoException{
            Mongo mongo=null;
            Morphia morphia=null;
            Datastore ds=null;
            mongo = new Mongo();
            morphia = new Morphia();
            morphia.map(Temp.class);
            ds = morphia.createDatastore(mongo, "test2");
            Temp t = new Temp();
            t._id ="hi";      
            MapProxy mp = new MapProxy(); // CHANGE HERE    
            mp.m.put("Hi","1"); // CHANGE HERE
            mp.m.put("Hi2",2); // CHANGE HERE
            t.strings.add(mp); // CHANGE HERE
            ds.save(t);
            t=ds.get(t);
            ds.ensureIndexes();
        }
    }
    

    and create a new class:

    @Embedded
    public class MapProxy {
        public Map<String,Object> m = new HashMap<String, Object>();
    
    }
    

    I have marked the changes I have made.

    The structure that this produces is like this:

    {
        "_id" : "hi",
        "className" : "YOUR CLASS NAME HERE",
        "strings" : 
                    [ { 
                         "m" : 
                                { 
                                    "Hi" : "1" , 
                                    "Hi2" : 2
                                } 
                    } ]
    }