From 9d18aa33f3654d937679e69d81ffd2ac7119aca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nick=20Manaigre=20=E2=9B=84?= Date: Wed, 31 Mar 2021 18:32:48 -0700 Subject: [PATCH] Allow disabling native type ids when deserializing for #270 --- .../jackson/dataformat/ion/IonFactory.java | 14 ++-- .../jackson/dataformat/ion/IonParser.java | 28 +++++++- .../PolymorphicTypeAnnotationsTest.java | 66 +++++++++++++++++++ 3 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 ion/src/test/java/com/fasterxml/jackson/dataformat/ion/polymorphism/PolymorphicTypeAnnotationsTest.java diff --git a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonFactory.java b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonFactory.java index 40f6810de..f1ae966af 100644 --- a/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonFactory.java +++ b/ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonFactory.java @@ -291,7 +291,7 @@ public int getFormatGeneratorFeatures() { * @since 2.7 */ public IonParser createParser(IonReader in) { - return new IonParser(in, _system, _createContext(in, false), getCodec()); + return new IonParser(in, _system, _createContext(in, false), getCodec(), _ionParserFeatures); } /** @@ -299,7 +299,7 @@ public IonParser createParser(IonReader in) { */ public IonParser createParser(IonValue value) { IonReader in = value.getSystem().newReader(value); - return new IonParser(in, _system, _createContext(in, true), getCodec()); + return new IonParser(in, _system, _createContext(in, true), getCodec(), _ionParserFeatures); } // NOTE! Suboptimal return type -- but can't change safely before 3.0 as return @@ -324,7 +324,7 @@ public IonSystem getIonSystem() { */ @Deprecated public IonParser createJsonParser(IonReader in) { - return new IonParser(in, _system, _createContext(in, false), getCodec()); + return new IonParser(in, _system, _createContext(in, false), getCodec(), _ionParserFeatures); } /** @@ -333,7 +333,7 @@ public IonParser createJsonParser(IonReader in) { @Deprecated public IonParser createJsonParser(IonValue value) { IonReader in = value.getSystem().newReader(value); - return new IonParser(in, _system, _createContext(in, true), getCodec()); + return new IonParser(in, _system, _createContext(in, true), getCodec(), _ionParserFeatures); } /** @@ -355,14 +355,14 @@ protected JsonParser _createParser(InputStream in, IOContext ctxt) throws IOException { IonReader ion = _system.newReader(in); - return new IonParser(ion, _system, ctxt, getCodec()); + return new IonParser(ion, _system, ctxt, getCodec(), _ionParserFeatures); } @Override protected JsonParser _createParser(Reader r, IOContext ctxt) throws IOException { - return new IonParser(_system.newReader(r), _system, ctxt, getCodec()); + return new IonParser(_system.newReader(r), _system, ctxt, getCodec(), _ionParserFeatures); } @Override @@ -376,7 +376,7 @@ protected JsonParser _createParser(char[] data, int offset, int len, IOContext c protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException { - return new IonParser(_system.newReader(data, offset, len), _system, ctxt, getCodec()); + return new IonParser(_system.newReader(data, offset, len), _system, ctxt, getCodec(), _ionParserFeatures); } @Override 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 82efdc1b7..8dcf3316a 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 @@ -40,6 +40,18 @@ public class IonParser */ public enum Feature implements FormatFeature // in 2.12 { + /** + * Whether to expect Ion native Type Id construct for indicating type (true); + * or "generic" type property (false) when deserializing. + *

+ * Enabled by default for backwards compatibility as that has been the behavior + * of `jackson-dataformat-ion` since 2.9 (first official public version) + * + * @see The Ion Specification + * + * @since 2.12 + */ + USE_NATIVE_TYPE_ID(true), ; final boolean _defaultState; @@ -113,6 +125,13 @@ private Feature(boolean defaultState) { */ protected JsonToken _valueToken; + /** + * Bit flag composed of bits that indicate which + * {@link IonParser.Feature}s + * are enabled. + */ + protected int _formatFeatures; + /* /***************************************************************** /* Construction @@ -133,15 +152,16 @@ public IonParser(IonReader r, IOContext ctxt) */ @Deprecated public IonParser(IonReader r, IOContext ctxt, ObjectCodec codec) { - this(r, IonSystemBuilder.standard().build(), ctxt, codec); + this(r, IonSystemBuilder.standard().build(), ctxt, codec, IonFactory.DEFAULT_ION_PARSER_FEATURE_FLAGS); } - IonParser(IonReader r, IonSystem system, IOContext ctxt, ObjectCodec codec) { + IonParser(IonReader r, IonSystem system, IOContext ctxt, ObjectCodec codec, int ionParserFeatures) { this._reader = r; this._ioContext = ctxt; this._objectCodec = codec; this._parsingContext = JsonReadContext.createRootContext(-1, -1, null); this._system = system; + this._formatFeatures = ionParserFeatures; } @Override @@ -179,7 +199,9 @@ public IonSystem getIonSystem() { @Override public boolean canReadTypeId() { - return true; // yes, Ion got 'em + // yes, Ion got 'em + // 31-Mar-2021, manaigrn: but we might want to ignore them as per [dataformats-binary#270] + return Feature.USE_NATIVE_TYPE_ID.enabledIn(_formatFeatures); } @Override diff --git a/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/polymorphism/PolymorphicTypeAnnotationsTest.java b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/polymorphism/PolymorphicTypeAnnotationsTest.java new file mode 100644 index 000000000..e71ae0f21 --- /dev/null +++ b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/polymorphism/PolymorphicTypeAnnotationsTest.java @@ -0,0 +1,66 @@ +package com.fasterxml.jackson.dataformat.ion.polymorphism; + +import java.io.IOException; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.dataformat.ion.IonObjectMapper; +import com.fasterxml.jackson.dataformat.ion.IonParser.Feature; +import org.junit.Assert; +import org.junit.Test; + +import com.amazon.ion.IonValue; +import com.amazon.ion.system.IonSystemBuilder; + +public class PolymorphicTypeAnnotationsTest { + private static final String SUBCLASS_TYPE_NAME = "subtype"; + + @JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "base", + visible = true + ) + @JsonSubTypes({ + @Type(value = Subclass.class, name = SUBCLASS_TYPE_NAME), + }) + static public class BaseClass { + } + + + public static class Subclass extends BaseClass { + public String base; + } + + + public static class Container { + public BaseClass objectWithType; + } + + + private static final IonValue CONTAINER_WITH_TYPED_OBJECT = asIonValue( + "{" + + " objectWithType:type::" + + " {" + + " base:\"" + SUBCLASS_TYPE_NAME + "\"," + + " }" + + "}"); + + @Test + public void testNativeTypeIdsDisabledReadsTypeAnnotationsSuccessfully() throws IOException { + IonObjectMapper mapper = new IonObjectMapper(); + mapper.disable(Feature.USE_NATIVE_TYPE_ID); + + Container containerWithBaseClass = mapper.readValue(CONTAINER_WITH_TYPED_OBJECT, Container.class); + + Assert.assertTrue(containerWithBaseClass.objectWithType instanceof Subclass); + Assert.assertEquals(SUBCLASS_TYPE_NAME, ((Subclass) containerWithBaseClass.objectWithType).base); + } + + private static IonValue asIonValue(final String ionStr) { + return IonSystemBuilder.standard() + .build() + .singleValue(ionStr); + } +}