Search code examples
javamongodbjdodatanucleus

Datanucleus/mongodb: Persisting map of lists


I'm using datanucleus 3.2.5 / JDO for persisting objects to a MongoDB database.

While trying to persist one map of lists I'm getting the following exception:

RuntimeException: json can't serialize type [list element type here]

Some sample code:

@PersistenceCapable
public class SomeClass {
    private Map<String, List<SomeOtherClass>> myAttribute;
    // ...
}


@PersistenceCapable(embeddedOnly="true")
public class SomeOtherClass {
    private String attribute;
    // ...
}

I could get around this problem annotating the embedded attribute as @Serialized, but I would rather prefer a more elegant way.

Am I missing anything? Is there a better approach to this issue?


Solution

  • Quoting Andy's reply to my question in the DataNucleus forums:

    No persistence spec defines any support for a container of a container. You are always recommended to make the inner container (List in your case) a field of an intermediate class.

    So there are two approaches here:

    Use an intermediate class

    By far the most elegant and maintainable solution. Following the example toy code:

    @PersistenceCapable
    public class SomeClass {
        private Map<String, SomeOtherClassContainer> myAttribute;
        // ...
    }
    
    @PersistenceCapable(embeddedOnly="true")
    public class SomeClassContainer {
        private List<SomeOtherClass> myAttribute;
        // ...
    }
    
    @PersistenceCapable(embeddedOnly="true")
    public class SomeOtherClass {
        private String attribute;
        // ...
    }
    

    Mark the attribute as @Serializable

    Ugly and probably a source of headaches, specially if relying on java default serialization.

    @PersistenceCapable
    public class SomeClass {
        @Serializable
        private Map<String, List<SomeOtherClass>> myAttribute;
        // ...
    }
    
    @PersistenceCapable(embeddedOnly="true")
    public class SomeOtherClass implements Serializable {
        private String attribute;
        // ...
    }