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

StackOverflow https://stackoverflow.com/questions/21860258

  •  13-10-2022
  •  | 
  •  

Question

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.

Était-ce utile?

La 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
                            } 
                } ]
}

Autres conseils

So here's what's going on. Morphia will attempt to serialize any non-transient, non-static field on a class. Now if that field is of a type annotated with @Entity, morphia will go through and introspect things and set up proper mappings. If not, it will some default basic serializers when constructing the DBObjects to hand over to the Java driver. In this case, you have a raw type (Object) and morphia has to make certain assumptions as to its type and structure. Upon finding out that your structure violates those assumptions, it bails. This is why it works when you break things out like Alex has shown. This is probably fixable in one way or another but as I'm planning on redoing the mapping code top to bottom, I don't foresee trying to fix this in the current code. Hope this helps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top