-
Notifications
You must be signed in to change notification settings - Fork 161
Open
Description
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
- Save a Sample entity.
- Edit the entity to set
values.structuredFieldto null using the GCP console. - 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
Labels
No labels