Objectify 5 save an embedded List of List or array of arrays?

459 views Asked by At

I'm converting code from objectify 4 to 5.

Previously I was saving an @Entity containing a class that contained

List<List<String>> listOfListOfStrings;

With version 5 I get a SaveException:

com.googlecode.objectify.SaveException: 
Error saving com.timmacp.server.OfyEntityClass@3d627804: 
listOfListOfStrings: java.util.ArrayList is not a supported property type`

same problem with arrays of arrays.

Here is some code I've used to test, MemberClass just contains a String.

@Entity
public class OfyEntityClass {
    @Id
    private Long ID;
    List<List<MemberClass>> memberClassObjects;
    public OfyEntityClass(){
        memberClassObjects=new ArrayList<List<MemberClass>>(8);
        List<MemberClass> l=new ArrayList<MemberClass>(8);
        MemberClass memberClassObject=new MemberClass();
        l.add(memberClassObject);
        memberClassObjects.add(l);
    }
}

A workaround seems to be to put each List level in its own class, but this seems strange as the docs state that "Many limitations of Objectify4 no longer apply to Objectify5: Nesting of collections of embedded objects is unrestricted."

Update: some of the fields were annotated with @Serialize in the ofy4 version. I'd removed these thinking they were not required in ofy5 so that explains the difference. Still wondering if its possible to do this without @Serialize. Wrapper classes seem to work to simulate a List<List<String> but not for more complex nesting.

Update 2: with v5, won't work with a recursive class? ie if Thing has a field of type List<Thing> then (so far) register fails: stack trace looks like infinite repetition of:

    at com.googlecode.objectify.impl.translate.Translators.create(Translators.java:138)
at com.googlecode.objectify.impl.translate.Translators.get(Translators.java:117)
at com.googlecode.objectify.impl.translate.CreateContext.getTranslator(CreateContext.java:27)
at com.googlecode.objectify.impl.translate.CollectionTranslatorFactory.create(CollectionTranslatorFactory.java:38)
at com.googlecode.objectify.impl.translate.Translators.create(Translators.java:138)
at com.googlecode.objectify.impl.translate.Translators.get(Translators.java:117)
at com.googlecode.objectify.impl.translate.CreateContext.getTranslator(CreateContext.java:27)
at com.googlecode.objectify.impl.translate.ClassPopulator.<init>(ClassPopulator.java:88)
at com.googlecode.objectify.impl.translate.ClassTranslatorFactory.createEmbeddedClassTranslator(ClassTranslatorFactory.java:75)
at com.googlecode.objectify.impl.translate.ClassTranslatorFactory.create(ClassTranslatorFactory.java:50)
at com.googlecode.objectify.impl.translate.ClassTranslatorFactory.create(ClassTranslatorFactory.java:36)

Or maybe there's a way to specify the number of recursion levels for the translators?

1

There are 1 answers

4
stickfigure On BEST ANSWER

Primary Objectify author here.

Objectify4 should not be able to save a field of type List<List<String>>. I can't even imagine what that would do, or why it would work. There are no tests around it. Historically, GAE only allowed storing a simple collection of scalar values in entities. At some point they expanded that by providing EmbeddedEntity, but that is something different. I haven't tried storing a List<List<String>> manually with the low-level api, but if it works, that's something new that Google has not announced nor have they documented it. Nor does there appear to be any way of defining structures like this in GAE/Python (db or ndb).

So I don't know what to tell you. If you tell me you have a working application which stores and retrieves a List<List<String>> field - then this is something new. How long have you had this deployed?