avro无法反序列化字段中具有逻辑类型的union

6ljaweal  于 2021-06-04  发布在  Kafka
关注(0)|答案(1)|浏览(531)

avro工具版本-1.9.2
这是我在反序列化avro数据时面临的问题。看起来avro无法生成正确的pojo类,当字段与null和逻辑类型并集时。
当前行为:当avro模式的字段是null和逻辑类型的并集时。avro不添加转换类型数组,因此我们得到类强制转换异常。这就是original.avsc的问题
预期行为:avro应该能够序列化具有空值的逻辑类型。
看一下下面的original.avsc,没有 conversions 为任何字段创建的数组。结果是 ClassCastException 因为原始字段数据是基元类型,而pojo字段是基于逻辑类型的。
原始.avsc

{
    "type": "record",
    "name": "UserRecord",
    "namespace": "com.original",
    "fields": [
        {
            "name": "user",
            "type": {
                "type": "record",
                "name": "User",
                "fields": [
                    {
                        "name": "KEY_NBR",
                        "type": [
                            "null",
                            "string"
                        ],
                        "default": null
                    },
                    {
                        "name": "CRTE_TMS",
                        "type": [
                            "null",
                            {
                                "type": "long",
                                "logicalType": "timestamp-micros"
                            }
                        ],
                        "default": null
                    },
                    {
                        "name": "BIRTH_DT",
                        "type": [
                            "null",
                            {
                                "type": "int",
                                "logicalType": "date"
                            }
                        ],
                        "default": null
                    },
                    {
                        "name": "BAL_AMT",
                        "type": [
                            "null",
                            {
                                "type": "bytes",
                                "precision": 7,
                                "scale": 2,
                                "logicalType": "decimal"
                            }
                        ],
                        "default": null
                    }
                ]
            }
        },
        {
            "name": "beforeUser",
            "type": [
                "null",
                "User"
            ],
            "default": null
        }
    ]
}

基于original.avsc的pojo

package com.original;

import org.apache.avro.generic.GenericArray;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.Utf8;
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;

@org.apache.avro.specific.AvroGenerated
public class User extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
  private static final long serialVersionUID = 4336376255546547414L;
  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"User\",\"namespace\":\"com.original\",\"fields\":[{\"name\":\"KEY_NBR\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"CRTE_TMS\",\"type\":[\"null\",{\"type\":\"long\",\"logicalType\":\"timestamp-micros\"}],\"default\":null},{\"name\":\"BIRTH_DT\",\"type\":[\"null\",{\"type\":\"int\",\"logicalType\":\"date\"}],\"default\":null},{\"name\":\"BAL_AMT\",\"type\":[\"null\",{\"type\":\"bytes\",\"precision\":7,\"scale\":2,\"logicalType\":\"decimal\"}],\"default\":null}]}");
  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }

  private static SpecificData MODEL$ = new SpecificData();
