Skip to content

Apache decoder fails with UnsupportedOperationException when AvroParser.Feature.AVRO_BUFFERING disabled #797

Description

@cowtowncoder

Problem

When AvroParser.Feature.AVRO_BUFFERING is disabled and the Apache decoder is used
(ApacheAvroFactory), parsing from an InputStream fails immediately with
UnsupportedOperationException: the very first nextToken() call throws, so no
content can be read at all.

Root cause: with buffering disabled, ApacheAvroParserImpl constructs the decoder with
DecoderFactory.directBinaryDecoder(), but RootReader.nextToken() calls
ApacheAvroParserImpl.checkInputEnd(), which delegates to BinaryDecoder.isEnd() --
and Apache's DirectBinaryDecoder.isEnd() is an unconditional
throw new UnsupportedOperationException().

java.lang.UnsupportedOperationException
	at org.apache.avro.io.DirectBinaryDecoder.isEnd(DirectBinaryDecoder.java:194)
	at com.fasterxml.jackson.dataformat.avro.apacheimpl.ApacheAvroParserImpl.checkInputEnd(ApacheAvroParserImpl.java:231)
	at com.fasterxml.jackson.dataformat.avro.deser.RootReader.nextToken(RootReader.java:28)
	at com.fasterxml.jackson.dataformat.avro.deser.AvroParserImpl.nextToken(AvroParserImpl.java:97)

Reproduction

AvroMapper vanilla = new AvroMapper();
AvroSchema schema = vanilla.schemaFrom(
    "{'type':'record','name':'Tiny','fields':[{'name':'x','type':'int'}]}".replace('\'', '"'));
byte[] doc = vanilla.writer(schema).writeValueAsBytes(Collections.singletonMap("x", 42));

AvroFactory f = new ApacheAvroFactory();
f.disable(AvroParser.Feature.AVRO_BUFFERING);
AvroMapper mapper = AvroMapper.builder(f).build();

// works: byte[] input
mapper.readerFor(Map.class).with(schema).readValue(doc);                          // -> {x=42}

// fails: InputStream input
mapper.readerFor(Map.class).with(schema)
    .readValue(new ByteArrayInputStream(doc));                                    // -> UnsupportedOperationException

Scope

Only the combination of all three matters:

  • Apache decoder (ApacheAvroFactory), AND
  • AVRO_BUFFERING disabled, AND
  • InputStream (not byte[]) input

byte[] input is unaffected because that constructor always uses
DECODER_FACTORY.binaryDecoder(buffer, ...) and ignores the feature entirely.
The non-Apache (native JacksonAvroParserImpl) decoder is unaffected.

Note that AvroFactoryBuilder.builderWithApacheDecoder() is currently a no-op
(the flag is copied to AvroFactory but never read by _createParser), so reaching
this requires constructing ApacheAvroFactory directly -- which is probably why it
has gone unnoticed.

Affects

Present since 2.16.0 (323373de, where direct-decoder support was added), and still
present on 2.18, 2.x and 3.x. No existing test parses with this combination:
MapperConfigTest only asserts the feature flag's state, never exercises decoding.

Possible fixes

  1. Track end-of-input in ApacheAvroParserImpl instead of delegating to
    BinaryDecoder.isEnd() when a direct decoder is in use; or
  2. ignore AVRO_BUFFERING for the Apache decoder (always buffer) and document that; or
  3. reject the combination explicitly at parser construction, so failure is a clear
    configuration error rather than an UnsupportedOperationException mid-parse.

Found while reviewing #796.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions