zamza
zamza

Reputation: 337

How to get a properly typed List from a ReflectionDBObject

I have a model classes like

public class MyClass extends ReflectionDBObject {
    private List<NiceAttribute> attributes;    
    ...
}

public class NiceAttribute extends ReflectionDBObject {
    ...
}

I create it in a typesafe way, like

List<NiceAttribute> attrs = new ArrayList<NiceAttribute>();
attrs.add(new NiceAttribute());
MyClass myClass = new MyClass();
myClass.setAttributes(attrs);

then save it to mongo, and retrieve with a code like

DBCollection col = ...;
col.setObjectClass(MyClass.class)
MyClass foundObject = (MyClass)col.findOne();

But the problem is that foundObject's attributes becomes a list of BasicDBObject. Looks like a driver can not (or does not want to) detect a list items type. Is this a driver limitation, or I missed something? What would be an elegant workaround for the problem?

BTW, I know about Morphia etc. Maybe it solves the problem. But my project is tiny, and I don't want to complicate things having one more layer of abstraction.

Upvotes: 5

Views: 1144

Answers (2)

Shivan Dragon
Shivan Dragon

Reputation: 15219

Well, there is a solution, but you're not gonna like it. Basically you can specify the corresponding class for an internal path within your object. Here's what I did, and it works:

public class Release extends ReflectionDBObject {

    //other fields omitted    

    private List<ReleaseDetailsByTerritory> releaseDetailsByTerritory = new ArrayList<ReleaseDetailsByTerritory>();

}

public class ReleaseDetailsByTerritory extends ReflectionDBObject { //...}

Now, if I simply do this:

    releaseColl.setObjectClass(Release.class);
    releaseColl.setInternalClass("ReleaseDetailsByTerritory.0", ReleaseDetailsByTerritory.class);
    Release r = (Release) releaseColl.findOne();
    //the internal list will contain ReleaseDetailsByTerritory type objects (not DBObjects)
    System.out.println(r.getReleaseDetailsByTerritory().get(0).getClass().getName());

The crappy thing here is that you can't (or at least I haven't found how) to specify the mapping class for ALL the elements of an embedded array. You CANNOT do something like:

releaseColl.setInternalClass("ReleaseDetailsByTerritory", ReleaseDetailsByTerritory.class);

or

releaseColl.setInternalClass("ReleaseDetailsByTerritory.*", ReleaseDetailsByTerritory.class);

You have instead to specify the mapping class of any possible element of the embedded array:

releaseColl.setInternalClass("ReleaseDetailsByTerritory.0", ReleaseDetailsByTerritory.class);
releaseColl.setInternalClass("ReleaseDetailsByTerritory.1", ReleaseDetailsByTerritory.class);
releaseColl.setInternalClass("ReleaseDetailsByTerritory.2", ReleaseDetailsByTerritory.class);

Upvotes: 4

Scott Hernandez
Scott Hernandez

Reputation: 7590

You should use Morphia. It adds support for POJOs and embedded objects (and collections). It doesn't have any of the limitations the driver does about requiring your classes to look like a Map<String, Object>.

Upvotes: -1

Related Questions