KafkaAvroDeserializer does not return SpecificRecord but returns GenericRecord

前端 未结 2 1953
Happy的楠姐
Happy的楠姐 2020-12-15 10:17

My KafkaProducer is able to use KafkaAvroSerializer to serialize objects to my topic. However, KafkaConsumer.poll() returns deserializ

相关标签:
2条回答
  • 2020-12-15 10:39

    Edit : reflect data support got merged (see below)

    To add to Chin Huang's answer, for minimal code and better performance, you should probably implement it this way :

    /**
     * Extends deserializer to support ReflectData.
     *
     * @param <V>
     *     value type
     */
    public abstract class SpecificKafkaAvroDeserializer<V extends SpecificRecordBase> extends AbstractKafkaAvroDeserializer implements Deserializer<V> {
      private final Schema schema;
      private Class<T> type;
      private DecoderFactory decoderFactory = DecoderFactory.get();
    
      protected SpecificKafkaAvroDeserializer(Class<T> type, Map<String, ?> props) {
        this.type = type;
        this.schema = ReflectData.get().getSchema(type);
        this.configure(this.deserializerConfig(props));
      }
    
      public void configure(Map<String, ?> configs) {
        this.configure(new KafkaAvroDeserializerConfig(configs));
      }
    
      @Override
      protected T deserialize(
              boolean includeSchemaAndVersion,
              String topic,
              Boolean isKey,
              byte[] payload,
              Schema readerSchemaIgnore) throws SerializationException {
    
        if (payload == null) {
          return null;
        }
    
        int schemaId = -1;
        try {
          ByteBuffer buffer = ByteBuffer.wrap(payload);
          if (buffer.get() != MAGIC_BYTE) {
            throw new SerializationException("Unknown magic byte!");
          }
    
          schemaId = buffer.getInt();
          Schema schema = schemaRegistry.getByID(schemaId);
    
          Schema readerSchema = ReflectData.get().getSchema(type);
    
          int start = buffer.position() + buffer.arrayOffset();
          int length = buffer.limit() - 1 - idSize;
          SpecificDatumReader<T> reader = new SpecificDatumReader(schema, readerSchema);
          BinaryDecoder decoder = decoderFactory.binaryDecoder(buffer.array(), start, length, null);
          return reader.read(null, decoder);
        } catch (IOException e) {
          throw new SerializationException("Error deserializing Avro message for id " + schemaId, e);
        } catch (RestClientException e) {
          throw new SerializationException("Error retrieving Avro schema for id " + schemaId, e);
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-15 11:02

    KafkaAvroDeserializer supports SpecificData

    It's not enabled by default. To enable it:

    properties.put(KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG, true);
    

    KafkaAvroDeserializer does not support ReflectData

    Confluent's KafkaAvroDeserializer does not know how to deserialize using Avro ReflectData. I had to extend it to support Avro ReflectData:

    /**
     * Extends deserializer to support ReflectData.
     *
     * @param <V>
     *     value type
     */
    public abstract class ReflectKafkaAvroDeserializer<V> extends KafkaAvroDeserializer {
    
      private Schema readerSchema;
      private DecoderFactory decoderFactory = DecoderFactory.get();
    
      protected ReflectKafkaAvroDeserializer(Class<V> type) {
        readerSchema = ReflectData.get().getSchema(type);
      }
    
      @Override
      protected Object deserialize(
          boolean includeSchemaAndVersion,
          String topic,
          Boolean isKey,
          byte[] payload,
          Schema readerSchemaIgnored) throws SerializationException {
    
        if (payload == null) {
          return null;
        }
    
        int schemaId = -1;
        try {
          ByteBuffer buffer = ByteBuffer.wrap(payload);
          if (buffer.get() != MAGIC_BYTE) {
            throw new SerializationException("Unknown magic byte!");
          }
    
          schemaId = buffer.getInt();
          Schema writerSchema = schemaRegistry.getByID(schemaId);
    
          int start = buffer.position() + buffer.arrayOffset();
          int length = buffer.limit() - 1 - idSize;
          DatumReader<Object> reader = new ReflectDatumReader(writerSchema, readerSchema);
          BinaryDecoder decoder = decoderFactory.binaryDecoder(buffer.array(), start, length, null);
          return reader.read(null, decoder);
        } catch (IOException e) {
          throw new SerializationException("Error deserializing Avro message for id " + schemaId, e);
        } catch (RestClientException e) {
          throw new SerializationException("Error retrieving Avro schema for id " + schemaId, e);
        }
      }
    }
    

    Define a custom deserializer class which deserializes to MyBean:

    public class MyBeanDeserializer extends ReflectKafkaAvroDeserializer<MyBean> {
      public MyBeanDeserializer() {
        super(MyBean.class);
      }
    }
    

    Configure KafkaConsumer to use the custom deserializer class:

    properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, MyBeanDeserializer.class);
    
    0 讨论(0)
提交回复
热议问题