天天看点

Avro根据avsc文件生成java类背景步骤结语

背景

Avro可以提供跨语言的数据交互,下面记录如何通过Avro生成java类

步骤

1、定义avsc文件,里面包含类的一些信息,比如包名、类名、属性列表等,示例如下

{
    "namespace": "szc.zone", 
    "type": "record",
    "name": "Person", 
    "fields": [ 
        {
            "name": "name",
            "type": "string"
        },
        {
            "name": "age",
            "type": "int"
        },
        {
            "name": "gender",
            "type": "string"
        },
        {
            "name": "hometown",
            "type": "string"
        }
    ]
}
           

其中namespace字段是为包名,name字段是为类名,fields字段是为类包含的属性,里面有属性名和属性类型

2、利用avro-tools工具,生成类文件

先下载avro-tools的jar文件,以版本1.7.7为例,下载地址为http://archive.apache.org/dist/avro/avro-1.7.7/java/,直接下载jar包即可,如下图所示

Avro根据avsc文件生成java类背景步骤结语

然后运行命令

java -jar avro-tools-1.7.7.jar compile schema .\input\StringPair.avsc .
           

其中avro-tools-1.7.7.jar就是下载的jar包,.\input\StringPair.avsc是输入的avsc路径,最后的.是输出目录,也就是当前目录。运行之后的结果如下图所示

Avro根据avsc文件生成java类背景步骤结语

在当前目录下,可以看到包目录szc

Avro根据avsc文件生成java类背景步骤结语

3、使用

最后把这个包目录整个拷到工程目录里的合适位置,就能使用了

Avro根据avsc文件生成java类背景步骤结语
Avro根据avsc文件生成java类背景步骤结语

最后,附上生成的Person类的源代码

/**
 * Autogenerated by Avro
 * 
 * DO NOT EDIT DIRECTLY
 */
