Class AvroCodec

java.lang.Object
org.acemq.amqp.codec.avro.AvroCodec
All Implemented Interfaces:
Codec

public final class AvroCodec extends Object implements Codec
Reads and writes Avro.

There is no asAvro() and there cannot be one. Avro's bytes describe nothing about themselves: a reader must already hold the schema the writer used, or the message is unreadable. A method taking no arguments would have nothing to build a codec out of, so this is reached through publisher.as(AvroCodec.of(schema)) instead. That asymmetry with JSON is not an oversight in the API; it is the difference between the formats, made visible.

Two ways to say where the schema comes from, and the choice matters more than it looks.

of(Schema) and of(Class) fix one schema for the codec's whole life. Small, fast, and nothing extra to run — and the writer's schema is whatever the reader happens to have compiled in. The moment a producer adds a field, every consumer still holding the old schema reads the new bytes wrongly, and Avro will not always notice. Sound only where producer and consumer are released together.

registered(SchemaRegistry) writes the schema's identifier into the front of every message, so a reader can look up exactly what the writer used and let Avro resolve it against its own. This is what makes a field addition safe, and it is the mode to use unless there is a reason not to. The framing is one zero byte, then four bytes of identifier, big-endian, then the Avro body — the layout Confluent's clients use, so messages written here can be read by them and the other way round.

The two framings are told apart by the content type, not by the bytes. A fixed-schema codec handed avro/binary decodes the body as it stands; handed application/vnd.acemq.avro it refuses, because reading the other framing would shift every field and report nonsense as success. Only a message that arrived saying nothing useful falls back to guessing from the first byte, and that guess is a last resort rather than a rule: an Avro body begins with a zero byte whenever its first field encodes to zero — an empty string, a 0, a false, the first branch of a union — so the byte alone cannot tell a framed message from an ordinary one.

  • Field Details

    • FIXED_CONTENT_TYPE

      public static final String FIXED_CONTENT_TYPE
      Content type for a codec whose schema is fixed at construction.
      See Also:
    • REGISTERED_CONTENT_TYPE

      public static final String REGISTERED_CONTENT_TYPE
      Content type for a codec that writes a schema identifier into each message.
      See Also:
  • Method Details

    • of

      public static AvroCodec of(org.apache.avro.Schema schema)
      Parameters:
      schema - the one schema this codec reads and writes; payloads are GenericRecord
      Returns:
      a codec fixed to that schema
    • of

      public static AvroCodec of(Class<? extends org.apache.avro.specific.SpecificRecord> type)
      Parameters:
      type - a class generated by the Avro compiler, which carries its own schema
      Returns:
      a codec fixed to that class's schema
    • registered

      public static AvroCodec registered(SchemaRegistry registry)
      Parameters:
      registry - where schema identifiers are resolved
      Returns:
      a codec that writes an identifier into every message, so that a reader can resolve the writer's schema against its own
    • registered

      public static AvroCodec registered(SchemaRegistry registry, org.apache.avro.Schema readerSchema)
      As registered(SchemaRegistry), but reading every message against a schema of your own rather than the writer's.

      This is what schema evolution actually needs. With a writer's schema alone, a consumer receives whatever the producer sent — a field it has never heard of arrives, and a field it expects is simply absent if the producer has not started sending it yet. Given both, Avro resolves them: a field the reader does not know is skipped, and one the writer omitted is filled in from the reader's default. The consumer then sees the shape it was written against, whichever version produced the message.

      The alternative is a generated SpecificRecord, whose class carries the reader schema. This exists for the generic path, where there is no class to read it from.

      Parameters:
      registry - where schema identifiers are resolved
      readerSchema - the schema this consumer was written against
      Returns:
      a codec that resolves every message onto readerSchema
    • contentType

      public String contentType()
      Specified by:
      contentType in interface Codec
      Returns:
      the content type this codec produces, for example application/json
    • encode

      public byte[] encode(Object payload)
      Specified by:
      encode in interface Codec
      Parameters:
      payload - object to encode; never null
      Returns:
      encoded bytes
    • decode

      public <T> T decode(byte[] body, Class<T> target)
      Specified by:
      decode in interface Codec
      Type Parameters:
      T - target type
      Parameters:
      body - encoded bytes
      target - type to produce
      Returns:
      the decoded payload
    • decode

      public <T> T decode(byte[] body, Class<T> target, @Nullable String contentType)
      Description copied from interface: Codec
      Decodes a received message, told what the sender said it was.

      The engine calls this one, because a codec that dispatches between several formats cannot choose without knowing the content type. A codec that handles a single format has no use for it and need not override this.

      Specified by:
      decode in interface Codec
      Type Parameters:
      T - target type
      Parameters:
      body - encoded bytes
      target - type to produce
      contentType - content type the message arrived with, or null when the sender did not set one
      Returns:
      the decoded payload
    • canDecode

      public boolean canDecode(@Nullable String contentType)
      Specified by:
      canDecode in interface Codec
      Parameters:
      contentType - content type of a received message, or null when the sender did not set one
      Returns:
      whether this codec can decode it
    • definitionOf

      public static SchemaDefinition definitionOf(org.apache.avro.Schema schema)
      Parameters:
      schema - an Avro schema
      Returns:
      the same schema as a registry sees it, so it can be registered before anything is published
    • toString

      public String toString()
      Overrides:
      toString in class Object