Skip to content

Commit 598ef8d

Browse files
committed
Merge branch '2.8'
2 parents 7aced0e + 954a133 commit 598ef8d

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

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

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.fasterxml.jackson.dataformat.avro;
22

3+
import java.util.Set;
34
import java.util.concurrent.atomic.AtomicReference;
45

56
import org.apache.avro.Schema;
7+
import org.apache.avro.Schema.Type;
68
import org.apache.avro.SchemaCompatibility;
79
import org.apache.avro.SchemaCompatibility.SchemaCompatibilityType;
810
import org.apache.avro.SchemaCompatibility.SchemaPairCompatibility;
@@ -75,21 +77,50 @@ public AvroSchema withReaderSchema(AvroSchema readerSchema)
7577
w = Schema.applyAliases(w, r);
7678

7779
// and then use Avro std lib to validate compatibility
80+
81+
// 16-Jun-2017, tatu: First, a very common case is for Record names not
82+
// to match; so let's check that first
83+
if (r.getType() == w.getType()) {
84+
if (!_schemaNamesEqual(w, r)) {
85+
throw new JsonMappingException(null, String.format(
86+
"Incompatible writer/reader schemas: root %ss have different names (\"%s\" vs \"%s\"), no match via aliases",
87+
r.getType().getName(), w.getFullName(), r.getFullName()));
88+
}
89+
}
90+
7891
SchemaPairCompatibility comp;
7992
try {
8093
comp = SchemaCompatibility.checkReaderWriterCompatibility(r, w);
8194
} catch (Exception e) {
8295
throw new JsonMappingException(null, String.format(
83-
"Failed to resolve given reader/writer schemas, problem: (%s) %s",
96+
"Failed to resolve given writer/reader schemas, problem: (%s) %s",
8497
e.getClass().getName(), e.getMessage()));
8598
}
8699
if (comp.getType() != SchemaCompatibilityType.COMPATIBLE) {
87-
throw new JsonMappingException(null, String.format("Incompatible reader/writer schema: %s",
100+
throw new JsonMappingException(null, String.format("Incompatible writer/reader schemas: %s",
88101
comp.getDescription()));
89102
}
90103
return Resolving.create(w, r);
91104
}
92105

106+
private boolean _schemaNamesEqual(Schema w, Schema r)
107+
{
108+
final String wname = w.getFullName();
109+
final String rname = r.getFullName();
110+
111+
if ((wname == rname) ||
112+
((wname != null) && wname.equals(rname))) {
113+
return true;
114+
}
115+
116+
// but may also have alias. NOTE! Avro lib itself does this, and we rely
117+
// on it, but basically only `NamedSchema` do NOT throw exception. But
118+
// we have no way of checking -- need to trust other cases bail out before
119+
// this (which they do). Unclean but... that's avrolib for you.
120+
Set<String> aliases = r.getAliases();
121+
return aliases.contains(wname);
122+
}
123+
93124
/**
94125
* Similar to {@link #withReaderSchema} but will NOT verify compatibility of schemas:
95126
* this means that certain problems (such as missing default value for a newly added

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schemaev/SimpleEvolutionTest.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class SimpleEvolutionTest extends AvroTestBase
2323
" { 'name':'x', 'type':'int' }\n"+
2424
" ]\n"+
2525
"}\n");
26-
26+
2727
static String SCHEMA_XY_JSON = aposToQuotes("{\n"+
2828
" 'type':'record',\n"+
2929
" 'name':'EvolvingPoint',\n"+
@@ -43,6 +43,16 @@ public class SimpleEvolutionTest extends AvroTestBase
4343
" ]\n"+
4444
"}\n");
4545

46+
static String SCHEMA_XYZ_RENAMED_JSON = aposToQuotes("{\n"+
47+
" 'type':'record',\n"+
48+
" 'name':'EvolvingPoint2',\n"+
49+
" 'fields':[\n"+
50+
" { 'name':'z', 'type':'int', 'default': 99 },\n"+
51+
" { 'name':'y', 'type':'int' },\n"+
52+
" { 'name':'x', 'type':'int' }\n"+
53+
" ]\n"+
54+
"}\n");
55+
4656
// and one with X + T and an Array
4757
static String SCHEMA_XAY_JSON = aposToQuotes("{\n"+
4858
" 'type':'record',\n"+
@@ -311,8 +321,9 @@ public void testFailNewFieldNoDefault() throws Exception
311321
srcSchema.withReaderSchema(dstSchema);
312322
fail("Should not pass");
313323
} catch (JsonMappingException e) {
314-
// 06-Feb-2016, tatu: Extremely lame error message by avro lib. Should consider
324+
// 06-Feb-2017, tatu: Extremely lame error message by avro lib. Should consider
315325
// rewriting to give some indication of issues...
326+
verifyException(e, "Incompatible writer/reader schemas");
316327
verifyException(e, "Data encoded using writer schema");
317328
verifyException(e, "will or may fail to decode using reader schema");
318329
}
@@ -321,4 +332,23 @@ public void testFailNewFieldNoDefault() throws Exception
321332
AvroSchema risky = srcSchema.withUnsafeReaderSchema(dstSchema);
322333
assertNotNull(risky);
323334
}
335+
336+
public void testFailNameChangeNoAlias() throws Exception
337+
{
338+
final AvroSchema srcSchema = MAPPER.schemaFrom(SCHEMA_XYZ_JSON);
339+
final AvroSchema dstSchema = MAPPER.schemaFrom(SCHEMA_XYZ_RENAMED_JSON);
340+
try {
341+
srcSchema.withReaderSchema(dstSchema);
342+
fail("Should not pass");
343+
} catch (JsonMappingException e) {
344+
// 16-Jun-2017, tatu: As is, names must match, so...
345+
verifyException(e, "Incompatible writer/reader schemas");
346+
verifyException(e, "root records have different names");
347+
verifyException(e, "\"EvolvingPoint\"");
348+
verifyException(e, "\"EvolvingPoint2\"");
349+
}
350+
// However... should be possible with unsafe alternative
351+
AvroSchema risky = srcSchema.withUnsafeReaderSchema(dstSchema);
352+
assertNotNull(risky);
353+
}
324354
}

0 commit comments

Comments
 (0)