Skip to content

Commit ca7c999

Browse files
authored
Merge pull request #513 from jimit-j-shah/jimit/506_nullvalue_demo_test
test: Fix handling NullValue in embedded maps
2 parents 7fbb571 + 3bdd6d7 commit ca7c999

4 files changed

Lines changed: 62 additions & 9 deletions

File tree

src/main/java/com/googlecode/objectify/impl/translate/CollectionTranslatorFactory.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@ public Translator<Collection<Object>, List<? extends Value<?>>> create(final Typ
4444

4545
@Override
4646
public Collection<Object> loadInto(final Value<List<? extends Value<?>>> node, final LoadContext ctx, final Path path, Collection<Object> collection) throws SkipException {
47-
// If the collection does not exist, skip it entirely. This mirrors the OLD underlying behavior
48-
// of collections in the datastore; if they are empty, they don't exist.
49-
if (node == null || node.get() == null)
50-
throw new SkipException();
51-
5247
if (collection == null)
5348
//noinspection unchecked
5449
collection = (Collection<Object>)fact.constructCollection(collectionType, node.get().size());

src/main/java/com/googlecode/objectify/impl/translate/EmbeddedMapTranslatorFactory.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,6 @@ else if (keyTypeErased == Key.class)
7070

7171
@Override
7272
public Map<Object, Object> loadInto(final Value<FullEntity<?>> node, final LoadContext ctx, final Path path, Map<Object, Object> into) {
73-
// Make this work more like collections than atomic values
74-
if (node == null)
75-
throw new SkipException();
76-
7773
if (into == null)
7874
//noinspection unchecked
7975
into = (Map<Object, Object>)fact.constructMap(mapType);

src/main/java/com/googlecode/objectify/impl/translate/TranslatorRecycles.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.googlecode.objectify.impl.translate;
22

33
import com.google.cloud.datastore.Value;
4+
import com.google.cloud.datastore.ValueType;
45
import com.googlecode.objectify.impl.Path;
56

67
/**
@@ -13,6 +14,13 @@
1314
abstract public class TranslatorRecycles<P, D> implements Translator<P, D>, Recycles {
1415
@Override
1516
final public P load(final Value<D> node, final LoadContext ctx, final Path path) throws SkipException {
17+
// If the underlying container (Map, EmbeddedMap or Collection) does not exist or is of type
18+
// NullValue, skip it entirely. For Collections, this mirrors the OLD underlying behavior of
19+
// collections in the datastore; if they are empty, they don't exist.
20+
if (node == null || node.getType() == ValueType.NULL) {
21+
throw new SkipException();
22+
}
23+
1624
@SuppressWarnings("unchecked")
1725
final P into = (P)ctx.useRecycled();
1826

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.googlecode.objectify.test;
2+
3+
import com.google.cloud.datastore.NullValue;
4+
import com.googlecode.objectify.annotation.Entity;
5+
import com.googlecode.objectify.annotation.Id;
6+
import com.googlecode.objectify.test.util.TestBase;
7+
import lombok.AllArgsConstructor;
8+
import lombok.Data;
9+
import lombok.NoArgsConstructor;
10+
import org.junit.jupiter.api.Test;
11+
12+
import java.util.Map;
13+
14+
import static com.googlecode.objectify.ObjectifyService.factory;
15+
import static com.googlecode.objectify.ObjectifyService.ofy;
16+
17+
// This class tests Objectify APIs handling of Embedded NullValue by comparing with Entitites
18+
// written and read using raw Datastore API calls.
19+
public class StrangeNullishTests extends TestBase {
20+
21+
@Entity(name = "Sample")
22+
@Data
23+
@NoArgsConstructor
24+
@AllArgsConstructor
25+
public static class Sample {
26+
@Id String name;
27+
Map<String, String> inner;
28+
}
29+
30+
/**
31+
* Verifies correctly loading NullValue embedded in a Map
32+
*/
33+
@Test
34+
public void loadSimplerNestedStructureWithNulls() {
35+
factory().register(Sample.class);
36+
37+
final String rawDatastoreDocId = "EmbeddedMapNullValue_rawDatastoreDoc";
38+
final com.google.cloud.datastore.Key rawDatastoreKey = datastore().newKeyFactory()
39+
.setKind("Sample")
40+
.newKey(rawDatastoreDocId);
41+
42+
final com.google.cloud.datastore.Entity rawSample =
43+
com.google.cloud.datastore.Entity.newBuilder(rawDatastoreKey)
44+
.set("inner", new NullValue())
45+
.build();
46+
47+
// Save to Datastore
48+
datastore().put(rawSample);
49+
50+
// Verify using Objectify `load` API
51+
final Sample sample = ofy().load().type(Sample.class).id(rawDatastoreDocId).now();
52+
// Just verifying this loads without NPE is success
53+
}
54+
}

0 commit comments

Comments
 (0)