Objectify embedded maps fail to retrieve

1.4k views Asked by At

I am using Objectify as a data access layer in my GoogleAppEngine hosted application.

The problem comes when I try to persist a map. My bean looks like this:

@Entity
@Cached
class MyBean{
    @Id 
    private Long id;
    @Embedded
    Map<String, String> parameters = new HashMap<String, String>();

    public MyBean(){}

    //getters and setters below
}

First of all note that the map 'parameters' is not private, it was throwing a JRE exception. When saving the map everything goes well. When retreiving it from the DataStore it fails.

My workaround is to use the @Serialized annotation. This is just a workaround since what I want to acheive is to use the expando feature of GAE Datastore.

According to the objectify doc I'm doing the right operations.

Exception details:

Caused by: java.lang.NullPointerException at com.googlecode.objectify.impl.Transmog.loadSingleValue(Transmog.java:364) at com.googlecode.objectify.impl.load.EmbeddedMapSetter.safeSet(EmbeddedMapSetter.java:65) at com.googlecode.objectify.impl.load.CollisionDetectingSetter.set(CollisionDetectingSetter.java:37) at com.googlecode.objectify.impl.Transmog.loadSingleValue(Transmog.java:359) at com.googlecode.objectify.impl.Transmog.load(Transmog.java:340) at com.googlecode.objectify.impl.ConcreteEntityMetadata.toObject(ConcreteEntityMetadata.java:203) at com.googlecode.objectify.impl.QueryImpl$ToObjectIterator.translate(QueryImpl.java:668) at com.googlecode.objectify.impl.QueryImpl$ToObjectIterator.translate(QueryImpl.java:657) at com.googlecode.objectify.util.TranslatingIterator.next(TranslatingIterator.java:35)

2

There are 2 answers

2
stickfigure On BEST ANSWER

Embedded maps were poorly supported in Objectify3, and should not have been publicly announced. The section on @Embedded Map has been removed from the Objectify3 documentation.

Objectify4 supports maps extensively, including these expando-style maps:

  • Map (or any primitive)
  • Map (key references)
  • Map (embedded classes

In addition, there is a @Mapify annotation that lets you take a normal collection of objects, pick one property out as a key, and store that as a Map.

Unfortunately Objectify4's documentation is not ready at this time. However, the source code is in active use by several parties. If you feel daring, build from trunk.

0
mjaggard On

I also recommend using Objectify 4 - I've upgraded my app and found it fairly easy to do. I much prefer the support for fields of the type Map in particular.

To answer the question, you should never put @Embedded onto an array containing only primitives. So you don't need to specify @Embedded on your map because String is primitive in the Google App Engine Datastore.