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
- Track end-of-input in
ApacheAvroParserImpl instead of delegating to
BinaryDecoder.isEnd() when a direct decoder is in use; or
- ignore
AVRO_BUFFERING for the Apache decoder (always buffer) and document that; or
- reject the combination explicitly at parser construction, so failure is a clear
configuration error rather than an UnsupportedOperationException mid-parse.
Found while reviewing #796.
Problem
When
AvroParser.Feature.AVRO_BUFFERINGis disabled and the Apache decoder is used(
ApacheAvroFactory), parsing from anInputStreamfails immediately withUnsupportedOperationException: the very firstnextToken()call throws, so nocontent can be read at all.
Root cause: with buffering disabled,
ApacheAvroParserImplconstructs the decoder withDecoderFactory.directBinaryDecoder(), butRootReader.nextToken()callsApacheAvroParserImpl.checkInputEnd(), which delegates toBinaryDecoder.isEnd()--and Apache's
DirectBinaryDecoder.isEnd()is an unconditionalthrow new UnsupportedOperationException().Reproduction
Scope
Only the combination of all three matters:
ApacheAvroFactory), ANDAVRO_BUFFERINGdisabled, ANDInputStream(notbyte[]) inputbyte[]input is unaffected because that constructor always usesDECODER_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
AvroFactorybut never read by_createParser), so reachingthis requires constructing
ApacheAvroFactorydirectly -- which is probably why ithas gone unnoticed.
Affects
Present since 2.16.0 (
323373de, where direct-decoder support was added), and stillpresent on
2.18,2.xand3.x. No existing test parses with this combination:MapperConfigTestonly asserts the feature flag's state, never exercises decoding.Possible fixes
ApacheAvroParserImplinstead of delegating toBinaryDecoder.isEnd()when a direct decoder is in use; orAVRO_BUFFERINGfor the Apache decoder (always buffer) and document that; orconfiguration error rather than an
UnsupportedOperationExceptionmid-parse.Found while reviewing #796.