google-code-export / twig-persist

Automatically exported from code.google.com/p/twig-persist
1 stars 1 forks source link

Primitive values in embedded, polymorphic HashMap #66

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
When an object contains a polymorphic embedded HashMap with values, some of 
which are (datastore) primitive types, decoding will fail with a 
NullPointerException.

E.g. given the class:

class Bag {
  @Id Long id;
  @Embedded(polymorphic = true)
  HashMap<String, Object> attrs;
}

and code:

bag = mew Bag();
bag.put("bar", new Date());
datastore.store(launch);

// later
datastore.find().type(Bag.class).returnAll().now();

Gives the following exception:

java.lang.IllegalStateException: Problem translating field private 
java.util.HashMap Bag.attrs with properties [[SimpleProperty value=Mon Jun 06 
10:49:52 UTC 2011 path=attrs:bar indexed=false]]
    at com.google.code.twig.translator.ObjectFieldTranslator.decode(ObjectFieldTranslator.java:130)
    at com.google.code.twig.standard.TranslatorObjectDatastore$StrategyObjectFieldTranslator.decode(TranslatorObjectDatastore.java:634)
    at com.google.code.twig.translator.ObjectFieldTranslator.decode(ObjectFieldTranslator.java:105)
    at com.google.code.twig.standard.StandardDecodeCommand.entityToInstance(StandardDecodeCommand.java:63)
    at com.google.code.twig.standard.StandardDecodeCommand$1.next(StandardDecodeCommand.java:102)
    at com.google.common.collect.ForwardingIterator.next(ForwardingIterator.java:48)
    at com.google.common.collect.Lists.newArrayList(Lists.java:140)
    at com.google.code.twig.standard.StandardRootFindCommand$4.now(StandardRootFindCommand.java:324)
    at com.google.code.twig.standard.StandardRootFindCommand$4.now(StandardRootFindCommand.java:320)
[...]
Caused by: java.lang.NullPointerException
    at com.google.code.twig.Path$Part.access$200(Path.java:89)
    at com.google.code.twig.Path$Builder.append(Path.java:84)
    at com.google.code.twig.util.PropertySets.createPrefixSubset(PropertySets.java:66)
    at com.google.code.twig.util.PropertySets.prefixPropertySets(PropertySets.java:57)
    at com.google.code.twig.translator.ObjectFieldTranslator.decode(ObjectFieldTranslator.java:76)
    at com.google.code.twig.translator.ChainedTranslator.decode(ChainedTranslator.java:62)
    at com.google.code.twig.translator.PolymorphicTranslator.decode(PolymorphicTranslator.java:42)
    at com.google.code.twig.translator.MapTranslator.decode(MapTranslator.java:68)
    at com.google.code.twig.translator.ListTranslator.decode(ListTranslator.java:50)
    at com.google.code.twig.translator.ObjectFieldTranslator.decode(ObjectFieldTranslator.java:125)
    ... 46 more

Original issue reported on code.google.com by martinpr...@google.com on 6 Jun 2011 at 10:54

GoogleCodeExporter commented 9 years ago
Maybe this should be handled by ConvertableTypeTranslator?

Original comment by mar...@probst.io on 6 Jun 2011 at 10:58

GoogleCodeExporter commented 9 years ago
The problem is that it is not possible to embed a primitive type as they do not 
have fields.  I think you are probably just needing to remove the @Embedded 
annotation and the default translator will first try to encode as a native type.

Is this what you are after?

Original comment by j...@citikey.com on 6 Jun 2011 at 11:34

GoogleCodeExporter commented 9 years ago
Possibly, but I actually wanted to mix primitive and non-primitive values in 
that particular map (that's why I have the polymorphic attribute). I assume I 
can wrap the primitives in another class to work around this.

The NPE is probably not intended behaviour, is it?

Original comment by mar...@probst.io on 6 Jun 2011 at 11:39

GoogleCodeExporter commented 9 years ago
Ok, I've created this test case that shows your situation working fine.  Modify 
it to make it fail if you are doing something different

package com.google.code.twig.tests.issues;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.junit.Test;

import com.google.code.twig.LocalDatastoreTestCase;
import com.google.code.twig.annotation.AnnotationObjectDatastore;
import com.google.code.twig.annotation.Embedded;
import com.google.code.twig.annotation.Id;

public class Issue66Test extends LocalDatastoreTestCase
{
    static class Bag 
    {
          @Id Long id;
          @Embedded(polymorphic = true)
          HashMap<String, Object> attrs = new HashMap<String, Object>();
    }

    static class Stuff 
    {
        String name = "j-lo";
        String asset = "ass";
    }

    @Test
    public void mixedPrimitiveAndObjectMap()
    {
        AnnotationObjectDatastore datastore = new AnnotationObjectDatastore();
        Bag bag = new Bag();
        bag.attrs.put("bar", new Date());
        bag.attrs.put("num", 8);
        bag.attrs.put("stuff", new Stuff());

        datastore.store(bag);

        datastore.disassociateAll();

        List<Bag> bags = datastore.find().type(Bag.class).returnAll().now();

        assert bags.size() == 1;

    }
}

Original comment by j...@citikey.com on 6 Jun 2011 at 12:13

GoogleCodeExporter commented 9 years ago
Strange, the code from trunk inserts a ConfigurationFieldTranslator into the 
chain that does not end up there when I run from my local project.

But that translator isn't either, it silently deserializes the primitive values 
into instances of Object that don't contain any data.

    @Test
    public void mixedPrimitiveAndObjectMap()
    {
        AnnotationObjectDatastore datastore = new AnnotationObjectDatastore();
        Bag bag = new Bag();
        Date dateValue = new Date();
        bag.attrs.put("bar", dateValue);
        bag.attrs.put("num", 8);
        bag.attrs.put("stuff", new Stuff());

        datastore.store(bag);

        datastore.disassociateAll();

        List<Bag> bags = datastore.find().type(Bag.class).returnAll().now();
        assert bags.size() == 1;
        assertEquals(dateValue, bags.get(0).attrs.get("bar"));
    }

Above test will fail, same for "num". I'll investigate some more to see if the 
new translator only got introduced at trunk.

Original comment by mar...@probst.io on 6 Jun 2011 at 2:00