package com.fasterxml.jackson.dataformat.avro.apacheimpl;

import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;

import org.apache.avro.io.BinaryDecoder;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.dataformat.avro.deser.AvroParserImpl;
import com.fasterxml.jackson.dataformat.avro.deser.AvroReadContext;

Implementation class that exposes additional internal API to be used as callbacks by AvroReadContext implementations.
/** * Implementation class that exposes additional internal API * to be used as callbacks by {@link AvroReadContext} implementations. */
public class ApacheAvroParserImpl extends AvroParserImpl { /* /********************************************************** /* Input source config /********************************************************** */ protected InputStream _inputStream;
Current buffer from which data is read; generally data is read into buffer from input source, but in some cases pre-loaded buffer is handed to the parser.
/** * Current buffer from which data is read; generally data is read into * buffer from input source, but in some cases pre-loaded buffer * is handed to the parser. */
protected byte[] _inputBuffer;
Flag that indicates whether the input buffer is recycable (and needs to be returned to recycler once we are done) or not.

If it is not, it also means that parser can NOT modify underlying buffer.

/** * Flag that indicates whether the input buffer is recycable (and * needs to be returned to recycler once we are done) or not. *<p> * If it is not, it also means that parser can NOT modify underlying * buffer. */
protected boolean _bufferRecyclable; /* /********************************************************** /* Helper objects /********************************************************** */
Actual decoder in use, possible same as _rootDecoder, but not necessarily, in case of different reader/writer schema in use.
/** * Actual decoder in use, possible same as <code>_rootDecoder</code>, but * not necessarily, in case of different reader/writer schema in use. */
protected BinaryDecoder _decoder;
We need to keep track of text values.
/** * We need to keep track of text values. */
protected String _textValue; /* /********************************************************** /* Life-cycle /********************************************************** */ public ApacheAvroParserImpl(IOContext ctxt, int parserFeatures, int avroFeatures, ObjectCodec codec, InputStream in) { super(ctxt, parserFeatures, avroFeatures, codec); _inputStream = in; _inputBuffer = ctxt.allocReadIOBuffer(); _inputPtr = 0; _inputEnd = 0; _bufferRecyclable = true; _decoder = ApacheCodecRecycler.decoder(in, Feature.AVRO_BUFFERING.enabledIn(avroFeatures)); } public ApacheAvroParserImpl(IOContext ctxt, int parserFeatures, int avroFeatures, ObjectCodec codec, byte[] data, int offset, int len) { super(ctxt, parserFeatures, avroFeatures, codec); _inputStream = null; _decoder = ApacheCodecRecycler.decoder(data, offset, len); } @Override protected void _releaseBuffers() throws IOException { super._releaseBuffers(); if (_bufferRecyclable) { byte[] buf = _inputBuffer; if (buf != null) { _inputBuffer = null; _ioContext.releaseReadIOBuffer(buf); } } BinaryDecoder d = _decoder; if (d != null) { _decoder = null; ApacheCodecRecycler.release(d); } } /* /********************************************************** /* Abstract method impls, i/o access /********************************************************** */ @Override public Object getInputSource() { return _inputStream; } @Override protected void _closeInput() throws IOException { if (_inputStream != null) { _inputStream.close(); } } /* /********************************************************** /* Abstract method impls, text /********************************************************** */ // For now we do not store char[] representation... @Override public boolean hasTextCharacters() { return false; } @Override public String nextTextValue() throws IOException { return (nextToken() == JsonToken.VALUE_STRING) ? _textValue : null; } @Override public String getText() throws IOException { if (_currToken == JsonToken.VALUE_STRING) { return _textValue; } if (_currToken == JsonToken.FIELD_NAME) { return _avroContext.getCurrentName(); } if (_currToken != null) { if (_currToken.isScalarValue()) { return _textValue; } return _currToken.asString(); } return null; } @Override // since 2.8 public int getText(Writer writer) throws IOException { JsonToken t = _currToken; if (t == JsonToken.VALUE_STRING) { writer.write(_textValue); return _textValue.length(); } if (t == JsonToken.FIELD_NAME) { String n = _parsingContext.getCurrentName(); writer.write(n); return n.length(); } if (t != null) { if (t.isNumeric()) { return _textBuffer.contentsToWriter(writer); } char[] ch = t.asCharArray(); writer.write(ch); return ch.length; } return 0; } /* /********************************************************** /* Methods for AvroReadContext implementations: general state /********************************************************** */ @Override public boolean checkInputEnd() throws IOException { return _decoder.isEnd(); } /* /********************************************************** /* Methods for AvroReadContext implementations: decoding /********************************************************** */ @Override public JsonToken decodeBoolean() throws IOException { return _decoder.readBoolean() ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE; } @Override public void skipBoolean() throws IOException { _decoder.skipFixed(1); } @Override public int decodeInt() throws IOException { return _decoder.readInt(); } @Override public JsonToken decodeIntToken() throws IOException { _numberInt = _decoder.readInt(); _numTypesValid = NR_INT; return JsonToken.VALUE_NUMBER_INT; } @Override public void skipInt() throws IOException { // ints use variable-length zigzagging; alas, no native skipping _decoder.readInt(); } @Override public long decodeLong() throws IOException { return _decoder.readLong(); } @Override public JsonToken decodeLongToken() throws IOException { _numberLong = _decoder.readLong(); _numTypesValid = NR_LONG; return JsonToken.VALUE_NUMBER_INT; } @Override public void skipLong() throws IOException { // ints use variable-length zigzagging; alas, no native skipping _decoder.readLong(); } @Override public JsonToken decodeFloat() throws IOException { _numberFloat = _decoder.readFloat(); _numTypesValid = NR_FLOAT; return JsonToken.VALUE_NUMBER_FLOAT; } @Override public void skipFloat() throws IOException { // floats have fixed length of 4 bytes _decoder.skipFixed(4); } @Override public JsonToken decodeDouble() throws IOException { _numberDouble = _decoder.readDouble(); _numTypesValid = NR_DOUBLE; return JsonToken.VALUE_NUMBER_FLOAT; } @Override public void skipDouble() throws IOException { // doubles have fixed length of 8 bytes _decoder.skipFixed(8); } @Override public void decodeString() throws IOException { _textValue = _decoder.readString(); } @Override public JsonToken decodeStringToken() throws IOException { decodeString(); return JsonToken.VALUE_STRING; } @Override public void skipString() throws IOException { _decoder.skipString(); } @Override public JsonToken decodeBytes() throws IOException { int len = _decoder.readInt(); if (len <= 0) { _binaryValue = NO_BYTES; } else { byte[] b = new byte[len]; // this is simple raw read, safe to use: _decoder.readFixed(b, 0, len); // plus let's retain reference to this buffer, for reuse // (is safe due to way Avro impl handles them) _binaryValue = b; } return JsonToken.VALUE_EMBEDDED_OBJECT; } @Override public void skipBytes() throws IOException { _decoder.skipBytes(); } @Override public JsonToken decodeFixed(int size) throws IOException { byte[] data = new byte[size]; _decoder.readFixed(data); _binaryValue = data; return JsonToken.VALUE_EMBEDDED_OBJECT; } @Override public void skipFixed(int size) throws IOException { _decoder.skipFixed(size); } // // // Array decoding @Override public long decodeArrayStart() throws IOException { return _decoder.readArrayStart(); } @Override public long decodeArrayNext() throws IOException { return _decoder.arrayNext(); } @Override public long skipArray() throws IOException { return _decoder.skipArray(); } // // // Map decoding @Override public String decodeMapKey() throws IOException { return _decoder.readString(); } @Override public long decodeMapStart() throws IOException { return _decoder.readMapStart(); } @Override public long decodeMapNext() throws IOException { return _decoder.mapNext(); } @Override public long skipMap() throws IOException { return _decoder.skipMap(); } // // // Misc other decoding @Override public int decodeIndex() throws IOException { return (_branchIndex = _decoder.readIndex()); } @Override public int decodeEnum() throws IOException { return (_enumIndex = _decoder.readEnum()); } /* /********************************************************** /* Methods for AvroReadContext impls, other /********************************************************** */ @Override protected JsonToken setString(String str) { _textValue = str; return JsonToken.VALUE_STRING; } }