in lang/java/avro/src/main/java/org/apache/avro/SchemaCompatibility.java [262:391]
private SchemaCompatibilityResult calculateCompatibility(final Schema reader, final Schema writer,
final Deque<String> location) {
assert (reader != null);
assert (writer != null);
SchemaCompatibilityResult result = SchemaCompatibilityResult.compatible();
if (reader.getType() == writer.getType()) {
switch (reader.getType()) {
case NULL:
case BOOLEAN:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
case BYTES:
case STRING: {
return result;
}
case ARRAY: {
return result
.mergedWith(getCompatibility("items", reader.getElementType(), writer.getElementType(), location));
}
case MAP: {
return result.mergedWith(getCompatibility("values", reader.getValueType(), writer.getValueType(), location));
}
case FIXED: {
result = result.mergedWith(checkSchemaNames(reader, writer, location));
return result.mergedWith(checkFixedSize(reader, writer, location));
}
case ENUM: {
result = result.mergedWith(checkSchemaNames(reader, writer, location));
return result.mergedWith(checkReaderEnumContainsAllWriterEnumSymbols(reader, writer, location));
}
case RECORD: {
result = result.mergedWith(checkSchemaNames(reader, writer, location));
return result.mergedWith(checkReaderWriterRecordFields(reader, writer, location));
}
case UNION: {
// Check that each individual branch of the writer union can be decoded:
int i = 0;
for (final Schema writerBranch : writer.getTypes()) {
location.addFirst(Integer.toString(i));
SchemaCompatibilityResult compatibility = getCompatibility(reader, writerBranch);
if (compatibility.getCompatibility() == SchemaCompatibilityType.INCOMPATIBLE) {
String message = String.format("reader union lacking writer type: %s", writerBranch.getType());
result = result.mergedWith(SchemaCompatibilityResult.incompatible(
SchemaIncompatibilityType.MISSING_UNION_BRANCH, reader, writer, message, asList(location)));
}
location.removeFirst();
i++;
}
// Each schema in the writer union can be decoded with the reader:
return result;
}
default: {
throw new AvroRuntimeException("Unknown schema type: " + reader.getType());
}
}
} else {
// Reader and writer have different schema types:
// Reader compatible with all branches of a writer union is compatible
if (writer.getType() == Schema.Type.UNION) {
int index = 0;
for (Schema s : writer.getTypes()) {
result = result.mergedWith(getCompatibility(Integer.toString(index), reader, s, location));
index++;
}
return result;
}
switch (reader.getType()) {
case NULL:
return result.mergedWith(typeMismatch(reader, writer, location));
case BOOLEAN:
return result.mergedWith(typeMismatch(reader, writer, location));
case INT:
return result.mergedWith(typeMismatch(reader, writer, location));
case LONG: {
return (writer.getType() == Type.INT) ? result : result.mergedWith(typeMismatch(reader, writer, location));
}
case FLOAT: {
return ((writer.getType() == Type.INT) || (writer.getType() == Type.LONG)) ? result
: result.mergedWith(typeMismatch(reader, writer, location));
}
case DOUBLE: {
return ((writer.getType() == Type.INT) || (writer.getType() == Type.LONG) || (writer.getType() == Type.FLOAT))
? result
: result.mergedWith(typeMismatch(reader, writer, location));
}
case BYTES: {
return (writer.getType() == Type.STRING) ? result : result.mergedWith(typeMismatch(reader, writer, location));
}
case STRING: {
return (writer.getType() == Type.BYTES) ? result : result.mergedWith(typeMismatch(reader, writer, location));
}
case ARRAY:
return result.mergedWith(typeMismatch(reader, writer, location));
case MAP:
return result.mergedWith(typeMismatch(reader, writer, location));
case FIXED:
return result.mergedWith(typeMismatch(reader, writer, location));
case ENUM:
return result.mergedWith(typeMismatch(reader, writer, location));
case RECORD:
return result.mergedWith(typeMismatch(reader, writer, location));
case UNION: {
for (final Schema readerBranch : reader.getTypes()) {
SchemaCompatibilityResult compatibility = getCompatibility(readerBranch, writer);
if (compatibility.getCompatibility() == SchemaCompatibilityType.COMPATIBLE) {
return result;
}
}
// No branch in the reader union has been found compatible with the writer
// schema:
String message = String.format("reader union lacking writer type: %s", writer.getType());
return result.mergedWith(SchemaCompatibilityResult
.incompatible(SchemaIncompatibilityType.MISSING_UNION_BRANCH, reader, writer, message, asList(location)));
}
default: {
throw new AvroRuntimeException("Unknown schema type: " + reader.getType());
}
}
}
}