[ 
https://issues.apache.org/jira/browse/AVRO-2602?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16969808#comment-16969808
 ] 

Sean Busbey commented on AVRO-2602:
-----------------------------------

1.7.7 -> 1.8 is a major version change for Avro. AVRO-997 is marked as 
backwards incompatible. What's the matter at hand [~lingchao]?

> 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.8.0, 1.8.1, 1.9.0, 1.8.2, 1.9.1
>            Reporter: xia0c
>            Priority: Major
>
> 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)

Reply via email to