From f4d5f4355a5b01c72a7f51be1e7becf921ce9125 Mon Sep 17 00:00:00 2001 From: Jesse Bryant Date: Mon, 15 Feb 2021 22:41:52 +0000 Subject: [PATCH] Add support for deserializing IonTimestamps and IonBlobs --- .../jackson/dataformat/ion/IonParser.java | 4 +++ .../ion/ionvalue/IonValueDeserializer.java | 25 ++++++++++++- .../ion/ionvalue/IonValueMapperTest.java | 36 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) 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 d9cbf635f..a8dc98a50 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 @@ -159,6 +159,10 @@ public Version version() { return PackageVersion.VERSION; } + public IonSystem getIonSystem() { + return _system; + } + /* /********************************************************** /* Capability introspection 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 f4ec0eead..ed435ed7a 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,8 +18,12 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.dataformat.ion.IonParser; +import com.amazon.ion.IonSystem; import com.amazon.ion.IonValue; +import com.amazon.ion.Timestamp; /** * Deserializer that knows how to deserialize an IonValue. @@ -28,6 +32,25 @@ class IonValueDeserializer extends JsonDeserializer { @Override public IonValue deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { - return (IonValue) jp.getEmbeddedObject(); + Object embeddedObject = jp.getEmbeddedObject(); + if (embeddedObject instanceof IonValue) { + return (IonValue) embeddedObject; + } + // We rely on the IonParser's IonSystem to wrap supported types into an IonValue + if (!(jp instanceof IonParser)) { + throw JsonMappingException.from(jp, "Unsupported parser for deserializing " + + embeddedObject.getClass().getCanonicalName() + " into IonValue"); + } + + IonSystem ionSystem = ((IonParser) jp).getIonSystem(); + if (embeddedObject instanceof Timestamp) { + return ionSystem.newTimestamp((Timestamp) embeddedObject); + } + if (embeddedObject instanceof byte[]) { + // The parser provides no distinction between BLOB and CLOB, deserializing to a BLOB is the safest choice. + return ionSystem.newBlob((byte[]) embeddedObject); + } + throw JsonMappingException.from(jp, "Cannot deserialize embedded object type " + + embeddedObject.getClass().getCanonicalName() + " into IonValue"); } } diff --git a/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueMapperTest.java b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueMapperTest.java index 8b316d6d4..0e171e3f3 100644 --- a/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueMapperTest.java +++ b/ion/src/test/java/com/fasterxml/jackson/dataformat/ion/ionvalue/IonValueMapperTest.java @@ -128,6 +128,38 @@ public void testPojo2() throws Exception { assertRoundTrip(value, TestPojo2.class); } + @Test + public void testPojo2WithTimestamp() throws Exception { + String value = "{" + + "raw_value:2017-05-25T15:33:08Z," + + "raw_sexp:(this that)," + + "wrapped_sexp:{sexp:(other)}," + + "}"; + + TestPojo2 t = ionValueMapper.parse(ionSystem.singleValue(value), TestPojo2.class); + assertEquals(ionSystem.singleValue("2017-05-25T15:33:08Z"), t.rawValue); + assertEquals(ionSystem.singleValue("(this that)"), t.rawSexp); + assertEquals(ionSystem.singleValue("(other)"), t.wrappedSexp.sexp); + + assertRoundTrip(value, TestPojo2.class); + } + + @Test + public void testPojo2WithBlob() throws Exception { + String value = "{" + + "raw_value:{{YmxvYl92YWx1ZQ==}}," + + "raw_sexp:(this that)," + + "wrapped_sexp:{sexp:(other)}," + + "}"; + + TestPojo2 t = ionValueMapper.parse(ionSystem.singleValue(value), TestPojo2.class); + assertEquals(ionSystem.newBlob("blob_value".getBytes()), t.rawValue); + assertEquals(ionSystem.singleValue("(this that)"), t.rawSexp); + assertEquals(ionSystem.singleValue("(other)"), t.wrappedSexp.sexp); + + assertRoundTrip(value, TestPojo2.class); + } + /** * This Pojo supports open content */ @@ -154,12 +186,16 @@ public void testPojo3WithOpenContent() throws Exception { "expected:1," + "something_unexpected:(boo!)," + "another_random_struct:{yikes:scared}," + + "timestamp_att:2021-02-15T18:40:40Z," + + "blob_att:{{YmxvYl92YWx1ZQ==}}," + "}"; TestPojo3 t = ionValueMapper.parse(ionSystem.singleValue(value), TestPojo3.class); assertEquals(1, t.expected); assertEquals(ionSystem.singleValue("(boo!)"), t.any().get("something_unexpected")); assertEquals(ionSystem.singleValue("{yikes:scared}"), t.any().get("another_random_struct")); + assertEquals(ionSystem.singleValue("2021-02-15T18:40:40Z"), t.any().get("timestamp_att")); + assertEquals(ionSystem.newBlob("blob_value".getBytes()), t.any().get("blob_att")); assertRoundTrip(value, TestPojo3.class); }