blob: 38934f07d6ae0038a585f96b57c8bb9b17ad0000 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.internal.binary;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInput;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.binary.BinaryCollectionFactory;
import org.apache.ignite.binary.BinaryInvalidTypeException;
import org.apache.ignite.binary.BinaryMapFactory;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjectException;
import org.apache.ignite.binary.BinaryRawReader;
import org.apache.ignite.binary.BinaryReader;
import org.apache.ignite.internal.binary.streams.BinaryInputStream;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BINARY_ENUM;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BINARY_OBJ;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BOOLEAN;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BOOLEAN_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BYTE;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.BYTE_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.CHAR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.CHAR_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.CLASS;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.COL;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DATE;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DATE_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DECIMAL;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DECIMAL_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DFLT_HDR_LEN;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DOUBLE;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.DOUBLE_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.ENUM;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.ENUM_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.FLOAT;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.FLOAT_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.HANDLE;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.INT;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.INT_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.LONG;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.LONG_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.MAP;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.NULL;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.OBJ;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.OBJ_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.OPTM_MARSH;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.PROXY;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.SHORT;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.SHORT_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.STRING;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.STRING_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.TIME;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.TIMESTAMP;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.TIMESTAMP_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.TIME_ARR;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.UNREGISTERED_TYPE_ID;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.UUID;
import static org.apache.ignite.internal.binary.GridBinaryMarshaller.UUID_ARR;
/**
* Binary reader implementation.
*/
@SuppressWarnings("unchecked")
public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, BinaryReaderHandlesHolder, ObjectInput {
/** Binary context. */
private final BinaryContext ctx;
/** Input stream. */
private final BinaryInputStream in;
/** Class loaded. */
private final ClassLoader ldr;
/** Reader context which is constantly passed between objects. */
private BinaryReaderHandles hnds;
/** */
private final int start;
/** Start of actual data. Positioned right after the header. */
private final int dataStart;
/** Type ID. */
private final int typeId;
/** Raw offset. */
private final int rawOff;
/** Footer start. */
private final int footerStart;
/** Footer end. */
private final int footerLen;
/** Class descriptor. */
private BinaryClassDescriptor desc;
/** Mapper. */
private final BinaryInternalMapper mapper;
/** Schema Id. */
private final int schemaId;
/** Whether this is user type or not. */
private final boolean userType;
/** Whether field IDs exist. */
private final int fieldIdLen;
/** Offset size in bytes. */
private final int fieldOffLen;
/** Object schema. */
private final BinarySchema schema;
/** Whether passed IDs matches schema order. Reset to false as soon as a single mismatch detected. */
private boolean matching = true;
/** Order of a field whose match is expected. */
private int matchingOrder;
/** Whether stream is in raw mode. */
private boolean raw;
/**
* Constructor.
*
* @param ctx Context.
* @param in Input stream.
* @param ldr Class loader.
* @param forUnmarshal {@code True} if reader is needed to unmarshal object.
*/
public BinaryReaderExImpl(BinaryContext ctx, BinaryInputStream in, ClassLoader ldr, boolean forUnmarshal) {
this(ctx,
in,
ldr,
null,
forUnmarshal);
}
/**
* Constructor.
*
* @param ctx Context.
* @param in Input stream.
* @param ldr Class loader.
* @param hnds Context.
* @param forUnmarshal {@code True} if reader is need to unmarshal object.
*/
public BinaryReaderExImpl(BinaryContext ctx,
BinaryInputStream in,
ClassLoader ldr,
@Nullable BinaryReaderHandles hnds,
boolean forUnmarshal) {
this(ctx,
in,
ldr,
hnds,
false,
forUnmarshal);
}
/**
* Constructor.
*
* @param ctx Context.
* @param in Input stream.
* @param ldr Class loader.
* @param hnds Context.
* @param skipHdrCheck Whether to skip header check.
* @param forUnmarshal {@code True} if reader is need to unmarshal object.
*/
public BinaryReaderExImpl(BinaryContext ctx,
BinaryInputStream in,
ClassLoader ldr,
@Nullable BinaryReaderHandles hnds,
boolean skipHdrCheck,
boolean forUnmarshal) {
// Initialize base members.
this.ctx = ctx;
this.in = in;
this.ldr = ldr;
this.hnds = hnds;
start = in.position();
// Perform full header parsing in case of binary object.
if (!skipHdrCheck && (in.readByte() == GridBinaryMarshaller.OBJ)) {
// Ensure protocol is fine.
BinaryUtils.checkProtocolVersion(in.readByte());
// Read header content.
short flags = in.readShort();
int typeId0 = in.readInt();
in.readInt(); // Skip hash code.
int len = in.readInt();
schemaId = in.readInt();
int offset = in.readInt();
// Get trivial flag values.
userType = BinaryUtils.isUserType(flags);
fieldIdLen = BinaryUtils.fieldIdLength(flags);
fieldOffLen = BinaryUtils.fieldOffsetLength(flags);
// Calculate footer borders and raw offset.
if (BinaryUtils.hasSchema(flags)) {
// Schema exists.
footerStart = start + offset;
if (BinaryUtils.hasRaw(flags)) {
footerLen = len - offset;
rawOff = start + in.readIntPositioned(start + len - 4);
}
else {
footerLen = len - offset;
rawOff = start + len;
}
}
else {
// No schema.
footerStart = start + len;
footerLen = 0;
if (BinaryUtils.hasRaw(flags))
rawOff = start + offset;
else
rawOff = start + len;
}
// Finally, we have to resolve real type ID.
if (typeId0 == UNREGISTERED_TYPE_ID) {
int off = in.position();
if (forUnmarshal) {
// Registers class by type ID, at least locally if the cache is not ready yet.
desc = ctx.descriptorForClass(BinaryUtils.doReadClass(in, ctx, ldr, typeId0), false, false);
typeId = desc.typeId();
}
else
typeId = ctx.typeId(BinaryUtils.doReadClassName(in));
int clsNameLen = in.position() - off;
dataStart = start + DFLT_HDR_LEN + clsNameLen;
}
else {
typeId = typeId0;
dataStart = start + DFLT_HDR_LEN;
}
mapper = userType ? ctx.userTypeMapper(typeId) : BinaryContext.defaultMapper();
schema = BinaryUtils.hasSchema(flags) ? getOrCreateSchema() : null;
}
else {
dataStart = 0;
typeId = 0;
rawOff = 0;
footerStart = 0;
footerLen = 0;
mapper = null;
schemaId = 0;
userType = false;
fieldIdLen = 0;
fieldOffLen = 0;
schema = null;
}
streamPosition(start);
}
/**
* @return Input stream.
*/
public BinaryInputStream in() {
return in;
}
/**
* @return Descriptor.
*/
BinaryClassDescriptor descriptor() {
if (desc == null)
desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
return desc;
}
/**
* @param offset Offset in the array.
* @return Unmarshalled value.
* @throws BinaryObjectException In case of error.
*/
public Object unmarshal(int offset) throws BinaryObjectException {
streamPosition(offset);
return in.position() >= 0 ? BinaryUtils.unmarshal(in, ctx, ldr, this) : null;
}
/**
* @param fieldName Field name.
* @return Unmarshalled value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Object unmarshalField(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? BinaryUtils.unmarshal(in, ctx, ldr, this) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Unmarshalled value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Object unmarshalField(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? BinaryUtils.unmarshal(in, ctx, ldr, this) : null;
}
/**
* @param fieldId Field ID.
* @return Binary object.
* @throws BinaryObjectException In case of error.
*/
@Nullable BinaryObject readBinaryObject(int fieldId) throws BinaryObjectException {
if (findFieldById(fieldId)) {
if (checkFlag(BINARY_OBJ) == Flag.NULL)
return null;
return new BinaryObjectImpl(ctx, BinaryUtils.doReadByteArray(in), in.readInt());
}
else
return null;
}
/**
* @param fieldId Field ID.
* @return Field class.
* @throws BinaryObjectException In case of error.
*/
@Nullable Class<?> readClass(int fieldId) throws BinaryObjectException {
if (findFieldById(fieldId)) {
if (checkFlag(CLASS) == Flag.NULL)
return null;
return BinaryUtils.doReadClass(in, ctx, ldr);
}
return null;
}
/**
* @param obj Object.
*/
void setHandle(Object obj) {
setHandle(obj, start);
}
/** {@inheritDoc} */
@Override public void setHandle(Object obj, int pos) {
handles().put(pos, obj);
}
/** {@inheritDoc} */
@Override public Object getHandle(int pos) {
return hnds != null ? hnds.get(pos) : null;
}
/** {@inheritDoc} */
@Override public BinaryReaderHandles handles() {
if (hnds == null)
hnds = new BinaryReaderHandles();
return hnds;
}
/**
* Recreating field value from a handle.
*
* @param <T> Field type.
* @return Field.
*/
private <T> T readHandleField() {
int handlePos = BinaryUtils.positionForHandle(in) - in.readInt();
Object obj = getHandle(handlePos);
if (obj == null) {
int retPos = in.position();
streamPosition(handlePos);
obj = BinaryUtils.doReadObject(in, ctx, ldr, this);
streamPosition(retPos);
}
return (T)obj;
}
/**
* Wraps an exception by adding the fieldName
*
* @param fieldName the name of the field, causes failure
* @param e the cause of the deserialization failure
* @return wrapping exception
*/
private BinaryObjectException wrapFieldException(String fieldName, Exception e) {
if (S.INCLUDE_SENSITIVE)
return new BinaryObjectException("Failed to read field: " + fieldName, e);
else
return new BinaryObjectException("Failed to read field.", e);
}
/** {@inheritDoc} */
@Override public byte readByte(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
byte readByte(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Byte readByteNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : null;
}
/** {@inheritDoc} */
@Override public byte readByte() throws BinaryObjectException {
return in.readByte();
}
/** {@inheritDoc} */
@Nullable @Override public byte[] readByteArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readByteArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable byte[] readByteArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readByteArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public byte[] readByteArray() throws BinaryObjectException {
switch (checkFlag(BYTE_ARR)) {
case NORMAL:
return BinaryUtils.doReadByteArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public boolean readBoolean(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL && in.readBoolean();
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
boolean readBoolean(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL && in.readBoolean();
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Boolean readBooleanNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL ? in.readBoolean() : null;
}
/** {@inheritDoc} */
@Override public boolean readBoolean() throws BinaryObjectException {
return in.readBoolean();
}
/** {@inheritDoc} */
@Nullable @Override public boolean[] readBooleanArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readBooleanArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable boolean[] readBooleanArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readBooleanArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public boolean[] readBooleanArray() throws BinaryObjectException {
switch (checkFlag(BOOLEAN_ARR)) {
case NORMAL:
return BinaryUtils.doReadBooleanArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public short readShort(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
short readShort(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Short readShortNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : null;
}
/** {@inheritDoc} */
@Override public short readShort() throws BinaryObjectException {
return in.readShort();
}
/** {@inheritDoc} */
@Nullable @Override public short[] readShortArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readShortArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable short[] readShortArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readShortArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public short[] readShortArray() throws BinaryObjectException {
switch (checkFlag(SHORT_ARR)) {
case NORMAL:
return BinaryUtils.doReadShortArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public char readChar(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
char readChar(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Character readCharNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : null;
}
/** {@inheritDoc} */
@Override public char readChar() throws BinaryObjectException {
return in.readChar();
}
/** {@inheritDoc} */
@Nullable @Override public char[] readCharArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readCharArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable char[] readCharArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readCharArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public char[] readCharArray() throws BinaryObjectException {
switch (checkFlag(CHAR_ARR)) {
case NORMAL:
return BinaryUtils.doReadCharArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public int readInt(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
int readInt(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Integer readIntNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : null;
}
/** {@inheritDoc} */
@Override public int readInt() throws BinaryObjectException {
return in.readInt();
}
/** {@inheritDoc} */
@Nullable @Override public int[] readIntArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readIntArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable int[] readIntArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readIntArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public int[] readIntArray() throws BinaryObjectException {
switch (checkFlag(INT_ARR)) {
case NORMAL:
return BinaryUtils.doReadIntArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public long readLong(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
long readLong(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Long readLongNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : null;
}
/** {@inheritDoc} */
@Override public long readLong() throws BinaryObjectException {
return in.readLong();
}
/** {@inheritDoc} */
@Nullable @Override public long[] readLongArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readLongArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable long[] readLongArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readLongArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public long[] readLongArray() throws BinaryObjectException {
switch (checkFlag(LONG_ARR)) {
case NORMAL:
return BinaryUtils.doReadLongArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public float readFloat(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
float readFloat(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Float readFloatNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : null;
}
/** {@inheritDoc} */
@Override public float readFloat() throws BinaryObjectException {
return in.readFloat();
}
/** {@inheritDoc} */
@Nullable @Override public float[] readFloatArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readFloatArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable float[] readFloatArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readFloatArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public float[] readFloatArray() throws BinaryObjectException {
switch (checkFlag(FLOAT_ARR)) {
case NORMAL:
return BinaryUtils.doReadFloatArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override public double readDouble(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : 0;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException If failed.
*/
double readDouble(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : 0;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Double readDoubleNullable(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : null;
}
/** {@inheritDoc} */
@Override public double readDouble() throws BinaryObjectException {
return in.readDouble();
}
/** {@inheritDoc} */
@Nullable @Override public double[] readDoubleArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readDoubleArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable double[] readDoubleArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readDoubleArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public double[] readDoubleArray() throws BinaryObjectException {
switch (checkFlag(DOUBLE_ARR)) {
case NORMAL:
return BinaryUtils.doReadDoubleArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override @Nullable public BigDecimal readDecimal(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readDecimal() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable BigDecimal readDecimal(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readDecimal() : null;
}
/** {@inheritDoc} */
@Override @Nullable public BigDecimal readDecimal() throws BinaryObjectException {
return checkFlagNoHandles(DECIMAL) == Flag.NORMAL ? BinaryUtils.doReadDecimal(in) : null;
}
/** {@inheritDoc} */
@Override @Nullable public BigDecimal[] readDecimalArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readDecimalArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable BigDecimal[] readDecimalArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readDecimalArray() : null;
}
/** {@inheritDoc} */
@Override @Nullable public BigDecimal[] readDecimalArray() throws BinaryObjectException {
switch (checkFlag(DECIMAL_ARR)) {
case NORMAL:
return BinaryUtils.doReadDecimalArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override @Nullable public String readString(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readString() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable String readString(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readString() : null;
}
/** {@inheritDoc} */
@Override @Nullable public String readString() throws BinaryObjectException {
return checkFlagNoHandles(STRING) == Flag.NORMAL ? BinaryUtils.doReadString(in) : null;
}
/** {@inheritDoc} */
@Override @Nullable public String[] readStringArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readStringArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable String[] readStringArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readStringArray() : null;
}
/** {@inheritDoc} */
@Override @Nullable public String[] readStringArray() throws BinaryObjectException {
switch (checkFlag(STRING_ARR)) {
case NORMAL:
return BinaryUtils.doReadStringArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override @Nullable public UUID readUuid(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readUuid() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable UUID readUuid(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readUuid() : null;
}
/** {@inheritDoc} */
@Override @Nullable public UUID readUuid() throws BinaryObjectException {
return checkFlagNoHandles(UUID) == Flag.NORMAL ? BinaryUtils.doReadUuid(in) : null;
}
/** {@inheritDoc} */
@Override @Nullable public UUID[] readUuidArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readUuidArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable UUID[] readUuidArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readUuidArray() : null;
}
/** {@inheritDoc} */
@Override @Nullable public UUID[] readUuidArray() throws BinaryObjectException {
switch (checkFlag(UUID_ARR)) {
case NORMAL:
return BinaryUtils.doReadUuidArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override @Nullable public Date readDate(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readDate() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Date readDate(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readDate() : null;
}
/** {@inheritDoc} */
@Override @Nullable public Date readDate() throws BinaryObjectException {
return checkFlagNoHandles(DATE) == Flag.NORMAL ? BinaryUtils.doReadDate(in) : null;
}
/** {@inheritDoc} */
@Override @Nullable public Date[] readDateArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readDateArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Date[] readDateArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readDateArray() : null;
}
/** {@inheritDoc} */
@Override @Nullable public Date[] readDateArray() throws BinaryObjectException {
switch (checkFlag(DATE_ARR)) {
case NORMAL:
return BinaryUtils.doReadDateArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override @Nullable public Timestamp readTimestamp(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readTimestamp() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Timestamp readTimestamp(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readTimestamp() : null;
}
/** {@inheritDoc} */
@Override @Nullable public Timestamp readTimestamp() throws BinaryObjectException {
return checkFlagNoHandles(TIMESTAMP) == Flag.NORMAL ? BinaryUtils.doReadTimestamp(in) : null;
}
/** {@inheritDoc} */
@Override @Nullable public Timestamp[] readTimestampArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readTimestampArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Timestamp[] readTimestampArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readTimestampArray() : null;
}
/** {@inheritDoc} */
@Override @Nullable public Timestamp[] readTimestampArray() throws BinaryObjectException {
switch (checkFlag(TIMESTAMP_ARR)) {
case NORMAL:
return BinaryUtils.doReadTimestampArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Override @Nullable public Time readTime(String fieldName) throws BinaryObjectException {
return findFieldByName(fieldName) ? this.readTime() : null;
}
/** {@inheritDoc} */
@Override @Nullable public Time readTime() throws BinaryObjectException {
return checkFlagNoHandles(TIME) == Flag.NORMAL ? BinaryUtils.doReadTime(in) : null;
}
/** {@inheritDoc} */
@Override @Nullable public Time[] readTimeArray(String fieldName) throws BinaryObjectException {
return findFieldByName(fieldName) ? this.readTimeArray() : null;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Time readTime(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readTime() : null;
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Time[] readTimeArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readTimeArray() : null;
}
/** {@inheritDoc} */
@Override @Nullable public Time[] readTimeArray() throws BinaryObjectException {
switch (checkFlag(TIME_ARR)) {
case NORMAL:
return BinaryUtils.doReadTimeArray(in);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Nullable @Override public <T> T readObject(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? (T)BinaryUtils.doReadObject(in, ctx, ldr, this) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Object readObject(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? BinaryUtils.doReadObject(in, ctx, ldr, this) : null;
}
/** {@inheritDoc} */
@Override public Object readObject() throws BinaryObjectException {
return BinaryUtils.doReadObject(in, ctx, ldr, this);
}
/** {@inheritDoc} */
@Nullable @Override public Object readObjectDetached() throws BinaryObjectException {
return BinaryUtils.unmarshal(in, ctx, ldr, this, true);
}
/** {@inheritDoc} */
@Nullable @Override public Object[] readObjectArray(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? this.readObjectArray() : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Object[] readObjectArray(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? this.readObjectArray() : null;
}
/** {@inheritDoc} */
@Nullable @Override public Object[] readObjectArray() throws BinaryObjectException {
switch (checkFlag(OBJ_ARR)) {
case NORMAL:
return BinaryUtils.doReadObjectArray(in, ctx, ldr, this, true);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Nullable @Override public <T extends Enum<?>> T readEnum(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? (T)readEnum0(null) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @param cls Class.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Enum<?> readEnum(int fieldId, @Nullable Class<?> cls) throws BinaryObjectException {
return findFieldById(fieldId) ? readEnum0(cls) : null;
}
/** {@inheritDoc} */
@Nullable @Override public <T extends Enum<?>> T readEnum() throws BinaryObjectException {
return (T)readEnum0(null);
}
/**
* Internal routine to read enum for named field.
*
* @param cls Class.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
private Enum<?> readEnum0(@Nullable Class<?> cls) throws BinaryObjectException {
if (checkFlagNoHandles(ENUM) == Flag.NORMAL) {
// Read class even if we know it in advance to set correct stream position.
Class<?> cls0 = BinaryUtils.doReadClass(in, ctx, ldr);
if (cls == null)
cls = cls0;
return BinaryUtils.doReadEnum(in, cls);
}
else
return null;
}
/** {@inheritDoc} */
@Nullable @Override public <T extends Enum<?>> T[] readEnumArray(String fieldName)
throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? (T[])readEnumArray0(null) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @return Binary Enum
* @throws BinaryObjectException If failed.
*/
@Nullable BinaryEnumObjectImpl readBinaryEnum(int fieldId) throws BinaryObjectException {
return findFieldById(fieldId) ? BinaryUtils.doReadBinaryEnum(in, ctx) : null;
}
/**
* @param fieldId Field ID.
* @param cls Class.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Object[] readEnumArray(int fieldId, @Nullable Class<?> cls) throws BinaryObjectException {
return findFieldById(fieldId) ? readEnumArray0(cls) : null;
}
/** {@inheritDoc} */
@Nullable @Override public <T extends Enum<?>> T[] readEnumArray() throws BinaryObjectException {
return (T[])readEnumArray0(null);
}
/**
* Internal routine to read enum for named field.
*
* @param cls Class.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
private Object[] readEnumArray0(@Nullable Class<?> cls) throws BinaryObjectException {
switch (checkFlag(ENUM_ARR)) {
case NORMAL:
// Read class even if we know it in advance to set correct stream position.
Class<?> cls0 = BinaryUtils.doReadClass(in, ctx, ldr);
if (cls == null)
cls = cls0;
return BinaryUtils.doReadEnumArray(in, ctx, ldr, cls);
case HANDLE:
return readHandleField();
default:
return null;
}
}
/** {@inheritDoc} */
@Nullable @Override public <T> Collection<T> readCollection(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? (Collection<T>)readCollection0(null) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/** {@inheritDoc} */
@Nullable @Override public <T> Collection<T> readCollection(String fieldName, BinaryCollectionFactory<T> factory)
throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? readCollection0(factory) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @param factory Collection factory.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable <T> Collection<T> readCollection(int fieldId, @Nullable BinaryCollectionFactory<T> factory)
throws BinaryObjectException {
return findFieldById(fieldId) ? (Collection<T>)readCollection0(factory) : null;
}
/** {@inheritDoc} */
@Nullable @Override public <T> Collection<T> readCollection() throws BinaryObjectException {
return readCollection0(null);
}
/** {@inheritDoc} */
@Nullable @Override public <T> Collection<T> readCollection(BinaryCollectionFactory<T> factory)
throws BinaryObjectException {
return readCollection0(factory);
}
/**
* Internal read collection routine.
*
* @param factory Collection factory.
* @return Value.
* @throws BinaryObjectException If failed.
*/
private Collection readCollection0(@Nullable BinaryCollectionFactory factory)
throws BinaryObjectException {
switch (checkFlag(COL)) {
case NORMAL:
return (Collection)BinaryUtils.doReadCollection(in, ctx, ldr, this, true, factory);
case HANDLE: {
int handlePos = BinaryUtils.positionForHandle(in) - in.readInt();
Object obj = getHandle(handlePos);
if (obj == null) {
int retPos = in.position();
streamPosition(handlePos);
obj = readCollection0(factory);
streamPosition(retPos);
}
return (Collection)obj;
}
default:
return null;
}
}
/** {@inheritDoc} */
@Nullable @Override public <K, V> Map<K, V> readMap(String fieldName) throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? (Map<K, V>)readMap0(null) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/** {@inheritDoc} */
@Nullable @Override public <K, V> Map<K, V> readMap(String fieldName, BinaryMapFactory<K, V> factory)
throws BinaryObjectException {
try {
return findFieldByName(fieldName) ? readMap0(factory) : null;
}
catch (Exception ex) {
throw wrapFieldException(fieldName, ex);
}
}
/**
* @param fieldId Field ID.
* @param factory Factory.
* @return Value.
* @throws BinaryObjectException In case of error.
*/
@Nullable Map<?, ?> readMap(int fieldId, @Nullable BinaryMapFactory factory) throws BinaryObjectException {
return findFieldById(fieldId) ? readMap0(factory) : null;
}
/** {@inheritDoc} */
@Nullable @Override public <K, V> Map<K, V> readMap() throws BinaryObjectException {
return readMap0(null);
}
/** {@inheritDoc} */
@Nullable @Override public <K, V> Map<K, V> readMap(BinaryMapFactory<K, V> factory)
throws BinaryObjectException {
return readMap0(factory);
}
/**
* Internal read map routine.
*
* @param factory Factory.
* @return Value.
* @throws BinaryObjectException If failed.
*/
private Map readMap0(@Nullable BinaryMapFactory factory) throws BinaryObjectException {
switch (checkFlag(MAP)) {
case NORMAL:
return (Map)BinaryUtils.doReadMap(in, ctx, ldr, this, true, factory);
case HANDLE: {
int handlePos = BinaryUtils.positionForHandle(in) - in.readInt();
Object obj = getHandle(handlePos);
if (obj == null) {
int retPos = in.position();
streamPosition(handlePos);
obj = readMap0(factory);
streamPosition(retPos);
}
return (Map)obj;
}
default:
return null;
}
}
/**
* Ensure that type flag is either null, handle or contains expected value.
*
* @param expFlag Expected value.
* @return Flag mode.
* @throws BinaryObjectException If flag is neither null, nor handle or expected.
*/
private Flag checkFlag(byte expFlag) {
byte flag = in.readByte();
if (flag == expFlag)
return Flag.NORMAL;
else if (flag == NULL)
return Flag.NULL;
else if (flag == HANDLE)
return Flag.HANDLE;
int pos = BinaryUtils.positionForHandle(in);
throw new BinaryObjectException("Unexpected field type [pos=" + pos + ", expected=" + fieldFlagName(expFlag) +
", actual=" + fieldFlagName(flag) + ']');
}
/**
* Ensure that type flag is either null or contains expected value.
*
* @param expFlag Expected value.
* @return Flag mode.
* @throws BinaryObjectException If flag is neither null, nor expected.
*/
private Flag checkFlagNoHandles(byte expFlag) {
byte flag = in.readByte();
if (flag == expFlag)
return Flag.NORMAL;
else if (flag == NULL)
return Flag.NULL;
int pos = BinaryUtils.positionForHandle(in);
throw new BinaryObjectException("Unexpected field type [pos=" + pos + ", expected=" + fieldFlagName(expFlag) +
", actual=" + fieldFlagName(flag) + ']');
}
/**
* Gets a flag name
*
* @param flag a flag value
* @return string representation of the flag (type name, handle, else number)
*/
private String fieldFlagName(byte flag) {
String typeName = BinaryUtils.fieldTypeName(flag);
return typeName == null ? String.valueOf(flag) : typeName;
}
/** {@inheritDoc} */
@Override public BinaryRawReader rawReader() {
if (!raw) {
streamPositionRandom(rawOff);
raw = true;
return this;
}
else
throw new BinaryObjectException("Method \"rawReader\" can be called only once.");
}
/**
* @return Deserialized object.
* @throws BinaryObjectException If failed.
*/
@Nullable Object deserialize() throws BinaryObjectException {
String newName = ctx.configuration().getIgniteInstanceName();
String oldName = IgniteUtils.setCurrentIgniteName(newName);
try {
return deserialize0();
}
finally {
IgniteUtils.restoreOldIgniteName(oldName, newName);
}
}
/**
* @return Deserialized object.
* @throws BinaryObjectException If failed.
*/
@Nullable private Object deserialize0() throws BinaryObjectException {
Object obj;
byte flag = in.readByte();
switch (flag) {
case NULL:
obj = null;
break;
case HANDLE:
int handlePos = start - in.readInt();
obj = getHandle(handlePos);
if (obj == null) {
int retPos = in.position();
streamPosition(handlePos);
obj = BinaryUtils.doReadObject(in, ctx, ldr, this);
streamPosition(retPos);
}
break;
case OBJ:
if (desc == null)
desc = ctx.descriptorForTypeId(userType, typeId, ldr, true);
streamPosition(dataStart);
if (desc == null)
throw new BinaryInvalidTypeException("Unknown type ID: " + typeId);
obj = desc.read(this);
streamPosition(footerStart + footerLen);
break;
case BYTE:
obj = in.readByte();
break;
case SHORT:
obj = in.readShort();
break;
case INT:
obj = in.readInt();
break;
case LONG:
obj = in.readLong();
break;
case FLOAT:
obj = in.readFloat();
break;
case DOUBLE:
obj = in.readDouble();
break;
case CHAR:
obj = in.readChar();
break;
case BOOLEAN:
obj = in.readBoolean();
break;
case DECIMAL:
obj = BinaryUtils.doReadDecimal(in);
break;
case STRING:
obj = BinaryUtils.doReadString(in);
break;
case UUID:
obj = BinaryUtils.doReadUuid(in);
break;
case DATE:
obj = BinaryUtils.doReadDate(in);
break;
case TIMESTAMP:
obj = BinaryUtils.doReadTimestamp(in);
break;
case TIME:
obj = BinaryUtils.doReadTime(in);
break;
case BYTE_ARR:
obj = BinaryUtils.doReadByteArray(in);
break;
case SHORT_ARR:
obj = BinaryUtils.doReadShortArray(in);
break;
case INT_ARR:
obj = BinaryUtils.doReadIntArray(in);
break;
case LONG_ARR:
obj = BinaryUtils.doReadLongArray(in);
break;
case FLOAT_ARR:
obj = BinaryUtils.doReadFloatArray(in);
break;
case DOUBLE_ARR:
obj = BinaryUtils.doReadDoubleArray(in);
break;
case CHAR_ARR:
obj = BinaryUtils.doReadCharArray(in);
break;
case BOOLEAN_ARR:
obj = BinaryUtils.doReadBooleanArray(in);
break;
case DECIMAL_ARR:
obj = BinaryUtils.doReadDecimalArray(in);
break;
case STRING_ARR:
obj = BinaryUtils.doReadStringArray(in);
break;
case UUID_ARR:
obj = BinaryUtils.doReadUuidArray(in);
break;
case DATE_ARR:
obj = BinaryUtils.doReadDateArray(in);
break;
case TIMESTAMP_ARR:
obj = BinaryUtils.doReadTimestampArray(in);
break;
case TIME_ARR:
obj = BinaryUtils.doReadTimeArray(in);
break;
case OBJ_ARR:
obj = BinaryUtils.doReadObjectArray(in, ctx, ldr, this, true);
break;
case COL:
obj = BinaryUtils.doReadCollection(in, ctx, ldr, this, true, null);
break;
case MAP:
obj = BinaryUtils.doReadMap(in, ctx, ldr, this, true, null);
break;
case BINARY_OBJ:
obj = BinaryUtils.doReadBinaryObject(in, ctx, false);
((BinaryObjectImpl)obj).context(ctx);
if (!GridBinaryMarshaller.KEEP_BINARIES.get())
obj = ((BinaryObject)obj).deserialize();
break;
case ENUM:
obj = BinaryUtils.doReadEnum(in, BinaryUtils.doReadClass(in, ctx, ldr));
break;
case ENUM_ARR:
obj = BinaryUtils.doReadEnumArray(in, ctx, ldr, BinaryUtils.doReadClass(in, ctx, ldr));
break;
case BINARY_ENUM:
obj = BinaryUtils.doReadBinaryEnum(in, ctx);
if (!GridBinaryMarshaller.KEEP_BINARIES.get())
obj = ((BinaryObject)obj).deserialize();
break;
case CLASS:
obj = BinaryUtils.doReadClass(in, ctx, ldr);
break;
case PROXY:
obj = BinaryUtils.doReadProxy(in, ctx, ldr, this);
break;
case OPTM_MARSH:
obj = BinaryUtils.doReadOptimized(in, ctx, ldr);
break;
default:
throw new BinaryObjectException("Invalid flag value: " + flag);
}
return obj;
}
/**
* @param fieldId Field ID.
* @return Deserialized object.
* @throws BinaryObjectException If failed.
*/
@Nullable Object readField(int fieldId) throws BinaryObjectException {
if (!findFieldById(fieldId))
return null;
return new BinaryReaderExImpl(ctx, in, ldr, hnds, true).deserialize();
}
/**
* @param name Field name.
* @return Field offset.
*/
private int fieldId(String name) {
assert name != null;
return mapper.fieldId(typeId, name);
}
/**
* Get or create object schema.
*
* @return Schema.
*/
public BinarySchema getOrCreateSchema() {
BinarySchema schema = ctx.schemaRegistry(typeId).schema(schemaId);
if (schema == null) {
if (fieldIdLen != BinaryUtils.FIELD_ID_LEN) {
BinaryTypeImpl type = (BinaryTypeImpl) ctx.metadata(typeId, schemaId);
BinaryMetadata meta = type != null ? type.metadata() : null;
if (type == null || meta == null)
throw new BinaryObjectException("Cannot find metadata for object with compact footer: " +
typeId);
Collection<BinarySchema> existingSchemas = meta.schemas();
for (BinarySchema existingSchema : existingSchemas) {
if (schemaId == existingSchema.schemaId()) {
schema = existingSchema;
break;
}
}
if (schema == null) {
List<Integer> existingSchemaIds = new ArrayList<>(existingSchemas.size());
for (BinarySchema existingSchema : existingSchemas)
existingSchemaIds.add(existingSchema.schemaId());
throw new BinaryObjectException("Cannot find schema for object with compact footer" +
" [typeName=" + type.typeName() +
", typeId=" + typeId +
", missingSchemaId=" + schemaId +
", existingSchemaIds=" + existingSchemaIds + ']'
);
}
}
else
schema = createSchema();
assert schema != null;
ctx.schemaRegistry(typeId).addSchema(schemaId, schema);
}
return schema;
}
/**
* Create schema.
*
* @return Schema.
*/
private BinarySchema createSchema() {
assert fieldIdLen == BinaryUtils.FIELD_ID_LEN;
BinarySchema.Builder builder = BinarySchema.Builder.newBuilder();
int searchPos = footerStart;
int searchEnd = searchPos + footerLen;
while (searchPos < searchEnd) {
int fieldId = in.readIntPositioned(searchPos);
builder.addField(fieldId);
searchPos += BinaryUtils.FIELD_ID_LEN + fieldOffLen;
}
return builder.build();
}
/**
* Try finding the field by name.
*
* @param name Field name.
* @return Offset.
*/
public boolean findFieldByName(String name) {
if (raw)
throw new BinaryObjectException("Failed to read named field because reader is in raw mode.");
assert dataStart != start;
if (footerLen == 0)
return false;
if (userType) {
int order;
if (matching) {
int expOrder = matchingOrder++;
BinarySchema.Confirmation confirm = schema.confirmOrder(expOrder, name);
switch (confirm) {
case CONFIRMED:
// The best case: got order without ID calculation and (ID -> order) lookup.
if (expOrder == 0)
// When we read the very first field, position is set to start, hence this re-positioning.
streamPosition(dataStart);
return true;
case REJECTED:
// Rejected, no more speculations are possible. Fallback to the slowest scenario.
matching = false;
order = schema.order(fieldId(name));
break;
default:
// Field name is not know for this order. Need to calculate ID and repeat speculation.
assert confirm == BinarySchema.Confirmation.CLARIFY;
int id = fieldId(name);
int realId = schema.fieldId(expOrder);
if (id == realId) {
// IDs matched, cache field name inside schema.
schema.clarifyFieldName(expOrder, name);
if (expOrder == 0)
streamPosition(dataStart);
return true;
}
else {
// No match, stop further speculations.
matching = false;
order = schema.order(id);
}
break;
}
}
else
order = schema.order(fieldId(name));
return trySetUserFieldPosition(order);
}
else
return trySetSystemFieldPosition(fieldId(name));
}
/**
* Try finding the field by ID. Used for types with stable schema (Serializable) to avoid
* (string -> ID) calculations.
*
* @param id Field ID.
* @return {@code True} if field was found and stream was positioned accordingly.
*/
private boolean findFieldById(int id) {
assert !raw; // Assert, not exception, because this is called only from internals for Serializable types.
assert dataStart != start;
if (footerLen == 0)
return false;
if (userType) {
int order;
if (matching) {
// Trying to get field order speculatively.
int expOrder = matchingOrder++;
int realId = schema.fieldId(expOrder);
if (realId == id) {
if (expOrder == 0)
streamPosition(dataStart);
return true;
}
else {
// Mismatch detected, no need for further speculations.
matching = false;
order = schema.order(id);
}
}
else
order = schema.order(id);
return trySetUserFieldPosition(order);
}
else
return trySetSystemFieldPosition(id);
}
/**
* Set position for the given user field order.
*
* @param order Order.
* @return {@code True} if field was found and stream was positioned accordingly.
*/
private boolean trySetUserFieldPosition(int order) {
if (order != BinarySchema.ORDER_NOT_FOUND) {
int offsetPos = footerStart + order * (fieldIdLen + fieldOffLen) + fieldIdLen;
int pos = start + BinaryUtils.fieldOffsetRelative(in, offsetPos, fieldOffLen);
streamPosition(pos);
return true;
}
else
return false;
}
/**
* Set position for the given system field ID.
*
* @param id Field ID.
* @return {@code True} if field was found and stream was positioned accordingly.
*/
private boolean trySetSystemFieldPosition(int id) {
// System types are never written with compact footers because they do not have metadata.
assert fieldIdLen == BinaryUtils.FIELD_ID_LEN;
int searchPos = footerStart;
int searchTail = searchPos + footerLen;
while (true) {
if (searchPos >= searchTail)
return false;
int id0 = in.readIntPositioned(searchPos);
if (id0 == id) {
int pos = start + BinaryUtils.fieldOffsetRelative(in, searchPos + BinaryUtils.FIELD_ID_LEN,
fieldOffLen);
streamPosition(pos);
return true;
}
searchPos += BinaryUtils.FIELD_ID_LEN + fieldOffLen;
}
}
/**
* Set stream position.
*
* @param pos Position.
*/
private void streamPosition(int pos) {
in.position(pos);
}
/**
* Set stream position as a part of some random read. Further speculations will be disabled after this call.
*
* @param pos Position.
*/
private void streamPositionRandom(int pos) {
streamPosition(pos);
matching = false;
}
/** {@inheritDoc} */
@Override public int readUnsignedByte() throws IOException {
return readByte() & 0xff;
}
/** {@inheritDoc} */
@Override public int readUnsignedShort() throws IOException {
return readShort() & 0xffff;
}
/** {@inheritDoc} */
@Override public String readLine() throws IOException {
SB sb = new SB();
int b;
while ((b = read()) >= 0) {
char c = (char)b;
switch (c) {
case '\n':
return sb.toString();
case '\r':
b = read();
if (b < 0 || b == '\n')
return sb.toString();
else
sb.a((char)b);
break;
default:
sb.a(c);
}
}
return sb.toString();
}
/** {@inheritDoc} */
@SuppressWarnings("ConstantConditions")
@NotNull @Override public String readUTF() throws IOException {
return readString();
}
/** {@inheritDoc} */
@SuppressWarnings("NullableProblems")
@Override public void readFully(byte[] b) throws IOException {
readFully(b, 0, b.length);
}
/** {@inheritDoc} */
@SuppressWarnings("NullableProblems")
@Override public void readFully(byte[] b, int off, int len) throws IOException {
int cnt = in.read(b, off, len);
if (cnt < len)
throw new EOFException();
}
/** {@inheritDoc} */
@Override public int skipBytes(int n) throws IOException {
int toSkip = Math.min(in.remaining(), n);
streamPositionRandom(in.position() + toSkip);
return toSkip;
}
/** {@inheritDoc} */
@Override public int read() throws IOException {
return readByte();
}
/** {@inheritDoc} */
@Override public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
/** {@inheritDoc} */
@Override public int read(byte[] b, int off, int len) throws IOException {
return in.read(b, off, len);
}
/** {@inheritDoc} */
@Override public long skip(long n) throws IOException {
return skipBytes((int) n);
}
/** {@inheritDoc} */
@Override public int available() throws IOException {
return in.remaining();
}
/** {@inheritDoc} */
@Override public void close() throws IOException {
// No-op.
}
/**
* @return Binary context.
*/
public BinaryContext context() {
return ctx;
}
/**
* Flag.
*/
private enum Flag {
/** Regular. */
NORMAL,
/** Handle. */
HANDLE,
/** Null. */
NULL
}
}