title: Differentiating an AVRO union type
body: <p>I'm consuming Avro serialized messages from Kafka using the "automatic" deserializer like:</p>
  
  <pre><code>props.put(
      ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
      "io.confluent.kafka.serializers.KafkaAvroDeserializer"
  );
  props.put("schema.registry.url", "https://example.com");
  </code></pre>
  
  <p>This works brilliantly, and is right out of the docs at <a href="https://docs.confluent.io/current/schema-registry/serializer-formatter.html#serializer" rel="nofollow noreferrer">https://docs.confluent.io/current/schema-registry/serializer-formatter.html#serializer</a>.</p>
  
  <p>The problem I'm facing is that I actually just want to forward these messages, but to do the routing I need some metadata from inside. Some technical constraints mean that I can't feasibly compile-in generated class files to use the <code>KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG =&gt; true</code>, so I am using a regular decoder without being tied into Kafka, specifically just reading the bytes as a <code>Array[Byte]</code> and passing them to a manually constructed deserializer:</p>
  
  <pre><code>var maxSchemasToCache = 1000;
  var schemaRegistryURL = "https://example.com/"
  var specificDeserializerProps = Map(
    "schema.registry.url" 
        -&gt; schemaRegistryURL,
    KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG 
        -&gt; "false"
  );
  var client = new CachedSchemaRegistryClient(
                       schemaRegistryURL, 
                       maxSchemasToCache
                   );
  var deserializer = new KafkaAvroDeserializer(
                           client,
                           specificDeserializerProps.asJava
                     );
  </code></pre>
  
  <p>The messages are a "container" type, with the really interesting part one of about ~25 types in a <code>union { A, B, C } msg</code> record field:</p>
  
  <pre><code>record Event {
      timestamp_ms created_at;
      union {
          Online,
          Offline,
          Available,
          Unavailable,
          ...
          ...Failed,
          ...Updated
      } msg;
  }
  </code></pre>
  
  <p>So I'm successfully reading a <code>Array[Byte]</code> into <code>record</code> and feeding it into the deserializer like this:</p>
  
  <pre><code>var genericRecord = deserializer.deserialize(topic, consumerRecord.value())
                         .asInstanceOf[GenericRecord];
  var schema = genericRecord.getSchema();
  var msgSchema = schema.getField("msg").schema();
  </code></pre>
  
  <p>The problem however is that I can find no to discern, discriminate or "resolve" the "type" of the <code>msg</code> field through the union:</p>
  
  <pre><code>System.out.printf(
      "msg.schema = %s msg.schema.getType = %s\n", 
      msgSchema.getFullName(),  
      msgSchema.getType().name());
  =&gt; msg.schema = union msg.schema.getType = union
  </code></pre>
  
  <p>How to discriminate types in this scenario? The confluent registry knows, these things have names, they have "types", even if I'm treating them as <code>GenericRecords</code>, </p>
  
  <p>My goal here is to know that <code>record.msg</code> is of "type" <code>Online | Offline | Available</code> rather than just knowing it's a <code>union</code>.</p>