Skip to content

Commit f1ae27d

Browse files
authored
Merge pull request #59 from baharclerode/bah.AliasAnnotation
[Avro] Add support for @AvroAlias annotation
2 parents 33ba784 + c847085 commit f1ae27d

File tree

3 files changed

+166
-6
lines changed

3 files changed

+166
-6
lines changed

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/AvroSchemaHelper.java

+22-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import org.apache.avro.Schema;
1111
import org.apache.avro.Schema.Parser;
12+
import org.apache.avro.reflect.AvroAlias;
1213
import org.apache.avro.reflect.Stringable;
1314
import org.apache.avro.specific.SpecificData;
1415

@@ -197,12 +198,12 @@ protected static <T> T throwUnsupported() {
197198
* needs to have fields added to it.
198199
*/
199200
public static Schema initializeRecordSchema(BeanDescription bean) {
200-
return Schema.createRecord(
201+
return addAlias(Schema.createRecord(
201202
getName(bean.getType()),
202203
bean.findClassDescription(),
203204
getNamespace(bean.getType()),
204205
bean.getType().isTypeOrSubTypeOf(Throwable.class)
205-
);
206+
), bean);
206207
}
207208

208209
/**
@@ -221,7 +222,25 @@ public static Schema parseJsonSchema(String json) {
221222
* @return An {@link org.apache.avro.Schema.Type#ENUM ENUM} schema.
222223
*/
223224
public static Schema createEnumSchema(BeanDescription bean, List<String> values) {
224-
return Schema.createEnum(getName(bean.getType()), bean.findClassDescription(), getNamespace(bean.getType()), values);
225+
return addAlias(Schema.createEnum(
226+
getName(bean.getType()),
227+
bean.findClassDescription(),
228+
getNamespace(bean.getType()), values
229+
), bean);
230+
}
231+
232+
/**
233+
* Looks for {@link AvroAlias @AvroAlias} on {@code bean} and adds it to {@code schema} if it exists
234+
* @param schema Schema to which the alias should be added
235+
* @param bean Bean to inspect for type aliases
236+
* @return {@code schema}, possibly with an alias added
237+
*/
238+
public static Schema addAlias(Schema schema, BeanDescription bean) {
239+
AvroAlias ann = bean.getClassInfo().getAnnotation(AvroAlias.class);
240+
if (ann != null) {
241+
schema.addAlias(ann.alias(), ann.space().equals(AvroAlias.NULL) ? null : ann.space());
242+
}
243+
return schema;
225244
}
226245

227246
/**

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/AvroTestBase.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
import junit.framework.TestCase;
99

1010
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
11-
import com.fasterxml.jackson.core.*;
11+
import com.fasterxml.jackson.core.JsonParser;
12+
import com.fasterxml.jackson.core.JsonToken;
1213
import com.fasterxml.jackson.databind.ObjectMapper;
13-
import com.fasterxml.jackson.dataformat.avro.AvroSchema;
1414

1515
public abstract class AvroTestBase extends TestCase
1616
{
@@ -61,7 +61,7 @@ public abstract class AvroTestBase extends TestCase
6161
/**********************************************************
6262
*/
6363

64-
protected static class Employee
64+
public static class Employee
6565
{
6666
public Employee() { }
6767

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package com.fasterxml.jackson.dataformat.avro.interop.annotations;
2+
3+
import java.io.IOException;
4+
5+
import org.apache.avro.Schema;
6+
import org.apache.avro.SchemaCompatibility;
7+
import org.apache.avro.reflect.AvroAlias;
8+
import org.apache.avro.reflect.Nullable;
9+
import org.junit.Test;
10+
11+
import com.fasterxml.jackson.dataformat.avro.AvroTestBase;
12+
import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
16+
public class AvroAliasTest extends InteropTestBase {
17+
18+
@AvroAlias(alias = "Employee", space = "com.fasterxml.jackson.dataformat.avro.AvroTestBase$")
19+
public static class NewEmployee {
20+
21+
public String name;
22+
23+
public int age;
24+
25+
public String[] emails;
26+
27+
public NewEmployee boss;
28+
}
29+
30+
@AvroAlias(alias = "NewEmployee")
31+
public static class AliasedNameEmployee {
32+
33+
public String name;
34+
35+
public int age;
36+
37+
public String[] emails;
38+
39+
@Nullable
40+
public AliasedNameEmployee boss;
41+
}
42+
43+
@AvroAlias(alias = "Size", space = "com.fasterxml.jackson.dataformat.avro.AvroTestBase$")
44+
public static enum NewSize {
45+
SMALL,
46+
LARGE;
47+
}
48+
49+
@AvroAlias(alias = "NewestSize")
50+
public static enum NewerSize {
51+
SMALL,
52+
LARGE;
53+
}
54+
55+
@AvroAlias(alias = "NewerSize")
56+
public static enum NewestSize {
57+
SMALL,
58+
LARGE;
59+
}
60+
61+
@Test
62+
public void testAliasedRecordForwardsCompatible() throws IOException {
63+
Schema oldSchema = schemaFunctor.apply(AvroTestBase.Employee.class);
64+
Schema newSchema = schemaFunctor.apply(NewEmployee.class);
65+
//
66+
SchemaCompatibility.SchemaPairCompatibility compatibility =
67+
SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema);
68+
//
69+
assertThat(compatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE);
70+
}
71+
72+
@Test
73+
public void testAliasedRecordBackwardsCompatible() throws IOException {
74+
Schema oldSchema = schemaFunctor.apply(AvroTestBase.Employee.class);
75+
Schema newSchema = schemaFunctor.apply(NewEmployee.class);
76+
//
77+
SchemaCompatibility.SchemaPairCompatibility compatibility =
78+
SchemaCompatibility.checkReaderWriterCompatibility(oldSchema, newSchema);
79+
//
80+
assertThat(compatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.INCOMPATIBLE);
81+
}
82+
83+
@Test
84+
public void testAliasedRecordForwardsCompatibleSameNamespace() throws IOException {
85+
Schema oldSchema = schemaFunctor.apply(NewEmployee.class);
86+
Schema newSchema = schemaFunctor.apply(AliasedNameEmployee.class);
87+
//
88+
SchemaCompatibility.SchemaPairCompatibility compatibility =
89+
SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema);
90+
//
91+
assertThat(compatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE);
92+
}
93+
94+
@Test
95+
public void testAliasedRecordBackwardsCompatibleSameNamespace() throws IOException {
96+
Schema oldSchema = schemaFunctor.apply(NewEmployee.class);
97+
Schema newSchema = schemaFunctor.apply(AliasedNameEmployee.class);
98+
//
99+
SchemaCompatibility.SchemaPairCompatibility compatibility =
100+
SchemaCompatibility.checkReaderWriterCompatibility(oldSchema, newSchema);
101+
//
102+
assertThat(compatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.INCOMPATIBLE);
103+
}
104+
105+
@Test
106+
public void testAliasedEnumForwardsCompatible() throws IOException {
107+
Schema oldSchema = schemaFunctor.apply(AvroTestBase.Size.class);
108+
Schema newSchema = schemaFunctor.apply(NewSize.class);
109+
//
110+
SchemaCompatibility.SchemaPairCompatibility compatibility =
111+
SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema);
112+
//
113+
assertThat(compatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE);
114+
}
115+
116+
@Test
117+
public void testAliasedEnumBackwardsCompatible() throws IOException {
118+
Schema oldSchema = schemaFunctor.apply(AvroTestBase.Size.class);
119+
Schema newSchema = schemaFunctor.apply(NewSize.class);
120+
//
121+
SchemaCompatibility.SchemaPairCompatibility compatibility =
122+
SchemaCompatibility.checkReaderWriterCompatibility(oldSchema, newSchema);
123+
//
124+
assertThat(compatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.INCOMPATIBLE);
125+
}
126+
127+
@Test
128+
public void testAliasedEnumForwardsAndBackwardsCompatible() throws IOException {
129+
Schema oldSchema = schemaFunctor.apply(NewerSize.class);
130+
Schema newSchema = schemaFunctor.apply(NewestSize.class);
131+
//
132+
SchemaCompatibility.SchemaPairCompatibility backwardsCompatibility =
133+
SchemaCompatibility.checkReaderWriterCompatibility(oldSchema, newSchema);
134+
SchemaCompatibility.SchemaPairCompatibility forwardsCompatibility =
135+
SchemaCompatibility.checkReaderWriterCompatibility(newSchema, oldSchema);
136+
//
137+
assertThat(backwardsCompatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE);
138+
assertThat(forwardsCompatibility.getType()).isEqualTo(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE);
139+
}
140+
141+
}

0 commit comments

Comments
 (0)