Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Null value in Embedded Entity's field causes Objectify LoadException #506

@TatsuhiroAbe

Description

@TatsuhiroAbe

We have a Sample Entity that includes values as an Embedded Entity.

@Entity(name = "Sample")
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Sample {
    @Id String name;
    Map<String, List<Value>> values;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Value {
    String primitiveField;
    Map<String, String> structuredField;
}

When loading an entity where structuredField is null, Objectify throws a com.googlecode.objectify.LoadException. The complete stack trace is as follows:

Exception in thread "main" com.googlecode.objectify.LoadException: Error loading Key{...}: Cannot invoke "com.google.cloud.datastore.FullEntity.getNames()" because the return value of "com.google.cloud.datastore.Value.get()" is null
	at com.googlecode.objectify.impl.EntityMetadata.load(EntityMetadata.java:84)
	at com.googlecode.objectify.impl.LoadEngine.load(LoadEngine.java:196)
	at com.googlecode.objectify.impl.LoadEngine$1.nowUncached(LoadEngine.java:154)
	at com.googlecode.objectify.impl.LoadEngine$1.nowUncached(LoadEngine.java:140)
	at com.googlecode.objectify.util.ResultCache.now(ResultCache.java:30)
	at com.googlecode.objectify.impl.Round$1.nowUncached(Round.java:66)
	at com.googlecode.objectify.util.ResultCache.now(ResultCache.java:30)
	at com.googlecode.objectify.LoadResult.now(LoadResult.java:25)
	at java_sandbox.App.main(App.java:55)
Caused by: java.lang.NullPointerException: Cannot invoke "com.google.cloud.datastore.FullEntity.getNames()" because the return value of "com.google.cloud.datastore.Value.get()" is null
	at com.googlecode.objectify.impl.translate.EmbeddedMapTranslatorFactory$1.loadInto(EmbeddedMapTranslatorFactory.java:83)
	at com.googlecode.objectify.impl.translate.EmbeddedMapTranslatorFactory$1.loadInto(EmbeddedMapTranslatorFactory.java:69)
	at com.googlecode.objectify.impl.translate.TranslatorRecycles.load(TranslatorRecycles.java:19)
	at com.googlecode.objectify.impl.PropertyPopulator.setValue(PropertyPopulator.java:95)
	at com.googlecode.objectify.impl.PropertyPopulator.load(PropertyPopulator.java:55)
	at com.googlecode.objectify.impl.translate.ClassPopulator.load(ClassPopulator.java:119)
	at com.googlecode.objectify.impl.translate.ClassTranslator.loadSafe(ClassTranslator.java:113)
	at com.googlecode.objectify.impl.translate.NullSafeTranslator.load(NullSafeTranslator.java:21)
	at com.googlecode.objectify.impl.translate.CollectionTranslatorFactory$1.loadInto(CollectionTranslatorFactory.java:61)
	at com.googlecode.objectify.impl.translate.CollectionTranslatorFactory$1.loadInto(CollectionTranslatorFactory.java:43)
	at com.googlecode.objectify.impl.translate.TranslatorRecycles.load(TranslatorRecycles.java:19)
	at com.googlecode.objectify.impl.translate.EmbeddedMapTranslatorFactory$1.loadInto(EmbeddedMapTranslatorFactory.java:88)
	at com.googlecode.objectify.impl.translate.EmbeddedMapTranslatorFactory$1.loadInto(EmbeddedMapTranslatorFactory.java:69)
	at com.googlecode.objectify.impl.translate.TranslatorRecycles.load(TranslatorRecycles.java:19)
	at com.googlecode.objectify.impl.PropertyPopulator.setValue(PropertyPopulator.java:95)
	at com.googlecode.objectify.impl.PropertyPopulator.load(PropertyPopulator.java:55)
	at com.googlecode.objectify.impl.translate.ClassPopulator.load(ClassPopulator.java:119)
	at com.googlecode.objectify.impl.translate.ClassTranslator.loadSafe(ClassTranslator.java:113)
	at com.googlecode.objectify.impl.translate.NullSafeTranslator.load(NullSafeTranslator.java:21)
	at com.googlecode.objectify.impl.EntityMetadata.load(EntityMetadata.java:80)
	... 8 more

Environment

Objectify: 6.1.1

Steps to Reproduce

  1. Save a Sample entity.
  2. Edit the entity to set values.structuredField to null using the GCP console.
  3. Attempt to load the entity.

Note: Even if structuredValue is set to null, saving with Objectify does not cause an error upon loading. The error occurs only when loading an entity directly edited in the GCP console. In our case, the error occurred when loading an entity written by Cloud Dataflow. We use DatastoreIO for writing with Cloud Dataflow.

public class App {

    @Entity(name = "Sample")
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Sample {
        @Id String name;
        Map<String, List<Value>> values;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Value {
        String primitiveField;
        Map<String, String> structuredField;
    }

    public static void main(String[] args) {
        Map<String, List<Value>> values = Map.of("k1", List.of(new Value(null, null)));
        String name = "sample1";
        Sample sample = new Sample(name, values);

        DatastoreOptions options = DatastoreOptions.newBuilder()
            .setProjectId("your-project-id")
            .setNamespace("your-namespace")
            .build();
        ObjectifyService.init(new ObjectifyFactory(options.getService()));
        ObjectifyService.register(Sample.class);

        try (Closeable session = ObjectifyService.begin()) {
            // If an entity is not saved, uncomment the following line and call save() method.
            // And edit the entity directly to `structuredFiled` has null (nullValue) from GCP console
            // ObjectifyService.ofy().save().entity(sample).now();

            Sample entity = ObjectifyService.ofy().load().key(Key.create(Sample.class, name)).now();
            System.out.println(entity);
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}

The final JSON representation of values is as follows:

{
  "properties": {
    "k1": {
      "arrayValue": {
        "values": [
          {
            "entityValue": {
              "properties": {
                "primitiveField": {
                  "nullValue": null,
                  "excludeFromIndexes": true
                },
                "structuredField": {
                  "nullValue": null,
                  "excludeFromIndexes": true
                }
              }
            }
          }
        ]
      }
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions