Skip to content

Commit 5d093ea

Browse files
committed
[Avro] Fix custom deserializers not being used
1 parent 30e7389 commit 5d093ea

File tree

3 files changed

+93
-11
lines changed

3 files changed

+93
-11
lines changed

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeDeserializer.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44

55
import com.fasterxml.jackson.annotation.JsonTypeInfo;
66
import com.fasterxml.jackson.core.JsonParser;
7-
import com.fasterxml.jackson.databind.BeanProperty;
8-
import com.fasterxml.jackson.databind.DeserializationContext;
9-
import com.fasterxml.jackson.databind.JavaType;
10-
import com.fasterxml.jackson.databind.JsonDeserializer;
7+
import com.fasterxml.jackson.databind.*;
118
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
129
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
1310
import com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase;
@@ -57,6 +54,13 @@ public Object deserializeTypedFromScalar(JsonParser p, DeserializationContext ct
5754

5855
@Override
5956
public Object deserializeTypedFromAny(JsonParser p, DeserializationContext ctxt) throws IOException {
57+
AnnotationIntrospector ai = ctxt.getAnnotationIntrospector();
58+
if (ai != null && _property != null) {
59+
JsonDeserializer<?> deser = ctxt.deserializerInstance(_property.getMember(), ai.findDeserializer(_property.getMember()));
60+
if (deser != null) {
61+
return deser.deserialize(p, ctxt);
62+
}
63+
}
6064
if (p.getTypeId() == null && getDefaultImpl() == null) {
6165
JsonDeserializer<Object> deser = _findDeserializer(ctxt, AvroSchemaHelper.getTypeId(_baseType));
6266
if (deser == null) {

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImplDecoder.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ public void skipString() throws IOException {
138138
@Override
139139
public ByteBuffer readBytes(ByteBuffer old) throws IOException {
140140
consumeToken(JsonToken.VALUE_EMBEDDED_OBJECT);
141+
byte[] value = _parser.getBinaryValue();
142+
if (old.capacity() >= value.length) {
143+
old.clear();
144+
old.put(value);
145+
old.flip();
146+
return old;
147+
}
141148
return ByteBuffer.wrap(_parser.getBinaryValue());
142149
}
143150

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package com.fasterxml.jackson.dataformat.avro.interop.annotations;
22

33
import java.io.IOException;
4-
import java.util.ArrayList;
5-
import java.util.Arrays;
6-
import java.util.HashMap;
7-
import java.util.Map;
4+
import java.nio.ByteBuffer;
5+
import java.util.*;
86

7+
import org.apache.avro.SchemaBuilder;
98
import org.apache.avro.io.Decoder;
109
import org.apache.avro.io.Encoder;
1110
import org.apache.avro.reflect.AvroEncode;
@@ -53,13 +52,16 @@ static class CustomComponent {
5352
@Nullable
5453
public Long longValue;
5554

55+
@AvroEncode(using = UuidAsBytesAvroEncoding.class)
56+
private UUID uuidValue;
57+
5658
protected CustomComponent() { }
5759
}
5860

5961
public static class ApacheImplEncoding extends CustomEncoding<CustomComponent> {
6062

6163
public ApacheImplEncoding() {
62-
schema = ApacheAvroInteropUtil.getJacksonSchema(CustomComponent.class);
64+
schema = ApacheAvroInteropUtil.getApacheSchema(CustomComponent.class);
6365
}
6466

6567
@Override
@@ -74,8 +76,67 @@ protected CustomComponent read(Object reuse, Decoder in) throws IOException {
7476

7577
}
7678

77-
protected Wrapper wrapper;
79+
public static class UuidAsBytesAvroEncoding extends CustomEncoding<UUID> {
80+
public static byte[] asByteArray(UUID uuid) {
81+
long msb = uuid.getMostSignificantBits();
82+
long lsb = uuid.getLeastSignificantBits();
83+
byte[] buffer = new byte[16];
84+
for (int i = 0; i < 8; i++) {
85+
buffer[i] = (byte) (msb >>> 8 * (7 - i));
86+
}
87+
for (int i = 8; i < 16; i++) {
88+
buffer[i] = (byte) (lsb >>> 8 * (7 - i));
89+
}
90+
return buffer;
91+
}
7892

93+
public static UUID toUUID(byte[] byteArray) {
94+
long msb = 0;
95+
long lsb = 0;
96+
for (int i = 0; i < 8; i++) { msb = (msb << 8) | (byteArray[i] & 0xff); }
97+
for (int i = 8; i < 16; i++) { lsb = (lsb << 8) | (byteArray[i] & 0xff); }
98+
return new UUID(msb, lsb);
99+
}
100+
101+
public UuidAsBytesAvroEncoding() {
102+
this.schema = SchemaBuilder.unionOf().nullType().and().bytesBuilder().endBytes().endUnion();
103+
}
104+
105+
@Override
106+
public void write(Object datum, Encoder encoder) throws IOException {
107+
if (datum == null) {
108+
encoder.writeIndex(0);
109+
encoder.writeNull();
110+
return;
111+
}
112+
encoder.writeIndex(1);
113+
encoder.writeBytes(asByteArray((UUID) datum));
114+
}
115+
116+
@Override
117+
public UUID read(Object datum, Decoder decoder) throws IOException {
118+
try {
119+
// get index in union
120+
int index = decoder.readIndex();
121+
if (index == 1) {
122+
// read in 16 bytes of data
123+
ByteBuffer b = ByteBuffer.allocate(16);
124+
decoder.readBytes(b);
125+
// convert
126+
UUID uuid = toUUID(b.array());
127+
return uuid;
128+
} else {
129+
decoder.readNull();
130+
// no uuid present
131+
return null;
132+
}
133+
} catch (Exception exception) {
134+
throw new IllegalStateException("Could not decode bytes into UUID", exception);
135+
}
136+
}
137+
}
138+
139+
protected Wrapper wrapper;
79140
protected Wrapper result;
80141

81142
@Before
@@ -92,6 +153,7 @@ public void setup() throws IOException {
92153
mv.put("cats", new ArrayList<Integer>());
93154
mv.put("dogs", new ArrayList<>(Arrays.asList(-1234, 56, 6767, 54134, 57, 86)));
94155
wrapper.component.stringValue = "Hello World!";
156+
wrapper.component.uuidValue = UUID.randomUUID();
95157

96158
CustomComponent cc = new CustomComponent();
97159
cc.byteValue = (byte) 42;
@@ -100,8 +162,8 @@ public void setup() throws IOException {
100162
cc.doubleValue = Double.POSITIVE_INFINITY;
101163
cc.longValue = Long.MAX_VALUE;
102164
cc.stringValue = "Nested Hello World!";
165+
cc.uuidValue = UUID.randomUUID();
103166
wrapper.component.nestedRecordValue = cc;
104-
105167
//
106168
result = roundTrip(wrapper);
107169
}
@@ -136,4 +198,13 @@ public void testIntegerValue() {
136198
assertThat(result.component.intValue).isEqualTo(wrapper.component.intValue);
137199
}
138200

201+
@Test
202+
public void testNestedUuidValue() {
203+
assertThat(result.component.nestedRecordValue.uuidValue).isEqualTo(wrapper.component.nestedRecordValue.uuidValue);
204+
}
205+
206+
@Test
207+
public void testUuidValue() {
208+
assertThat(result.component.uuidValue).isEqualTo(wrapper.component.uuidValue);
209+
}
139210
}

0 commit comments

Comments
 (0)