You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@avro.apache.org by "ehud.lev" <eh...@gmail.com> on 2014/02/25 14:08:52 UTC

Re: Enum & backward compatibility in distributed services...

Hi,
I am one of the developers in Amichay's group.
I manage to create a small POC that solve this issue.
First I updated the enum template and set it using the avro plugin (I 
add enum.vm below), so I got a similar class as you wrote.

In addition, I changed the code of the SpecificDatumReader (added 
below). I am pretty sure that it will work with an extension as well.
The code is calling in reflection to the class constructor with the 
symbol value even if it does not exist in the expected schema.
I catch the avro exception and replace the string. I know this is quick 
and dirty, and I would like to change it in the 
ResolvingGrammarGenerator.mkEnumAdjust. However it is a private method, 
so either I can extend many classes or change the private method but 
then I would ruin the GenericDatumReader.

So here are my questions:
1. Should I added it as an external change and if so, is there a way to 
change the adjustments without adding a lot of duplication code.
2. We are currently working with avro 1.7.3. Do you plan to add 
something like this to the next versions ? or how can we (after writing 
the whole solution) add it ?

Thanks

Ehud


*SpecificDatumReader.java

...
*

  /** Called to read an enum value. May be overridden for alternate enum
      * representations.  By default, returns a GenericEnumSymbol. */
     protected Object readEnum(Schema expected, Decoder in) throws 
IOException {
         try{
         List<String> symList = expected.getEnumSymbols();
         String symbol = symList.get(in.readEnum());
         return createEnum(symbol,expected);
         }
         // TODO change this
         catch(AvroTypeException e){
           String tryingSymbol = e.getMessage().replace("No match for", 
"").trim();
           return createEnum(tryingSymbol, expected);
       }
     }



     @Override
     @SuppressWarnings("unchecked")
     protected Object createEnum(String symbol, Schema schema) {
         Class c = getSpecificData().getClass(schema);
         try{
             return c.getDeclaredConstructor(Schema.class, 
String.class).newInstance(schema,symbol);
         } catch (InvocationTargetException e) {
             throw new AvroTypeException(String.format("can not read 
constructor of class [%s]",c.getCanonicalName()),e);
         } catch (NoSuchMethodException e) {
             throw new AvroTypeException(String.format("can not read 
constructor of class [%s]",c.getCanonicalName()),e);
         } catch (InstantiationException e) {
             throw new AvroTypeException(String.format("can not read 
constructor of class [%s]",c.getCanonicalName()),e);
         } catch (IllegalAccessException e) {
             throw new AvroTypeException(String.format("can not read 
constructor of class [%s]",c.getCanonicalName()),e);
         }
     }


*enum.vm*
#if ($schema.getNamespace())
package $schema.getNamespace();
#end

import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;

@SuppressWarnings("all")
#if ($schema.getDoc())
/** $schema.getDoc() */
#end
#foreach ($annotation in $this.javaAnnotations($schema))
@$annotation
#end
@org.apache.avro.specific.AvroGenerated
public class ${this.mangle($schema.getName())} extends 
GenericData.EnumSymbol {

public ${this.mangle($schema.getName())}(Schema schema, String symbol) {
super(schema, symbol);
}

public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("${this.javaEscape($schema.toString())}");

#foreach ($symbol in ${schema.getEnumSymbols()})
/*Ehuds Genration*/
public static final ${this.mangle($schema.getName())} 
${this.mangle($symbol)} = new 
${this.mangle($schema.getName())}(SCHEMA$,"${this.mangle($symbol)}");

#end

public static final ${this.mangle($schema.getName())} [] values = new 
${this.mangle($schema.getName())} [] {
#foreach ($symbol in 
${schema.getEnumSymbols()})${this.mangle($symbol)}#if 
($velocityHasNext), #end#end
};


}