package szc.zone;  
@SuppressWarnings("all")
@org.apache.avro.specific.AvroGenerated
public class Person extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"Person\",\"namespace\":\"szc.zone\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"age\",\"type\":\"int\"},{\"name\":\"gender\",\"type\":\"string\"},{\"name\":\"hometown\",\"type\":\"string\"}]}");
  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
  @Deprecated public CharSequence name;
  @Deprecated public int age;
  @Deprecated public CharSequence gender;
  @Deprecated public CharSequence hometown;

  /**
   * Default constructor.  Note that this does not initialize fields
   * to their default values from the schema.  If that is desired then
   * one should use <code>newBuilder()</code>. 
   */
  public Person() {}

  /**
   * All-args constructor.
   */
  public Person(CharSequence name, Integer age, CharSequence gender, CharSequence hometown) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.hometown = hometown;
  }

  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
  // Used by DatumWriter.  Applications should not call. 
  public Object get(int field$) {
    switch (field$) {
    case 0: return name;
    case 1: return age;
    case 2: return gender;
    case 3: return hometown;
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }
  // Used by DatumReader.  Applications should not call. 
  @SuppressWarnings(value="unchecked")
  public void put(int field$, Object value$) {
    switch (field$) {
    case 0: name = (CharSequence)value$; break;
    case 1: age = (Integer)value$; break;
    case 2: gender = (CharSequence)value$; break;
    case 3: hometown = (CharSequence)value$; break;
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }

  /**
   * Gets the value of the 'name' field.
   */
  public CharSequence getName() {
    return name;
  }

  /**
   * Sets the value of the 'name' field.
   * @param value the value to set.
   */
  public void setName(CharSequence value) {
    this.name = value;
  }

  /**
   * Gets the value of the 'age' field.
   */
  public Integer getAge() {
    return age;
  }

  /**
   * Sets the value of the 'age' field.
   * @param value the value to set.
   */
  public void setAge(Integer value) {
    this.age = value;
  }

  /**
   * Gets the value of the 'gender' field.
   */
  public CharSequence getGender() {
    return gender;
  }

  /**
   * Sets the value of the 'gender' field.
   * @param value the value to set.
   */
  public void setGender(CharSequence value) {
    this.gender = value;
  }

  /**
   * Gets the value of the 'hometown' field.
   */
  public CharSequence getHometown() {
    return hometown;
  }

  /**
   * Sets the value of the 'hometown' field.
   * @param value the value to set.
   */
  public void setHometown(CharSequence value) {
    this.hometown = value;
  }

  /** Creates a new Person RecordBuilder */
  public static Builder newBuilder() {
    return new Builder();
  }
  
  /** Creates a new Person RecordBuilder by copying an existing Builder */
  public static Builder newBuilder(Builder other) {
    return new Builder(other);
  }
  
  /** Creates a new Person RecordBuilder by copying an existing Person instance */
  public static Builder newBuilder(Person other) {
    return new Builder(other);
  }
  
  /**
   * RecordBuilder for Person instances.
   */
  public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<Person>
    implements org.apache.avro.data.RecordBuilder<Person> {

    private CharSequence name;
    private int age;
    private CharSequence gender;
    private CharSequence hometown;

    /** Creates a new Builder */
    private Builder() {
      super(Person.SCHEMA$);
    }
    
    /** Creates a Builder by copying an existing Builder */
    private Builder(Builder other) {
      super(other);
      if (isValidValue(fields()[0], other.name)) {
        this.name = data().deepCopy(fields()[0].schema(), other.name);
        fieldSetFlags()[0] = true;
      }
      if (isValidValue(fields()[1], other.age)) {
        this.age = data().deepCopy(fields()[1].schema(), other.age);
        fieldSetFlags()[1] = true;
      }
      if (isValidValue(fields()[2], other.gender)) {
        this.gender = data().deepCopy(fields()[2].schema(), other.gender);
        fieldSetFlags()[2] = true;
      }
      if (isValidValue(fields()[3], other.hometown)) {
        this.hometown = data().deepCopy(fields()[3].schema(), other.hometown);
        fieldSetFlags()[3] = true;
      }
    }
    
    /** Creates a Builder by copying an existing Person instance */
    private Builder(Person other) {
            super(Person.SCHEMA$);
      if (isValidValue(fields()[0], other.name)) {
        this.name = data().deepCopy(fields()[0].schema(), other.name);
        fieldSetFlags()[0] = true;
      }
      if (isValidValue(fields()[1], other.age)) {
        this.age = data().deepCopy(fields()[1].schema(), other.age);
        fieldSetFlags()[1] = true;
      }
      if (isValidValue(fields()[2], other.gender)) {
        this.gender = data().deepCopy(fields()[2].schema(), other.gender);
        fieldSetFlags()[2] = true;
      }
      if (isValidValue(fields()[3], other.hometown)) {
        this.hometown = data().deepCopy(fields()[3].schema(), other.hometown);
        fieldSetFlags()[3] = true;
      }
    }

    /** Gets the value of the 'name' field */
    public CharSequence getName() {
      return name;
    }
    
    /** Sets the value of the 'name' field */
    public Builder setName(CharSequence value) {
      validate(fields()[0], value);
      this.name = value;
      fieldSetFlags()[0] = true;
      return this; 
    }
    
    /** Checks whether the 'name' field has been set */
    public boolean hasName() {
      return fieldSetFlags()[0];
    }
    
    /** Clears the value of the 'name' field */
    public Builder clearName() {
      name = null;
      fieldSetFlags()[0] = false;
      return this;
    }

    /** Gets the value of the 'age' field */
    public Integer getAge() {
      return age;
    }
    
    /** Sets the value of the 'age' field */
    public Builder setAge(int value) {
      validate(fields()[1], value);
      this.age = value;
      fieldSetFlags()[1] = true;
      return this; 
    }
    
    /** Checks whether the 'age' field has been set */
    public boolean hasAge() {
      return fieldSetFlags()[1];
    }
    
    /** Clears the value of the 'age' field */
    public Builder clearAge() {
      fieldSetFlags()[1] = false;
      return this;
    }

    /** Gets the value of the 'gender' field */
    public CharSequence getGender() {
      return gender;
    }
    
    /** Sets the value of the 'gender' field */
    public Builder setGender(CharSequence value) {
      validate(fields()[2], value);
      this.gender = value;
      fieldSetFlags()[2] = true;
      return this; 
    }
    
    /** Checks whether the 'gender' field has been set */
    public boolean hasGender() {
      return fieldSetFlags()[2];
    }
    
    /** Clears the value of the 'gender' field */
    public Builder clearGender() {
      gender = null;
      fieldSetFlags()[2] = false;
      return this;
    }

    /** Gets the value of the 'hometown' field */
    public CharSequence getHometown() {
      return hometown;
    }
    
    /** Sets the value of the 'hometown' field */
    public Builder setHometown(CharSequence value) {
      validate(fields()[3], value);
      this.hometown = value;
      fieldSetFlags()[3] = true;
      return this; 
    }
    
    /** Checks whether the 'hometown' field has been set */
    public boolean hasHometown() {
      return fieldSetFlags()[3];
    }
    
    /** Clears the value of the 'hometown' field */
    public Builder clearHometown() {
      hometown = null;
      fieldSetFlags()[3] = false;
      return this;
    }

    @Override
    public Person build() {
      try {
        Person record = new Person();
        record.name = fieldSetFlags()[0] ? this.name : (CharSequence) defaultValue(fields()[0]);
        record.age = fieldSetFlags()[1] ? this.age : (Integer) defaultValue(fields()[1]);
        record.gender = fieldSetFlags()[2] ? this.gender : (CharSequence) defaultValue(fields()[2]);
        record.hometown = fieldSetFlags()[3] ? this.hometown : (CharSequence) defaultValue(fields()[3]);
        return record;
      } catch (Exception e) {
        throw new org.apache.avro.AvroRuntimeException(e);
      }
    }
  }
}
           

结语

 其实Avro的类生成不是必须的,它只需要我们提供avsc文件作为数据的格式,然后利用DatumWriter+Encoder进行数据输出、DatumReader+Decoder进行数据输入即可。不过,在数据IO的时候,如果要同时对多个字段处理,把字段封装成java类可能有利于进一步操作;但如果只需要处理一两个字段,比如统计计数等,就不用封装了。

继续阅读