Skip to content

Commit 9f3cdae

Browse files
committed
Refactoring to support optional enabling of "enhanced type handling"...
1 parent c8a09d3 commit 9f3cdae

File tree

9 files changed

+90
-54
lines changed

9 files changed

+90
-54
lines changed

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

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ public class AvroAnnotationIntrospector extends AnnotationIntrospector
4545
{
4646
private static final long serialVersionUID = 1L;
4747

48+
protected final boolean _useEnhancedTyping;
49+
50+
public AvroAnnotationIntrospector() {
51+
_useEnhancedTyping = true;
52+
}
53+
4854
@Override
4955
public Version version() {
5056
return PackageVersion.VERSION;
@@ -98,7 +104,7 @@ protected PropertyName _findName(Annotated a)
98104
@Override
99105
public Boolean hasRequiredMarker(AnnotatedMember m) {
100106
if (_hasAnnotation(m, Nullable.class)) {
101-
return false;
107+
return Boolean.FALSE;
102108
}
103109
return null;
104110
}
@@ -133,13 +139,14 @@ public Object findSerializer(Annotated a) {
133139
}
134140

135141
@Override
136-
public List<NamedType> findSubtypes(Annotated a) {
137-
Union union = _findAnnotation(a, Union.class);
138-
if (union == null) {
142+
public List<NamedType> findSubtypes(Annotated a)
143+
{
144+
Class<?>[] types = _getUnionTypes(a);
145+
if (types == null) {
139146
return null;
140147
}
141-
ArrayList<NamedType> names = new ArrayList<>(union.value().length);
142-
for (Class<?> subtype : union.value()) {
148+
ArrayList<NamedType> names = new ArrayList<>(types.length);
149+
for (Class<?> subtype : types) {
143150
names.add(new NamedType(subtype, AvroSchemaHelper.getTypeId(subtype)));
144151
}
145152
return names;
@@ -161,11 +168,32 @@ public TypeResolverBuilder<?> findPropertyContentTypeResolver(MapperConfig<?> co
161168
}
162169

163170
protected TypeResolverBuilder<?> _findTypeResolver(MapperConfig<?> config, Annotated ann, JavaType baseType) {
164-
TypeResolverBuilder<?> resolver = new AvroTypeResolverBuilder();
165-
JsonTypeInfo typeInfo = ann.getAnnotation(JsonTypeInfo.class);
166-
if (typeInfo != null && typeInfo.defaultImpl() != JsonTypeInfo.class) {
167-
resolver = resolver.defaultImpl(typeInfo.defaultImpl());
171+
// 14-Apr-2017, tatu: Only enable polymorphic type handling if explicitly annotated; otherwise
172+
// we have no way to determine this. Part of the problem is that we have no access to
173+
// schema infomration here, which would contain information.
174+
if (_useEnhancedTyping || (_getUnionTypes(ann) != null)) {
175+
TypeResolverBuilder<?> resolver = new AvroTypeResolverBuilder();
176+
JsonTypeInfo typeInfo = ann.getAnnotation(JsonTypeInfo.class);
177+
if (typeInfo != null && typeInfo.defaultImpl() != JsonTypeInfo.class) {
178+
resolver = resolver.defaultImpl(typeInfo.defaultImpl());
179+
}
180+
return resolver;
168181
}
169-
return resolver;
182+
return null;
183+
}
184+
185+
protected Class<?>[] _getUnionTypes(Annotated a) {
186+
Union ann = _findAnnotation(a, Union.class);
187+
if (ann != null) {
188+
// 14-Apr-2017, tatu: I think it makes sense to require non-empty List, as this allows
189+
// disabling annotation with overrides. But one could even consider requiring more than
190+
// one (where single type is not really polymorphism)... for now, however, just one
191+
// is acceptable, and maybe that has valid usages.
192+
Class<?>[] c = ann.value();
193+
if (c.length > 0) {
194+
return c;
195+
}
196+
}
197+
return null;
170198
}
171199
}

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

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Collection;
44

5+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
56
import com.fasterxml.jackson.databind.DeserializationConfig;
67
import com.fasterxml.jackson.databind.JavaType;
78
import com.fasterxml.jackson.databind.SerializationConfig;
@@ -18,35 +19,38 @@
1819
public class AvroTypeResolverBuilder extends StdTypeResolverBuilder {
1920

2021
public AvroTypeResolverBuilder() {
21-
super();
22-
typeIdVisibility(false).typeProperty("@class");
22+
super(JsonTypeInfo.Id.CUSTOM,
23+
JsonTypeInfo.As.PROPERTY, // N/A for custom
24+
"@class" // similarly, N/A
25+
);
2326
}
2427

2528
@Override
26-
public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
29+
public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType,
30+
Collection<NamedType> subtypes) {
2731
// All type information is encoded in the schema, never in the data.
2832
return null;
2933
}
3034

3135
@Override
32-
public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) {
33-
JavaType defaultImpl = null;
34-
if (getDefaultImpl() != null) {
35-
defaultImpl = config.constructType(getDefaultImpl());
36-
}
37-
36+
public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType,
37+
Collection<NamedType> subtypes)
38+
{
39+
Class<?> rawDefault = getDefaultImpl();
40+
JavaType defaultImpl = (rawDefault == null) ? null :
41+
config.constructType(rawDefault);
3842
return new AvroTypeDeserializer(baseType,
39-
idResolver(config, baseType, subtypes, true, true),
40-
getTypeProperty(),
41-
isTypeIdVisible(),
42-
defaultImpl
43+
idResolver(config, baseType, subtypes, true, true),
44+
getTypeProperty(),
45+
isTypeIdVisible(),
46+
defaultImpl
4347
);
44-
4548
}
4649

4750
@Override
48-
protected TypeIdResolver idResolver(MapperConfig<?> config, JavaType baseType, Collection<NamedType> subtypes, boolean forSer,
49-
boolean forDeser) {
51+
protected TypeIdResolver idResolver(MapperConfig<?> config, JavaType baseType,
52+
Collection<NamedType> subtypes, boolean forSer,
53+
boolean forDeser) {
5054
return new AvroTypeIdResolver(baseType, config.getTypeFactory(), subtypes);
5155
}
5256
}

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/ApacheAvroInteropUtil.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import com.fasterxml.jackson.dataformat.avro.AvroMapper;
2121
import com.fasterxml.jackson.dataformat.avro.AvroModule;
2222
import com.fasterxml.jackson.dataformat.avro.AvroSchema;
23+
import com.fasterxml.jackson.dataformat.avro.testsupport.BiFunction;
24+
import com.fasterxml.jackson.dataformat.avro.testsupport.Function;
2325

2426
/**
2527
* Utilities and helper functions to aid compatibility testing between Jackson and Apache Avro implementations
@@ -141,14 +143,6 @@ protected String getSchemaName(Object datum) {
141143
}
142144
};
143145

144-
public interface BiFunction<T, U, V> {
145-
V apply(T first, U second) throws IOException;
146-
}
147-
148-
public interface Function<T, U> {
149-
U apply(T input) throws IOException;
150-
}
151-
152146
/**
153147
* Deserialize an avro-encoded payload using the given {@code schema} and Apache implementation
154148
*
@@ -206,12 +200,8 @@ public static Schema getApacheSchema(Type type) {
206200
*
207201
* @return Schema for {@code type}
208202
*/
209-
public static Schema getJacksonSchema(Type type) {
210-
try {
211-
return MAPPER.schemaFor(MAPPER.constructType(type)).getAvroSchema();
212-
} catch (JsonMappingException e) {
213-
throw new RuntimeException("Could not generate schema for " + type, e);
214-
}
203+
public static Schema getJacksonSchema(Type type) throws IOException {
204+
return MAPPER.schemaFor(MAPPER.constructType(type)).getAvroSchema();
215205
}
216206

217207
/**

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/InteropTestBase.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
import org.junit.runner.RunWith;
99
import org.junit.runners.Parameterized;
1010

11+
import com.fasterxml.jackson.dataformat.avro.testsupport.BiFunction;
12+
import com.fasterxml.jackson.dataformat.avro.testsupport.Function;
13+
1114
import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.*;
1215

1316
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ protected CustomComponent() { }
5959
@SuppressWarnings("unchecked")
6060
public static class ApacheImplEncoding extends CustomEncoding<CustomComponent> {
6161

62-
public ApacheImplEncoding() {
62+
public ApacheImplEncoding() throws IOException {
6363
schema = ApacheAvroInteropUtil.getJacksonSchema(CustomComponent.class);
6464
}
6565

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ public static class OverriddenFieldSchema {
4646
}
4747

4848
@Test
49-
public void testJacksonClassDescription() {
49+
public void testJacksonClassDescription() throws Exception {
5050
Schema schema = ApacheAvroInteropUtil.getJacksonSchema(OverriddenFieldSchema.class);
5151
//
5252
assertThat(schema.getDoc()).isEqualTo("A cool class!");
5353
}
5454

5555
@Test
56-
public void testJacksonPropertyDescription() {
56+
public void testJacksonPropertyDescription() throws Exception {
5757
Schema schema = ApacheAvroInteropUtil.getJacksonSchema(OverriddenFieldSchema.class);
5858
//
5959
assertThat(schema.getField("recursiveOverride").doc()).isEqualTo("the best field in the world");

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveArrayTest.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.io.IOException;
44

5-
import lombok.Data;
65
import org.junit.Test;
76

87
import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase;
@@ -14,16 +13,14 @@
1413
*/
1514
public class RecordWithPrimitiveArrayTest extends InteropTestBase
1615
{
17-
18-
@Data
1916
public static class TestRecord {
20-
private byte[] byteArrayField = new byte[0];
21-
private short[] shortArrayField = new short[0];
22-
private char[] characterArrayField = new char[0];
23-
private int[] integerArrayField = new int[0];
24-
private long[] longArrayField = new long[0];
25-
private float[] floatArrayField = new float[0];
26-
private double[] doubleArrayField = new double[0];
17+
public byte[] byteArrayField = new byte[0];
18+
public short[] shortArrayField = new short[0];
19+
public char[] characterArrayField = new char[0];
20+
public int[] integerArrayField = new int[0];
21+
public long[] longArrayField = new long[0];
22+
public float[] floatArrayField = new float[0];
23+
public double[] doubleArrayField = new double[0];
2724
}
2825

2926
@Test
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.fasterxml.jackson.dataformat.avro.testsupport;
2+
3+
import java.io.IOException;
4+
5+
public interface BiFunction<T, U, V> {
6+
V apply(T first, U second) throws IOException;
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.fasterxml.jackson.dataformat.avro.testsupport;
2+
3+
import java.io.IOException;
4+
5+
public interface Function<T, U> {
6+
U apply(T input) throws IOException;
7+
}

0 commit comments

Comments
 (0)