diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeDeserializer.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeDeserializer.java index 191195d58..dbb74fae0 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeDeserializer.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeDeserializer.java @@ -4,10 +4,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.BeanProperty; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; import com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase; diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java index cd95a1b41..837310482 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java @@ -1,11 +1,10 @@ package com.fasterxml.jackson.dataformat.avro.interop.annotations; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.nio.ByteBuffer; +import java.util.*; +import org.apache.avro.SchemaBuilder; import org.apache.avro.io.Decoder; import org.apache.avro.io.Encoder; import org.apache.avro.reflect.AvroEncode; @@ -53,6 +52,9 @@ static class CustomComponent { @Nullable public Long longValue; + @AvroEncode(using = UuidAsBytesAvroEncoding.class) + private UUID uuidValue; + protected CustomComponent() { } } @@ -60,7 +62,7 @@ protected CustomComponent() { } public static class ApacheImplEncoding extends CustomEncoding { public ApacheImplEncoding() throws IOException { - schema = ApacheAvroInteropUtil.getJacksonSchema(CustomComponent.class); + schema = ApacheAvroInteropUtil.getApacheSchema(CustomComponent.class); } @Override @@ -75,8 +77,67 @@ protected CustomComponent read(Object reuse, Decoder in) throws IOException { } - protected Wrapper wrapper; + public static class UuidAsBytesAvroEncoding extends CustomEncoding { + public static byte[] asByteArray(UUID uuid) { + long msb = uuid.getMostSignificantBits(); + long lsb = uuid.getLeastSignificantBits(); + byte[] buffer = new byte[16]; + for (int i = 0; i < 8; i++) { + buffer[i] = (byte) (msb >>> 8 * (7 - i)); + } + for (int i = 8; i < 16; i++) { + buffer[i] = (byte) (lsb >>> 8 * (7 - i)); + } + return buffer; + } + public static UUID toUUID(byte[] byteArray) { + long msb = 0; + long lsb = 0; + for (int i = 0; i < 8; i++) { msb = (msb << 8) | (byteArray[i] & 0xff); } + for (int i = 8; i < 16; i++) { lsb = (lsb << 8) | (byteArray[i] & 0xff); } + return new UUID(msb, lsb); + } + + public UuidAsBytesAvroEncoding() { + this.schema = SchemaBuilder.unionOf().nullType().and().bytesBuilder().endBytes().endUnion(); + } + + @Override + public void write(Object datum, Encoder encoder) throws IOException { + if (datum == null) { + encoder.writeIndex(0); + encoder.writeNull(); + return; + } + encoder.writeIndex(1); + encoder.writeBytes(asByteArray((UUID) datum)); + } + + @Override + public UUID read(Object datum, Decoder decoder) throws IOException { + try { + // get index in union + int index = decoder.readIndex(); + if (index == 1) { + // read in 16 bytes of data + ByteBuffer b = ByteBuffer.allocate(16); + decoder.readBytes(b); + // convert + UUID uuid = toUUID(b.array()); + return uuid; + } else { + decoder.readNull(); + // no uuid present + return null; + } + } catch (Exception exception) { + throw new IllegalStateException("Could not decode bytes into UUID", exception); + } + } + } + + protected Wrapper wrapper; protected Wrapper result; @Before @@ -93,6 +154,7 @@ public void setup() throws IOException { mv.put("cats", new ArrayList()); mv.put("dogs", new ArrayList<>(Arrays.asList(-1234, 56, 6767, 54134, 57, 86))); wrapper.component.stringValue = "Hello World!"; + wrapper.component.uuidValue = UUID.randomUUID(); CustomComponent cc = new CustomComponent(); cc.byteValue = (byte) 42; @@ -101,8 +163,8 @@ public void setup() throws IOException { cc.doubleValue = Double.POSITIVE_INFINITY; cc.longValue = Long.MAX_VALUE; cc.stringValue = "Nested Hello World!"; + cc.uuidValue = UUID.randomUUID(); wrapper.component.nestedRecordValue = cc; - // result = roundTrip(wrapper); } @@ -137,4 +199,13 @@ public void testIntegerValue() { assertThat(result.component.intValue).isEqualTo(wrapper.component.intValue); } + @Test + public void testNestedUuidValue() { + assertThat(result.component.nestedRecordValue.uuidValue).isEqualTo(wrapper.component.nestedRecordValue.uuidValue); + } + + @Test + public void testUuidValue() { + assertThat(result.component.uuidValue).isEqualTo(wrapper.component.uuidValue); + } }