diff --git a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializer.java b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializer.java index 128f503ca..73010db12 100644 --- a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializer.java +++ b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializer.java @@ -17,6 +17,7 @@ import java.io.IOException; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonDeserializer; @@ -58,11 +59,14 @@ public IonValue deserialize(JsonParser jp, DeserializationContext ctxt) throws I @Override public IonValue getNullValue(DeserializationContext ctxt) throws JsonMappingException { try { - Object embeddedObj = ctxt.getParser().getEmbeddedObject(); - if (embeddedObj instanceof IonValue) { - IonValue iv = (IonValue) embeddedObj; - if (iv.isNullValue()) { - return iv; + final JsonParser parser = ctxt.getParser(); + if (parser != null && parser.getCurrentToken() != JsonToken.END_OBJECT) { + final Object embeddedObj = parser.getEmbeddedObject(); + if (embeddedObj instanceof IonValue) { + IonValue iv = (IonValue) embeddedObj; + if (iv.isNullValue()) { + return iv; + } } } diff --git a/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializerTest.java b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializerTest.java index 07c61bb57..507c64b94 100644 --- a/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializerTest.java +++ b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueDeserializerTest.java @@ -2,12 +2,16 @@ import com.amazon.ion.IonSystem; import com.amazon.ion.IonValue; +import com.amazon.ion.IonStruct; import com.amazon.ion.system.IonSystemBuilder; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.util.AccessPattern; +import com.fasterxml.jackson.dataformat.ion.IonObjectMapper; import org.junit.Test; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -166,6 +170,39 @@ public void shouldBeAbleToSerializeAndDeserializeStringData() throws Exception { assertEquals(source, result); } + static class MyBean { + public IonStruct required; + public IonStruct optional; + + MyBean( + @JsonProperty("required") IonStruct required, + @JsonProperty("optional") IonStruct optional + ) { + this.required = required; + this.optional = optional; + } + } + + @Test + public void testWithMissingProperty() throws IOException + { + IonSystem ionSystem = IonSystemBuilder.standard().build(); + IonObjectMapper ionObjectMapper = IonObjectMapper.builder(ionSystem) + .addModule(new IonValueModule()) + .build(); + + String input1 = "{required:{}, optional:{}}"; + MyBean deserializedBean1 = ionObjectMapper.readValue(input1, MyBean.class); + assertEquals(ionSystem.newEmptyStruct(), deserializedBean1.required); + assertEquals(ionSystem.newEmptyStruct(), deserializedBean1.optional); + + // This deserialization should not fail with missing property + String input2 = "{required:{}}"; + MyBean deserializedBean2 = ionObjectMapper.readValue(input2, MyBean.class); + assertEquals(ionSystem.newEmptyStruct(), deserializedBean2.required); + assertEquals(null, deserializedBean2.optional); + } + @Test public void shouldOverrideNullAccessPatternToBeDynamic() { IonValueDeserializer deserializer = new IonValueDeserializer();