static {
    MODEL$.addLogicalTypeConversion(new org.apache.avro.data.TimeConversions.DateConversion());
    MODEL$.addLogicalTypeConversion(new org.apache.avro.data.TimeConversions.TimestampMillisConversion());
  }

  private static final BinaryMessageEncoder<User> ENCODER =
      new BinaryMessageEncoder<User>(MODEL$, SCHEMA$);

  private static final BinaryMessageDecoder<User> DECODER =
      new BinaryMessageDecoder<User>(MODEL$, SCHEMA$);

  public static BinaryMessageEncoder<User> getEncoder() {
    return ENCODER;
  }

  public static BinaryMessageDecoder<User> getDecoder() {
    return DECODER;
  }

  public static BinaryMessageDecoder<User> createDecoder(SchemaStore resolver) {
    return new BinaryMessageDecoder<User>(MODEL$, SCHEMA$, resolver);
  }

  public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
    return ENCODER.encode(this);
  }

  public static User fromByteBuffer(
      java.nio.ByteBuffer b) throws java.io.IOException {
    return DECODER.decode(b);
  }

   private java.lang.CharSequence KEY_NBR;
   private java.time.Instant CRTE_TMS;
   private java.time.LocalDate BIRTH_DT;
   private java.nio.ByteBuffer BAL_AMT;

  public User() {}

  public User(java.lang.CharSequence KEY_NBR, java.time.Instant CRTE_TMS, java.time.LocalDate BIRTH_DT, java.nio.ByteBuffer BAL_AMT) {
    this.KEY_NBR = KEY_NBR;
    this.CRTE_TMS = CRTE_TMS;
    this.BIRTH_DT = BIRTH_DT;
    this.BAL_AMT = BAL_AMT;
  }

  public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
  // Used by DatumWriter.  Applications should not call.
  public java.lang.Object get(int field$) {
    switch (field$) {
    case 0: return KEY_NBR;
    case 1: return CRTE_TMS;
    case 2: return BIRTH_DT;
    case 3: return BAL_AMT;
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }

  // Used by DatumReader.  Applications should not call.
  @SuppressWarnings(value="unchecked")
  public void put(int field$, java.lang.Object value$) {
    switch (field$) {
    case 0: KEY_NBR = (java.lang.CharSequence)value$; break;
    case 1: CRTE_TMS = (java.time.Instant)value$; break;
    case 2: BIRTH_DT = (java.time.LocalDate)value$; break;
    case 3: BAL_AMT = (java.nio.ByteBuffer)value$; break;
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }

  public java.lang.CharSequence getKEYNBR() {
    return KEY_NBR;
  }

  /**
   * Sets the value of the 'KEY_NBR' field.
   * @param value the value to set.
   */
  public void setKEYNBR(java.lang.CharSequence value) {
    this.KEY_NBR = value;
  }

  public java.time.Instant getCRTETMS() {
    return CRTE_TMS;
  }

  /**
   * Sets the value of the 'CRTE_TMS' field.
   * @param value the value to set.
   */
  public void setCRTETMS(java.time.Instant value) {
    this.CRTE_TMS = value;
  }

  /**
   * Gets the value of the 'BIRTH_DT' field.
   * @return The value of the 'BIRTH_DT' field.
   */
  public java.time.LocalDate getBIRTHDT() {
    return BIRTH_DT;
  }

  public void setBIRTHDT(java.time.LocalDate value) {
    this.BIRTH_DT = value;
  }

  /**
   * Gets the value of the 'BAL_AMT' field.
   * @return The value of the 'BAL_AMT' field.
   */
  public java.nio.ByteBuffer getBALAMT() {
    return BAL_AMT;
  }

  /**
   * Sets the value of the 'BAL_AMT' field.
   * @param value the value to set.
   */
  public void setBALAMT(java.nio.ByteBuffer value) {
    this.BAL_AMT = value;
  }

  /**
   * Creates a new User RecordBuilder.
   * @return A new User RecordBuilder
   */
  public static com.original.User.Builder newBuilder() {
    return new com.original.User.Builder();
  }

  public static com.original.User.Builder newBuilder(com.original.User.Builder other) {
    if (other == null) {
      return new com.original.User.Builder();
    } else {
      return new com.original.User.Builder(other);
    }
  }

  public static com.original.User.Builder newBuilder(com.original.User other) {
    if (other == null) {
      return new com.original.User.Builder();
    } else {
      return new com.original.User.Builder(other);
    }
  }

  @org.apache.avro.specific.AvroGenerated
  public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<User>
    implements org.apache.avro.data.RecordBuilder<User> {

    private java.lang.CharSequence KEY_NBR;
    private java.time.Instant CRTE_TMS;
    private java.time.LocalDate BIRTH_DT;
    private java.nio.ByteBuffer BAL_AMT;

    private Builder() {
      super(SCHEMA$);
    }

    private Builder(com.original.User.Builder other) {
      super(other);
      if (isValidValue(fields()[0], other.KEY_NBR)) {
        this.KEY_NBR = data().deepCopy(fields()[0].schema(), other.KEY_NBR);
        fieldSetFlags()[0] = other.fieldSetFlags()[0];
      }
      if (isValidValue(fields()[1], other.CRTE_TMS)) {
        this.CRTE_TMS = data().deepCopy(fields()[1].schema(), other.CRTE_TMS);
        fieldSetFlags()[1] = other.fieldSetFlags()[1];
      }
      if (isValidValue(fields()[2], other.BIRTH_DT)) {
        this.BIRTH_DT = data().deepCopy(fields()[2].schema(), other.BIRTH_DT);
        fieldSetFlags()[2] = other.fieldSetFlags()[2];
      }
      if (isValidValue(fields()[3], other.BAL_AMT)) {
        this.BAL_AMT = data().deepCopy(fields()[3].schema(), other.BAL_AMT);
        fieldSetFlags()[3] = other.fieldSetFlags()[3];
      }
    }

    private Builder(com.original.User other) {
      super(SCHEMA$);
      if (isValidValue(fields()[0], other.KEY_NBR)) {
        this.KEY_NBR = data().deepCopy(fields()[0].schema(), other.KEY_NBR);
        fieldSetFlags()[0] = true;
      }
      if (isValidValue(fields()[1], other.CRTE_TMS)) {
        this.CRTE_TMS = data().deepCopy(fields()[1].schema(), other.CRTE_TMS);
        fieldSetFlags()[1] = true;
      }
      if (isValidValue(fields()[2], other.BIRTH_DT)) {
        this.BIRTH_DT = data().deepCopy(fields()[2].schema(), other.BIRTH_DT);
        fieldSetFlags()[2] = true;
      }
      if (isValidValue(fields()[3], other.BAL_AMT)) {
        this.BAL_AMT = data().deepCopy(fields()[3].schema(), other.BAL_AMT);
        fieldSetFlags()[3] = true;
      }
    }

    public java.lang.CharSequence getKEYNBR() {
      return KEY_NBR;
    }

    public com.original.User.Builder setKEYNBR(java.lang.CharSequence value) {
      validate(fields()[0], value);
      this.KEY_NBR = value;
      fieldSetFlags()[0] = true;
      return this;
    }

    public boolean hasKEYNBR() {
      return fieldSetFlags()[0];
    }

    public com.original.User.Builder clearKEYNBR() {
      KEY_NBR = null;
      fieldSetFlags()[0] = false;
      return this;
    }

    /**
      * Gets the value of the 'CRTE_TMS' field.
      * @return The value.
      */
    public java.time.Instant getCRTETMS() {
      return CRTE_TMS;
    }

    public com.original.User.Builder setCRTETMS(java.time.Instant value) {
      validate(fields()[1], value);
      this.CRTE_TMS = value;
      fieldSetFlags()[1] = true;
      return this;
    }

    /**
      * Checks whether the 'CRTE_TMS' field has been set.
      * @return True if the 'CRTE_TMS' field has been set, false otherwise.
      */
    public boolean hasCRTETMS() {
      return fieldSetFlags()[1];
    }

    public com.original.User.Builder clearCRTETMS() {
      CRTE_TMS = null;
      fieldSetFlags()[1] = false;
      return this;
    }

    public java.time.LocalDate getBIRTHDT() {
      return BIRTH_DT;
    }

    public com.original.User.Builder setBIRTHDT(java.time.LocalDate value) {
      validate(fields()[2], value);
      this.BIRTH_DT = value;
      fieldSetFlags()[2] = true;
      return this;

    public boolean hasBIRTHDT() {
      return fieldSetFlags()[2];
    }

    /**
      * Clears the value of the 'BIRTH_DT' field.
      * @return This builder.
      */
    public com.original.User.Builder clearBIRTHDT() {
      BIRTH_DT = null;
      fieldSetFlags()[2] = false;
      return this;
    }

    /**
      * Gets the value of the 'BAL_AMT' field.
      * @return The value.
      */
    public java.nio.ByteBuffer getBALAMT() {
      return BAL_AMT;
    }

    public com.original.User.Builder setBALAMT(java.nio.ByteBuffer value) {
      validate(fields()[3], value);
      this.BAL_AMT = value;
      fieldSetFlags()[3] = true;
      return this;
    }

    /**
      * Checks whether the 'BAL_AMT' field has been set.
      * @return True if the 'BAL_AMT' field has been set, false otherwise.
      */
    public boolean hasBALAMT() {
      return fieldSetFlags()[3];
    }

    public com.original.User.Builder clearBALAMT() {
      BAL_AMT = null;
      fieldSetFlags()[3] = false;
      return this;
    }

    @Override
    @SuppressWarnings("unchecked")
    public User build() {
      try {
        User record = new User();
        record.KEY_NBR = fieldSetFlags()[0] ? this.KEY_NBR : (java.lang.CharSequence) defaultValue(fields()[0]);
        record.CRTE_TMS = fieldSetFlags()[1] ? this.CRTE_TMS : (java.time.Instant) defaultValue(fields()[1]);
        record.BIRTH_DT = fieldSetFlags()[2] ? this.BIRTH_DT : (java.time.LocalDate) defaultValue(fields()[2]);
        record.BAL_AMT = fieldSetFlags()[3] ? this.BAL_AMT : (java.nio.ByteBuffer) defaultValue(fields()[3]);
        return record;
      } catch (org.apache.avro.AvroMissingFieldException e) {
        throw e;
      } catch (java.lang.Exception e) {
        throw new org.apache.avro.AvroRuntimeException(e);
      }
    }
  }

  @SuppressWarnings("unchecked")
  private static final org.apache.avro.io.DatumWriter<User>
    WRITER$ = (org.apache.avro.io.DatumWriter<User>)MODEL$.createDatumWriter(SCHEMA$);

  @Override public void writeExternal(java.io.ObjectOutput out)
    throws java.io.IOException {
    WRITER$.write(this, SpecificData.getEncoder(out));
  }

  @SuppressWarnings("unchecked")
  private static final org.apache.avro.io.DatumReader<User>
    READER$ = (org.apache.avro.io.DatumReader<User>)MODEL$.createDatumReader(SCHEMA$);

  @Override public void readExternal(java.io.ObjectInput in)
    throws java.io.IOException {
    READER$.read(this, SpecificData.getDecoder(in));
  }
}

然而,如果我修改原始模式并从逻辑类型字段中取出空值。avro生成适当的 conversions (选中突出显示的部分)的逻辑类型字段,我能够成功地将avro消息反序列化到pojo。
修改.avsc

{
    "type": "record",
    "name": "UserRecord",
    "namespace": "com.modified",
    "fields": [
        {
            "name": "user",
            "type": {
                "type": "record",
                "name": "User",
                "fields": [
                    {
                        "name": "KEY_NBR",
                        "type": [
                            "null",
                            "string"
                        ],
                        "default": null
                    },
                    {
                        "name": "CRTE_TMS",
                        "type":
                            {
                                "type": "long",
                                "logicalType": "timestamp-micros"
                            },
                        "default": 1
                    },
                    {
                        "name": "BIRTH_DT",
                        "type":
                            {
                                "type": "int",
                                "logicalType": "date"
                            },
                        "default": 1
                    },
                    {
                        "name": "BAL_AMT",
                        "type":
                            {
                                "type": "bytes",
                                "precision": 7,
                                "scale": 2,
                                "logicalType": "decimal"
                            }
                    }
                ]
            }
        },
        {
            "name": "beforeUser",
            "type": [
                "null",
                "User"
            ],
            "default": null
        }
    ]
}

从修改的架构生成的pojo类

package com.modified;

import org.apache.avro.generic.GenericArray;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.util.Utf8;
import org.apache.avro.message.BinaryMessageEncoder;
import org.apache.avro.message.BinaryMessageDecoder;
import org.apache.avro.message.SchemaStore;

@org.apache.avro.specific.AvroGenerated
public class User extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
  private static final long serialVersionUID = -2671150121474031299L;
  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"User\",\"namespace\":\"com.modified\",\"fields\":[{\"name\":\"KEY_NBR\",\"type\":[\"null\",\"string\"],\"default\":null},{\"name\":\"CRTE_TMS\",\"type\":{\"type\":\"long\",\"logicalType\":\"timestamp-micros\"},\"default\":1},{\"name\":\"BIRTH_DT\",\"type\":{\"type\":\"int\",\"logicalType\":\"date\"},\"default\":1},{\"name\":\"BAL_AMT\",\"type\":{\"type\":\"bytes\",\"precision\":7,\"scale\":2,\"logicalType\":\"decimal\"}}]}");
  public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }

  private static SpecificData MODEL$ = new SpecificData();
