Hi,
I'm trying to test versioning in Avro data serialization and I'm seeing an
AvroTypeException thrown when I add a new field to an optional record.
Here's the V1 schema:
@namespace("v1")
protocol Service {
record Result {
string id;
string text;
boolean isRecommended;
}
record Response {
int version;
boolean success;
union {null, Result} results;
}
}
V2 (added isFeatured to Result):
@namespace("v2")
protocol Service {
record Result {
string id;
string text;
boolean isRecommended;
boolean isFeatured;
}
record Response {
int version;
boolean success;
union {null, Result} results;
}
}
Here's the code:
import org.apache.avro.Protocol;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
public class AvroServiceMain {
public static void main(String[] args)
throws Exception {
Protocol protocol_v2 = Protocol.parse(new File("TestCase_v2.avdr"));
Protocol protocol_v1 = Protocol.parse(new File("TestCase_v1.avdr"));
SpecificDatumWriter< v2.Response> responseSerializer = new
SpecificDatumWriter< v2.Response>(protocol_v2.getType("Response"));
SpecificDatumReader< v1.Response> responseDeserializer = new
SpecificDatumReader<
v1.Response>(protocol_v2.getType("Response"),protocol_v1.getType("Response"));
v2.Response responseV2 = new v2.Response();
responseV2.setVersion(2);
responseV2.setSuccess(true);
v2.Result result = new v2.Result();
result.setId("1234");
result.setIsRecommended(false);
result.setIsFeatured(true);
result.setText("Some text...");
responseV2.setResults(result);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().directBinaryEncoder(baos,
null);
responseSerializer.write(responseV2, encoder);
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
BinaryDecoder decoder = DecoderFactory.get().directBinaryDecoder(bais,
null);
v1.Response responseV1 = new v1.Response();
responseDeserializer.read(responseV1, decoder);
System.out.println(responseV1);
}
}
Here's the exception thrown:
Exception in thread "main" org.apache.avro.AvroTypeException: Found {
"type" : "record",
"name" : "Result",
"namespace" : "v2",
"fields" : [ {
"name" : "id",
"type" : "string"
}, {
"name" : "text",
"type" : "string"
}, {
"name" : "isRecommended",
"type" : "boolean"
}, {
"name" : "isFeatured",
"type" : "boolean"
} ]
}, expecting [ "null", {
"type" : "record",
"name" : "Result",
"namespace" : "v1",
"fields" : [ {
"name" : "id",
"type" : "string"
}, {
"name" : "text",
"type" : "string"
}, {
"name" : "isRecommended",
"type" : "boolean"
} ]
} ]
at org.apache.avro.io.ResolvingDecoder.doAction(ResolvingDecoder.java:231)
at org.apache.avro.io.parsing.Parser.advance(Parser.java:88)
at
org.apache.avro.io.ResolvingDecoder.readIndex(ResolvingDecoder.java:206)
at
org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:148)
at
org.apache.avro.generic.GenericDatumReader.readRecord(GenericDatumReader.java:173)
at
org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:144)
at
org.apache.avro.generic.GenericDatumReader.read(GenericDatumReader.java:135)
at TestCaseMain.main(TestCaseMain.java:44)
The exception doesn't occur when the field is not Optional.
Am I missing something or does this look like a bug?
Thanks,
Francois.