You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avro.apache.org by "xia0c (Jira)" <ji...@apache.org> on 2019/10/21 15:49:00 UTC
[jira] [Created] (AVRO-2602) Updating breaks backward compatibility
by throwing AvroTypeException in some cases
xia0c created AVRO-2602:
---------------------------
Summary: Updating breaks backward compatibility by throwing AvroTypeException in some cases
Key: AVRO-2602
URL: https://issues.apache.org/jira/browse/AVRO-2602
Project: Apache Avro
Issue Type: Bug
Affects Versions: 1.9.1, 1.8.2, 1.9.0, 1.8.1, 1.8.0
Reporter: xia0c
When I try to update Avro from 1.7.7 to the newer version. The following code:
{code:java}
@Test
public void Demo() throws IOException{
Schema schema = Schema.parse("{\"type\": \"enum\", \"name\": \"MyEnum\", \"symbols\": [\"A\", \"B\", \"C\"]}");
Map<String, String> expectedA = new java.util.HashMap();
expectedA.put("", "A");
assertEquals(expectedA, write(schema, "A"));
}
private Map<String, String> write(Schema schema, Object datum) throws IOException {
DatumWriter<Object> writer = new GenericDatumWriter<Object>(schema);
Map<String, String> out = new java.util.HashMap();
KeyValueEncoder encoder = new KeyValueEncoder(schema, out);
writer.write(datum, encoder);
return out;
}
}
class KeyValueEncoder extends ParsingEncoder implements Parser.ActionHandler {
final Parser parser;
protected BitSet isEmpty = new BitSet();
private java.util.Map<String, String> out;
KeyValueEncoder(Schema sc, java.util.Map<String, String> out) throws IOException {
configure(out);
this.parser =
new Parser(new JsonGrammarGenerator().generate(sc), this);
}
public void flush() throws IOException {
// Do nothing
}
public KeyValueEncoder configure(java.util.Map<String, String> newOut) throws IOException {
this.out = newOut;
return this;
}
/////////////////////////////////////////////////////////////////////////////
@Override
public void writeNull() throws IOException {
parser.advance(Symbol.NULL);
}
@Override
public void writeBoolean(boolean b) throws IOException {
parser.advance(Symbol.BOOLEAN);
out.put(getKeyPathString(), Boolean.toString(b));
}
@Override
public void writeInt(int n) throws IOException {
parser.advance(Symbol.INT);
out.put(getKeyPathString(), Integer.toString(n));
}
@Override
public void writeLong(long n) throws IOException {
parser.advance(Symbol.LONG);
out.put(getKeyPathString(), Long.toString(n));
}
@Override
public void writeFloat(float f) throws IOException {
parser.advance(Symbol.FLOAT);
out.put(getKeyPathString(), Float.toString(f));
}
@Override
public void writeDouble(double d) throws IOException {
parser.advance(Symbol.DOUBLE);
out.put(getKeyPathString(), Double.toString(d));
}
@Override
public void writeString(Utf8 utf8) throws IOException {
writeString(utf8.toString());
}
@Override
public void writeString(String str) throws IOException {
parser.advance(Symbol.STRING);
trace("writeString(" + str + ")");
if (parser.topSymbol() == Symbol.MAP_KEY_MARKER) {
parser.advance(Symbol.MAP_KEY_MARKER);
pushKeyPathComponent(str);
// out.writeFieldName(str);
} else {
out.put(getKeyPathString(), str);
}
}
@Override
public void writeBytes(ByteBuffer bytes) throws IOException {
if (bytes.hasArray()) {
writeBytes(bytes.array(), bytes.position(), bytes.remaining());
} else {
byte[] b = new byte[bytes.remaining()];
for (int i = 0; i < b.length; i++) {
b[i] = bytes.get();
}
writeBytes(b);
}
}
@Override
public void writeBytes(byte[] bytes, int start, int len) throws IOException {
parser.advance(Symbol.BYTES);
writeByteArray(bytes, start, len);
}
private void writeByteArray(byte[] bytes, int start, int len) throws IOException {
out.put(getKeyPathString(), new String(bytes, start, len, "UTF-8"));
}
@Override
public void writeFixed(byte[] bytes, int start, int len) throws IOException {
throw new IOException("Fixed encoding is not implemented");
}
@Override
public void writeEnum(int e) throws IOException {
parser.advance(Symbol.ENUM);
Symbol.EnumLabelsAction top = (Symbol.EnumLabelsAction) parser.popSymbol();
trace("writeEnum(" + e + " : " + top.getLabel(e) + ")");
if (e < 0 || e >= top.size) {
throw new AvroTypeException(
"Enumeration out of range: max is " +
top.size + " but received " + e);
}
out.put(getKeyPathString(), top.getLabel(e));
}
@Override
public void writeArrayStart() throws IOException {
throw new IOException("Array encoding is not implemented");
}
@Override
public void writeArrayEnd() throws IOException {
if (! isEmpty.get(pos)) {
parser.advance(Symbol.ITEM_END);
}
pop();
parser.advance(Symbol.ARRAY_END);
// out.writeEndArray();
}
@Override
public void writeMapStart() throws IOException {
push();
isEmpty.set(depth());
parser.advance(Symbol.MAP_START);
// out.writeStartObject();
}
@Override
public void writeMapEnd() throws IOException {
if (! isEmpty.get(pos)) {
parser.advance(Symbol.ITEM_END);
popKeyPathComponent();
}
pop();
parser.advance(Symbol.MAP_END);
// out.writeEndObject();
}
@Override
public void startItem() throws IOException {
trace("startItem");
if (! isEmpty.get(pos)) {
parser.advance(Symbol.ITEM_END);
popKeyPathComponent();
}
super.startItem();
isEmpty.clear(depth());
}
@Override
public void writeIndex(int unionIndex) throws IOException {
parser.advance(Symbol.UNION);
Symbol.Alternative top = (Symbol.Alternative) parser.popSymbol();
Symbol symbol = top.getSymbol(unionIndex);
if (symbol != Symbol.NULL) {
pushKeyPathComponent(top.getLabel(unionIndex));
parser.pushSymbol(Symbol.UNION_END);
}
parser.pushSymbol(symbol);
}
public Symbol doAction(Symbol input, Symbol top) throws IOException {
if (top instanceof Symbol.FieldAdjustAction) {
Symbol.FieldAdjustAction fa = (Symbol.FieldAdjustAction) top;
pushKeyPathComponent(fa.fname);
} else if (top == Symbol.RECORD_START) {
// out.writeStartObject();
} else if (top == Symbol.RECORD_END || top == Symbol.UNION_END) {
// out.writeEndObject();
} else if (top == Symbol.FIELD_END) {
popKeyPathComponent();
} else {
throw new AvroTypeException("Unknown action symbol " + top);
}
return null;
}
/////////////////////////////////////////////////////////////////////////////
// Key path
private java.util.ArrayList<String> keyPath = new java.util.ArrayList();
private void pushKeyPathComponent(String component) {
keyPath.add(component);
}
private void popKeyPathComponent() {
keyPath.remove(keyPath.size() - 1);
}
private String getKeyPathString() {
return StringUtils.join(keyPath, '|');
}
/////////////////////////////////////////////////////////////////////////////
private void trace(String s) {
System.out.println(s + ":\t topSymbol=" + parser.topSymbol() + " keyPath=" + getKeyPathString());
}
}
{code}
Throws an AvroTypeException error:
{code:java}
org.apache.avro.AvroTypeException: Not an enum: A for schema: {"type":"enum","name":"MyEnum","symbols":["A","B","C"]}
at org.apache.avro.generic.GenericDatumWriter.writeEnum(GenericDatumWriter.java:218)
at org.apache.avro.generic.GenericDatumWriter.writeWithoutConversion(GenericDatumWriter.java:133)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:82)
at org.apache.avro.generic.GenericDatumWriter.write(GenericDatumWriter.java:72)
at UTD.SeLab.BBI.BugDetection.TestAvro.write(TestAvro.java:42)
at UTD.SeLab.BBI.BugDetection.TestAvro.Demo(TestAvro.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
{code}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)