static {
    MODEL$.addLogicalTypeConversion(new org.apache.avro.data.TimeConversions.DateConversion());
    MODEL$.addLogicalTypeConversion(new org.apache.avro.data.TimeConversions.TimestampMillisConversion());
  }

  private static final BinaryMessageEncoder<User> ENCODER =
      new BinaryMessageEncoder<User>(MODEL$, SCHEMA$);

  private static final BinaryMessageDecoder<User> DECODER =
      new BinaryMessageDecoder<User>(MODEL$, SCHEMA$);

  public static BinaryMessageEncoder<User> getEncoder() {
    return ENCODER;
  }

  public static BinaryMessageDecoder<User> getDecoder() {
    return DECODER;
  }

  public static BinaryMessageDecoder<User> createDecoder(SchemaStore resolver) {
    return new BinaryMessageDecoder<User>(MODEL$, SCHEMA$, resolver);
  }

  public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException {
    return ENCODER.encode(this);
  }

  public static User fromByteBuffer(
      java.nio.ByteBuffer b) throws java.io.IOException {
    return DECODER.decode(b);
  }

   private java.lang.CharSequence KEY_NBR;
   private java.time.Instant CRTE_TMS;
   private java.time.LocalDate BIRTH_DT;
   private java.nio.ByteBuffer BAL_AMT;

  public User() {}

  public User(java.lang.CharSequence KEY_NBR, java.time.Instant CRTE_TMS, java.time.LocalDate BIRTH_DT, java.nio.ByteBuffer BAL_AMT) {
    this.KEY_NBR = KEY_NBR;
    this.CRTE_TMS = CRTE_TMS.truncatedTo(java.time.temporal.ChronoUnit.MICROS);
    this.BIRTH_DT = BIRTH_DT;
    this.BAL_AMT = BAL_AMT;
  }

  public org.apache.avro.specific.SpecificData getSpecificData() { return MODEL$; }
  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
  // Used by DatumWriter.  Applications should not call.
  public java.lang.Object get(int field$) {
    switch (field$) {
    case 0: return KEY_NBR;
    case 1: return CRTE_TMS;
    case 2: return BIRTH_DT;
    case 3: return BAL_AMT;
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// This was missing from original POJO class thus failing deserialization

  private static final org.apache.avro.Conversion<?>[] conversions =
      new org.apache.avro.Conversion<?>[] {
      null,
      new org.apache.avro.data.TimeConversions.TimestampMicrosConversion(),
      new org.apache.avro.data.TimeConversions.DateConversion(),
      null,
      null
  };
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  @Override
  public org.apache.avro.Conversion<?> getConversion(int field) {
    return conversions[field];
  }

  // Used by DatumReader.  Applications should not call.
  @SuppressWarnings(value="unchecked")
  public void put(int field$, java.lang.Object value$) {
    switch (field$) {
    case 0: KEY_NBR = (java.lang.CharSequence)value$; break;
    case 1: CRTE_TMS = (java.time.Instant)value$; break;
    case 2: BIRTH_DT = (java.time.LocalDate)value$; break;
    case 3: BAL_AMT = (java.nio.ByteBuffer)value$; break;
    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
    }
  }

  public java.lang.CharSequence getKEYNBR() {
    return KEY_NBR;
  }

  public void setKEYNBR(java.lang.CharSequence value) {
    this.KEY_NBR = value;
  }

  public java.time.Instant getCRTETMS() {
    return CRTE_TMS;
  }

  public void setCRTETMS(java.time.Instant value) {
    this.CRTE_TMS = value.truncatedTo(java.time.temporal.ChronoUnit.MICROS);
  }

  public java.time.LocalDate getBIRTHDT() {
    return BIRTH_DT;
  }

  public void setBIRTHDT(java.time.LocalDate value) {
    this.BIRTH_DT = value;
  }

  public java.nio.ByteBuffer getBALAMT() {
    return BAL_AMT;
  }

  public void setBALAMT(java.nio.ByteBuffer value) {
    this.BAL_AMT = value;
  }

  public static com.modified.User.Builder newBuilder() {
    return new com.modified.User.Builder();
  }

  public static com.modified.User.Builder newBuilder(com.modified.User.Builder other) {
    if (other == null) {
      return new com.modified.User.Builder();
    } else {
      return new com.modified.User.Builder(other);
    }
  }

  public static com.modified.User.Builder newBuilder(com.modified.User other) {
    if (other == null) {
      return new com.modified.User.Builder();
    } else {
      return new com.modified.User.Builder(other);
    }
  }

  @org.apache.avro.specific.AvroGenerated
  public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<User>
    implements org.apache.avro.data.RecordBuilder<User> {

    private java.lang.CharSequence KEY_NBR;
    private java.time.Instant CRTE_TMS;
    private java.time.LocalDate BIRTH_DT;
    private java.nio.ByteBuffer BAL_AMT;

    /**Creates a new Builder */
    private Builder() {
      super(SCHEMA$);
    }

    private Builder(com.modified.User.Builder other) {
      super(other);
      if (isValidValue(fields()[0], other.KEY_NBR)) {
        this.KEY_NBR = data().deepCopy(fields()[0].schema(), other.KEY_NBR);
        fieldSetFlags()[0] = other.fieldSetFlags()[0];
      }
      if (isValidValue(fields()[1], other.CRTE_TMS)) {
        this.CRTE_TMS = data().deepCopy(fields()[1].schema(), other.CRTE_TMS);
        fieldSetFlags()[1] = other.fieldSetFlags()[1];
      }
      if (isValidValue(fields()[2], other.BIRTH_DT)) {
        this.BIRTH_DT = data().deepCopy(fields()[2].schema(), other.BIRTH_DT);
        fieldSetFlags()[2] = other.fieldSetFlags()[2];
      }
      if (isValidValue(fields()[3], other.BAL_AMT)) {
        this.BAL_AMT = data().deepCopy(fields()[3].schema(), other.BAL_AMT);
        fieldSetFlags()[3] = other.fieldSetFlags()[3];
      }
    }

    /**
     * Creates a Builder by copying an existing User instance
     * @param other The existing instance to copy.
     */
    private Builder(com.modified.User other) {
      super(SCHEMA$);
      if (isValidValue(fields()[0], other.KEY_NBR)) {
        this.KEY_NBR = data().deepCopy(fields()[0].schema(), other.KEY_NBR);
        fieldSetFlags()[0] = true;
      }
      if (isValidValue(fields()[1], other.CRTE_TMS)) {
        this.CRTE_TMS = data().deepCopy(fields()[1].schema(), other.CRTE_TMS);
        fieldSetFlags()[1] = true;
      }
      if (isValidValue(fields()[2], other.BIRTH_DT)) {
        this.BIRTH_DT = data().deepCopy(fields()[2].schema(), other.BIRTH_DT);
        fieldSetFlags()[2] = true;
      }
      if (isValidValue(fields()[3], other.BAL_AMT)) {
        this.BAL_AMT = data().deepCopy(fields()[3].schema(), other.BAL_AMT);
        fieldSetFlags()[3] = true;
      }
    }

    /**
      * Gets the value of the 'KEY_NBR' field.
      * @return The value.
      */
    public java.lang.CharSequence getKEYNBR() {
      return KEY_NBR;
    }

    public com.modified.User.Builder setKEYNBR(java.lang.CharSequence value) {
      validate(fields()[0], value);
      this.KEY_NBR = value;
      fieldSetFlags()[0] = true;
      return this;
    }

    public boolean hasKEYNBR() {
      return fieldSetFlags()[0];
    }

    public com.modified.User.Builder clearKEYNBR() {
      KEY_NBR = null;
      fieldSetFlags()[0] = false;
      return this;
    }

    public java.time.Instant getCRTETMS() {
      return CRTE_TMS;
    }

    public com.modified.User.Builder setCRTETMS(java.time.Instant value) {
      validate(fields()[1], value);
      this.CRTE_TMS = value.truncatedTo(java.time.temporal.ChronoUnit.MICROS);
      fieldSetFlags()[1] = true;
      return this;
    }

    public boolean hasCRTETMS() {
      return fieldSetFlags()[1];
    }

    public com.modified.User.Builder clearCRTETMS() {
      fieldSetFlags()[1] = false;
      return this;
    }

    public java.time.LocalDate getBIRTHDT() {
      return BIRTH_DT;
    }

    public com.modified.User.Builder setBIRTHDT(java.time.LocalDate value) {
      validate(fields()[2], value);
      this.BIRTH_DT = value;
      fieldSetFlags()[2] = true;
      return this;
    }

    public boolean hasBIRTHDT() {
      return fieldSetFlags()[2];
    }

    public com.modified.User.Builder clearBIRTHDT() {
      fieldSetFlags()[2] = false;
      return this;
    }

    /**
      * Gets the value of the 'BAL_AMT' field.
      * @return The value.
      */
    public java.nio.ByteBuffer getBALAMT() {
      return BAL_AMT;
    }

    public com.modified.User.Builder setBALAMT(java.nio.ByteBuffer value) {
      validate(fields()[3], value);
      this.BAL_AMT = value;
      fieldSetFlags()[3] = true;
      return this;
    }

    /**
      * Checks whether the 'BAL_AMT' field has been set.
      * @return True if the 'BAL_AMT' field has been set, false otherwise.
      */
    public boolean hasBALAMT() {
      return fieldSetFlags()[3];
    }

    public com.modified.User.Builder clearBALAMT() {
      BAL_AMT = null;
      fieldSetFlags()[3] = false;
      return this;
    }

    @Override
    @SuppressWarnings("unchecked")
    public User build() {
      try {
        User record = new User();
        record.KEY_NBR = fieldSetFlags()[0] ? this.KEY_NBR : (java.lang.CharSequence) defaultValue(fields()[0]);
        record.CRTE_TMS = fieldSetFlags()[1] ? this.CRTE_TMS : (java.time.Instant) defaultValue(fields()[1]);
        record.BIRTH_DT = fieldSetFlags()[2] ? this.BIRTH_DT : (java.time.LocalDate) defaultValue(fields()[2]);
        record.BAL_AMT = fieldSetFlags()[3] ? this.BAL_AMT : (java.nio.ByteBuffer) defaultValue(fields()[3]);
        return record;
      } catch (org.apache.avro.AvroMissingFieldException e) {
        throw e;
      } catch (java.lang.Exception e) {
        throw new org.apache.avro.AvroRuntimeException(e);
      }
    }
  }

  @SuppressWarnings("unchecked")
  private static final org.apache.avro.io.DatumWriter<User>
    WRITER$ = (org.apache.avro.io.DatumWriter<User>)MODEL$.createDatumWriter(SCHEMA$);

  @Override public void writeExternal(java.io.ObjectOutput out)
    throws java.io.IOException {
    WRITER$.write(this, SpecificData.getEncoder(out));
  }

  @SuppressWarnings("unchecked")
  private static final org.apache.avro.io.DatumReader<User>
    READER$ = (org.apache.avro.io.DatumReader<User>)MODEL$.createDatumReader(SCHEMA$);

  @Override public void readExternal(java.io.ObjectInput in)
    throws java.io.IOException {
    READER$.read(this, SpecificData.getDecoder(in));
  }
}

我不明白为什么avro要这么做,而且我不喜欢用黑客攻击原始模式来让事情正常进行。有人能帮我弄清楚世界是如何处理这些问题的吗?
注意:这个问题和我原来问的这个问题有关。

s4n0splo

s4n0splo1#

和我在avro版本1.10.1中得到的行为一样。根据我的经验,avro在反序列化类型union为null的字段和逻辑类型之一(timestamp,decimal)时失败
例子:
{“name”:“costamount”,“type”:[“null”,{“type”:“bytes”,“logicaltype”:“decimal”,“precision”:19,“scale”:2}],“default”:null},

相关问题