From 05104239cbcc3f343d1840667926587f0c6aaf81 Mon Sep 17 00:00:00 2001 From: joshc Date: Wed, 9 Apr 2025 12:06:31 -0700 Subject: [PATCH 1/4] Fix #571: Unable to deserialize a pojo with IonStruct --- .../jackson/dataformat/ion/IonParser.java | 18 +++++ .../ion/ionvalue/IonValueDeserializer.java | 57 ++++++++++++-- .../ionvalue/IonValueDeserializerTest.java | 78 +++++++++++++++---- 3 files changed, 131 insertions(+), 22 deletions(-) diff --git a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java index 706068237..0c79992ba 100644 --- a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java +++ b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java @@ -53,6 +53,18 @@ public enum Feature implements FormatFeature // in 2.12 * @since 2.12.3 */ USE_NATIVE_TYPE_ID(true), + /** + * Whether to convert "null" to an IonValueNull (true); + * or leave as a java null (false) when deserializing. + *

+ * Enabled by default for backwards compatibility as that has been the behavior + * of `jackson-dataformat-ion` since 2.13. + * + * @see The Ion Specification + * + * @since 2.19.0 + */ + READ_NULL_AS_IONVALUE(true), ; final boolean _defaultState; @@ -563,6 +575,12 @@ private IonValue getIonValue() throws IOException { writer.writeValue(_reader); IonValue v = l.get(0); v.removeFromContainer(); + + if (v.isNullValue() && !Feature.READ_NULL_AS_IONVALUE.enabledIn(_formatFeatures)) { + if (_valueToken == JsonToken.VALUE_NULL && !IonType.isContainer(v.getType())) { + return null; + } + } return v; } 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 0835a989b..965948e57 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 @@ -16,21 +16,51 @@ import java.io.IOException; -import com.amazon.ion.*; - import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.deser.ContextualDeserializer; +import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.util.AccessPattern; import com.fasterxml.jackson.dataformat.ion.IonParser; +import com.amazon.ion.IonContainer; +import com.amazon.ion.IonList; +import com.amazon.ion.IonSexp; +import com.amazon.ion.IonStruct; +import com.amazon.ion.IonSystem; +import com.amazon.ion.IonType; +import com.amazon.ion.IonValue; +import com.amazon.ion.Timestamp; /** * Deserializer that knows how to deserialize an IonValue. */ -class IonValueDeserializer extends JsonDeserializer { +class IonValueDeserializer extends JsonDeserializer implements ContextualDeserializer { + + private final JavaType targetType; + + public IonValueDeserializer() { + this.targetType = null; + } + + public IonValueDeserializer(JavaType targetType) { + this.targetType = targetType; + } + + @Override + public JsonDeserializer createContextual(DeserializationContext ctxt, BeanProperty property) { + JavaType contextualType = (property != null) + ? property.getType() + : ctxt.getContextualType(); // fallback + return new IonValueDeserializer(contextualType); + } @Override public IonValue deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + Object embeddedObject = jp.getEmbeddedObject(); if (embeddedObject instanceof IonValue) { return (IonValue) embeddedObject; @@ -62,17 +92,34 @@ public IonValue getNullValue(DeserializationContext ctxt) throws JsonMappingExce if (embeddedObj instanceof IonValue) { IonValue iv = (IonValue) embeddedObj; if (iv.isNullValue()) { + if (IonType.isContainer(iv.getType())) { + return iv; + } + IonType containerType = getIonContainerType(); + if (containerType != null) { + IonSystem ionSystem = ((IonParser) parser).getIonSystem(); + return ionSystem.newNull(containerType); + } return iv; } } } - return super.getNullValue(ctxt); } catch (IOException e) { throw JsonMappingException.from(ctxt, e.toString()); } } + private IonType getIonContainerType() { + if (targetType != null) { + Class clazz = targetType.getRawClass(); + if (IonStruct.class.isAssignableFrom(clazz)) return IonType.STRUCT; + if (IonList.class.isAssignableFrom(clazz)) return IonType.LIST; + if (IonSexp.class.isAssignableFrom(clazz)) return IonType.SEXP; + } + return null; + } + @Override public AccessPattern getNullAccessPattern() { return AccessPattern.DYNAMIC; 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 7c97012e6..2285061e2 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 @@ -1,15 +1,23 @@ package com.fasterxml.jackson.dataformat.ion.ionvalue; -import java.io.IOException; -import java.util.*; - -import com.amazon.ion.*; +import com.amazon.ion.IonSystem; +import com.amazon.ion.IonValue; +import com.amazon.ion.IonStruct; import com.amazon.ion.system.IonSystemBuilder; -import org.junit.jupiter.api.Test; - -import com.fasterxml.jackson.annotation.*; +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 com.fasterxml.jackson.dataformat.ion.IonParser; + + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.junit.jupiter.api.Test; import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -65,7 +73,7 @@ static class IonValueData extends Data { } private static final IonSystem SYSTEM = IonSystemBuilder.standard().build(); - private static final IonValueMapper ION_VALUE_MAPPER = new IonValueMapper(SYSTEM, SNAKE_CASE); + private final IonValueMapper ION_VALUE_MAPPER = new IonValueMapper(SYSTEM, SNAKE_CASE); @Test public void shouldBeAbleToDeserialize() throws Exception { @@ -92,23 +100,49 @@ public void shouldBeAbleToDeserializeIncludingNullList() throws Exception { } @Test - public void shouldBeAbleToDeserializeNullList() throws Exception { - IonValue ion = ion("{c:null.list}"); - - IonValueData data = ION_VALUE_MAPPER.readValue(ion, IonValueData.class); + public void shouldBeAbleToDeserializeNullToIonNull() throws Exception { + String ion = "{c:null}"; + verifyNullDeserialization(ion, SYSTEM.newNull()); + ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); + verifyNullDeserialization(ion, null); + } - assertEquals(1, data.getAllData().size()); - assertEquals(SYSTEM.newNullList(), data.getAllData().get("c")); + @Test + public void shouldBeAbleToDeserializeNullList() throws Exception { + String ion = "{c:null.list}"; + verifyNullDeserialization(ion, SYSTEM.newNullList()); + ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); + verifyNullDeserialization(ion, SYSTEM.newNullList()); } @Test public void shouldBeAbleToDeserializeNullStruct() throws Exception { - IonValue ion = ion("{c:null.struct}"); + String ion = "{c:null.struct}"; + verifyNullDeserialization(ion, SYSTEM.newNullStruct()); + ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); + verifyNullDeserialization(ion, SYSTEM.newNullStruct()); + } - IonValueData data = ION_VALUE_MAPPER.readValue(ion, IonValueData.class); + @Test + public void shouldBeAbleToDeserializeNullSexp() throws Exception { + String ion = "{c:null.sexp}"; + verifyNullDeserialization(ion, SYSTEM.newNullSexp()); + ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); + verifyNullDeserialization(ion, SYSTEM.newNullSexp()); + } + + private void verifyNullDeserialization(String ionString, IonValue expected) throws Exception { + + IonValueData data = ION_VALUE_MAPPER.readValue(ionString, IonValueData.class); + + assertEquals(1, data.getAllData().size()); + assertEquals(expected, data.getAllData().get("c")); + + IonValue ion = ion(ionString); + data = ION_VALUE_MAPPER.readValue(ion, IonValueData.class); assertEquals(1, data.getAllData().size()); - assertEquals(SYSTEM.newNullStruct(), data.getAllData().get("c")); + assertEquals(expected, data.getAllData().get("c")); } @Test @@ -162,7 +196,17 @@ public void shouldBeAbleToSerializeAndDeserializeStringData() throws Exception { IonValue data = ION_VALUE_MAPPER.writeValueAsIonValue(source); StringData result = ION_VALUE_MAPPER.parse(data, StringData.class); + assertEquals(source, result); + } + + @Test + public void shouldBeAbleToSerializeAndDeserializeStringDataAsString() throws Exception { + StringData source = new StringData(); + source.put("a", "1"); + source.put("b", null); + String data = ION_VALUE_MAPPER.writeValueAsString(source); + StringData result = ION_VALUE_MAPPER.readValue(data, StringData.class); assertEquals(source, result); } From c92fce887a385f996652c036b7699413d1feade3 Mon Sep 17 00:00:00 2001 From: joshc Date: Fri, 11 Apr 2025 11:57:03 -0700 Subject: [PATCH 2/4] Fix #571: Address PR comments --- .../jackson/dataformat/ion/IonParser.java | 9 ++- .../ion/ionvalue/IonValueDeserializer.java | 25 +++------ .../ionvalue/IonValueDeserializerTest.java | 56 ++++++++++++------- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java index 0c79992ba..1948b9fe3 100644 --- a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java +++ b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java @@ -576,8 +576,13 @@ private IonValue getIonValue() throws IOException { IonValue v = l.get(0); v.removeFromContainer(); - if (v.isNullValue() && !Feature.READ_NULL_AS_IONVALUE.enabledIn(_formatFeatures)) { - if (_valueToken == JsonToken.VALUE_NULL && !IonType.isContainer(v.getType())) { + if (!Feature.READ_NULL_AS_IONVALUE.enabledIn(_formatFeatures)) { + // 2025-04-11, seadbrane: The default is to read 'null' as an Ion Null object. + // However, there is no way to determine from the serialized ion data if a 'null' + // was an IonNullValue or a 'null' container type such as IonNullStruct or IonNullList. + // So if READ_NULL_AS_IONVALUE is disabled, then return 'null' if the _valueToken + // is 'null' and the Ion value read is not container type already. + if (v.isNullValue() && _valueToken == JsonToken.VALUE_NULL && !IonType.isContainer(v.getType())) { return null; } } 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 965948e57..bd04adf7c 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 @@ -18,36 +18,25 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.BeanProperty; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.deser.ContextualDeserializer; -import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.util.AccessPattern; import com.fasterxml.jackson.dataformat.ion.IonParser; -import com.amazon.ion.IonContainer; -import com.amazon.ion.IonList; -import com.amazon.ion.IonSexp; -import com.amazon.ion.IonStruct; -import com.amazon.ion.IonSystem; -import com.amazon.ion.IonType; -import com.amazon.ion.IonValue; -import com.amazon.ion.Timestamp; +import com.amazon.ion.*; /** * Deserializer that knows how to deserialize an IonValue. */ class IonValueDeserializer extends JsonDeserializer implements ContextualDeserializer { - private final JavaType targetType; + private final JavaType _targetType; public IonValueDeserializer() { - this.targetType = null; + this._targetType = null; } public IonValueDeserializer(JavaType targetType) { - this.targetType = targetType; + this._targetType = targetType; } @Override @@ -111,8 +100,8 @@ public IonValue getNullValue(DeserializationContext ctxt) throws JsonMappingExce } private IonType getIonContainerType() { - if (targetType != null) { - Class clazz = targetType.getRawClass(); + if (_targetType != null) { + Class clazz = _targetType.getRawClass(); if (IonStruct.class.isAssignableFrom(clazz)) return IonType.STRUCT; if (IonList.class.isAssignableFrom(clazz)) return IonType.LIST; if (IonSexp.class.isAssignableFrom(clazz)) return IonType.SEXP; 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 2285061e2..20e2a4d7b 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 @@ -1,12 +1,15 @@ package com.fasterxml.jackson.dataformat.ion.ionvalue; +import com.amazon.ion.IonList; 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.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.util.AccessPattern; import com.fasterxml.jackson.dataformat.ion.IonObjectMapper; import com.fasterxml.jackson.dataformat.ion.IonParser; @@ -73,7 +76,8 @@ static class IonValueData extends Data { } private static final IonSystem SYSTEM = IonSystemBuilder.standard().build(); - private final IonValueMapper ION_VALUE_MAPPER = new IonValueMapper(SYSTEM, SNAKE_CASE); + private static final IonValueMapper ION_VALUE_MAPPER = new IonValueMapper(SYSTEM, SNAKE_CASE); + private static final IonValueMapper ION_MAPPER_READ_NULL_DISABLED = (IonValueMapper) new IonValueMapper(SYSTEM, SNAKE_CASE).disable(IonParser.Feature.READ_NULL_AS_IONVALUE); @Test public void shouldBeAbleToDeserialize() throws Exception { @@ -101,45 +105,43 @@ public void shouldBeAbleToDeserializeIncludingNullList() throws Exception { @Test public void shouldBeAbleToDeserializeNullToIonNull() throws Exception { - String ion = "{c:null}"; - verifyNullDeserialization(ion, SYSTEM.newNull()); - ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); - verifyNullDeserialization(ion, null); + verifyNullDeserialization("{c:null}", SYSTEM.newNull(), null); } @Test public void shouldBeAbleToDeserializeNullList() throws Exception { - String ion = "{c:null.list}"; - verifyNullDeserialization(ion, SYSTEM.newNullList()); - ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); - verifyNullDeserialization(ion, SYSTEM.newNullList()); + verifyNullDeserialization("{c:null.list}", SYSTEM.newNullList()); } + + @Test public void shouldBeAbleToDeserializeNullStruct() throws Exception { - String ion = "{c:null.struct}"; - verifyNullDeserialization(ion, SYSTEM.newNullStruct()); - ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); - verifyNullDeserialization(ion, SYSTEM.newNullStruct()); + verifyNullDeserialization("{c:null.struct}", SYSTEM.newNullStruct()); } @Test public void shouldBeAbleToDeserializeNullSexp() throws Exception { - String ion = "{c:null.sexp}"; - verifyNullDeserialization(ion, SYSTEM.newNullSexp()); - ION_VALUE_MAPPER.disable(IonParser.Feature.READ_NULL_AS_IONVALUE); - verifyNullDeserialization(ion, SYSTEM.newNullSexp()); + verifyNullDeserialization("{c:null.sexp}", SYSTEM.newNullSexp()); } private void verifyNullDeserialization(String ionString, IonValue expected) throws Exception { + verifyNullDeserialization(ionString, expected, expected); + } + + private void verifyNullDeserialization(String ionString, IonValue expected, IonValue expectedReadNullDisabled) throws Exception { + verifyNullDeserialization(ION_VALUE_MAPPER, ionString, expected); + verifyNullDeserialization(ION_MAPPER_READ_NULL_DISABLED, ionString, expectedReadNullDisabled); + } - IonValueData data = ION_VALUE_MAPPER.readValue(ionString, IonValueData.class); + private void verifyNullDeserialization(IonValueMapper mapper, String ionString, IonValue expected) throws Exception { + IonValueData data = mapper.readValue(ionString, IonValueData.class); assertEquals(1, data.getAllData().size()); assertEquals(expected, data.getAllData().get("c")); IonValue ion = ion(ionString); - data = ION_VALUE_MAPPER.readValue(ion, IonValueData.class); + data = mapper.readValue(ion, IonValueData.class); assertEquals(1, data.getAllData().size()); assertEquals(expected, data.getAllData().get("c")); @@ -188,6 +190,22 @@ public void shouldBeAbleToSerializeAndDeserializePojo() throws Exception { assertEquals(source, result); } + @Test + public void shouldBeAbleToSerializeAndDeserializeIonValueDataWithIncludeNonNull() throws Exception { + IonValueData source = new IonValueData(); + source.put("a", SYSTEM.newInt(1)); + source.put("b", SYSTEM.newNull()); + source.put("c", null); + IonValueMapper mapper = (IonValueMapper) ION_VALUE_MAPPER.copy().setSerializationInclusion(JsonInclude.Include.NON_NULL); + + String data = mapper.writeValueAsString(source); + assertEquals("{a:1,b:null}", data); + // Now remove the null element for the comparison below. + source.getAllData().remove("c"); + IonValueData result = mapper.readValue(data, IonValueData.class); + assertEquals(source, result); + } + @Test public void shouldBeAbleToSerializeAndDeserializeStringData() throws Exception { StringData source = new StringData(); From b606b31b460868fe883d16702916bf782bd06271 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 11 Apr 2025 14:29:25 -0700 Subject: [PATCH 3/4] Minor tweaks --- .../ionvalue/IonValueDeserializerTest.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) 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 20e2a4d7b..430cba2fa 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 @@ -1,28 +1,25 @@ package com.fasterxml.jackson.dataformat.ion.ionvalue; -import com.amazon.ion.IonList; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + import com.amazon.ion.IonSystem; import com.amazon.ion.IonValue; import com.amazon.ion.IonStruct; + +import org.junit.jupiter.api.Test; + import com.amazon.ion.system.IonSystemBuilder; import com.fasterxml.jackson.annotation.JsonAnyGetter; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.util.AccessPattern; import com.fasterxml.jackson.dataformat.ion.IonObjectMapper; import com.fasterxml.jackson.dataformat.ion.IonParser; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import org.junit.jupiter.api.Test; - -import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -76,8 +73,10 @@ static class IonValueData extends Data { } private static final IonSystem SYSTEM = IonSystemBuilder.standard().build(); - private static final IonValueMapper ION_VALUE_MAPPER = new IonValueMapper(SYSTEM, SNAKE_CASE); - private static final IonValueMapper ION_MAPPER_READ_NULL_DISABLED = (IonValueMapper) new IonValueMapper(SYSTEM, SNAKE_CASE).disable(IonParser.Feature.READ_NULL_AS_IONVALUE); + private static final IonValueMapper ION_VALUE_MAPPER + = new IonValueMapper(SYSTEM, PropertyNamingStrategies.SNAKE_CASE); + private static final IonValueMapper ION_MAPPER_READ_NULL_DISABLED + = (IonValueMapper) new IonValueMapper(SYSTEM, PropertyNamingStrategies.SNAKE_CASE).disable(IonParser.Feature.READ_NULL_AS_IONVALUE); @Test public void shouldBeAbleToDeserialize() throws Exception { @@ -242,7 +241,7 @@ static class MyBean { } @Test - public void testWithMissingProperty() throws IOException + public void testWithMissingProperty() throws Exception { IonSystem ionSystem = IonSystemBuilder.standard().build(); IonObjectMapper ionObjectMapper = IonObjectMapper.builder(ionSystem) From cebe606a8d3d25c8fdfedf69e90c361f6c604c1d Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 11 Apr 2025 14:33:51 -0700 Subject: [PATCH 4/4] Update release notes --- release-notes/CREDITS-2.x | 4 ++++ release-notes/VERSION-2.x | 3 +++ 2 files changed, 7 insertions(+) diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 6348ee0a8..8dec9da09 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -381,3 +381,7 @@ Cormac Redmond (@credmond) Manuel Sugawara (@sugmanue) * Contributed #568: Improve ASCII decoding performance for `CBORParser` (2.19.0) + +Josh Curry (@seadbrane) + * Reported, contributed fix for #571: Unable to deserialize a pojo with IonStruct + (2.19.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 135d01caa..213be7c18 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -14,6 +14,9 @@ Active maintainers: === Releases === ------------------------------------------------------------------------ +#571: Unable to deserialize a pojo with IonStruct + (reported, fix contributed by Josh C) + 2.19.0-rc2 (07-Apr-2025) #300: (smile) Floats are encoded with sign extension while doubles without