You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/12/11 13:52:34 UTC

[32/42] ignite git commit: ignite-2065: rename "portable" packages to "binary"

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
new file mode 100644
index 0000000..bf47d53
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderExImpl.java
@@ -0,0 +1,2028 @@
+/*
+ * 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.Timestamp;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.ignite.binary.BinaryCollectionFactory;
+import org.apache.ignite.binary.BinaryIdMapper;
+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.PortableInputStream;
+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.GridPortableMarshaller.BOOLEAN;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.BOOLEAN_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.BYTE;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.BYTE_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.CHAR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.CHAR_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.CLASS;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.COL;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DATE;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DATE_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DECIMAL;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DECIMAL_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DFLT_HDR_LEN;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DOUBLE;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.DOUBLE_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.ENUM;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.ENUM_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.FLOAT;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.FLOAT_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.HANDLE;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.INT;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.INT_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.LONG;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.LONG_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.MAP;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.NULL;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.OBJ;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.OBJ_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.OPTM_MARSH;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.PORTABLE_OBJ;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.SHORT;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.SHORT_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.STRING;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.STRING_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.TIMESTAMP;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.TIMESTAMP_ARR;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.UNREGISTERED_TYPE_ID;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.UUID;
+import static org.apache.ignite.internal.binary.GridPortableMarshaller.UUID_ARR;
+
+/**
+ * Portable reader implementation.
+ */
+@SuppressWarnings("unchecked")
+public class BinaryReaderExImpl implements BinaryReader, BinaryRawReaderEx, BinaryReaderHandlesHolder, ObjectInput {
+    /** Portable context. */
+    private final PortableContext ctx;
+
+    /** Input stream. */
+    private final PortableInputStream 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;
+
+    /** ID mapper. */
+    private final BinaryIdMapper idMapper;
+
+    /** 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 fieldOffsetLen;
+
+    /** Object schema. */
+    private final PortableSchema 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.
+     */
+    public BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, ClassLoader ldr) {
+        this(ctx, in, ldr, null);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Context.
+     * @param in Input stream.
+     * @param ldr Class loader.
+     * @param hnds Context.
+     */
+    public BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, ClassLoader ldr,
+        @Nullable BinaryReaderHandles hnds) {
+        this(ctx, in, ldr, hnds, false);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Context.
+     * @param in Input stream.
+     * @param ldr Class loader.
+     * @param hnds Context.
+     * @param skipHdrCheck Whether to skip header check.
+     */
+    public BinaryReaderExImpl(PortableContext ctx, PortableInputStream in, ClassLoader ldr,
+        @Nullable BinaryReaderHandles hnds, boolean skipHdrCheck) {
+        // 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 portable object.
+        if (!skipHdrCheck && (in.readByte() == GridPortableMarshaller.OBJ)) {
+            // Ensure protocol is fine.
+            PortableUtils.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 = PortableUtils.isUserType(flags);
+            fieldIdLen = PortableUtils.fieldIdLength(flags);
+            fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
+
+            // Calculate footer borders and raw offset.
+            if (PortableUtils.hasSchema(flags)) {
+                // Schema exists.
+                footerStart = start + offset;
+
+                if (PortableUtils.hasRaw(flags)) {
+                    footerLen = len - offset - 4;
+                    rawOff = start + in.readIntPositioned(start + len - 4);
+                }
+                else {
+                    footerLen = len - offset;
+                    rawOff = start + len;
+                }
+            }
+            else {
+                // No schema.
+                footerStart = start + len;
+                footerLen = 0;
+
+                if (PortableUtils.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();
+
+                // Registers class by type ID, at least locally if the cache is not ready yet.
+                typeId = ctx.descriptorForClass(PortableUtils.doReadClass(in, ctx, ldr, typeId0), false).typeId();
+
+                int clsNameLen = in.position() - off;
+
+                dataStart = start + DFLT_HDR_LEN + clsNameLen;
+            }
+            else {
+                typeId = typeId0;
+
+                dataStart = start + DFLT_HDR_LEN;
+            }
+
+            idMapper = userType ? ctx.userTypeIdMapper(typeId) : BinaryInternalIdMapper.defaultInstance();
+            schema = PortableUtils.hasSchema(flags) ? getOrCreateSchema() : null;
+        }
+        else {
+            dataStart = 0;
+            typeId = 0;
+            rawOff = 0;
+            footerStart = 0;
+            footerLen = 0;
+            idMapper = null;
+            schemaId = 0;
+            userType = false;
+            fieldIdLen = 0;
+            fieldOffsetLen = 0;
+            schema = null;
+        }
+
+        streamPosition(start);
+    }
+
+    /**
+     * @return Input stream.
+     */
+    public PortableInputStream in() {
+        return in;
+    }
+
+    /**
+     * @return Descriptor.
+     */
+    PortableClassDescriptor descriptor() {
+        return ctx.descriptorForTypeId(userType, typeId, ldr, true);
+    }
+
+    /**
+     * @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 ? PortableUtils.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 {
+        return findFieldByName(fieldName) ? PortableUtils.unmarshal(in, ctx, ldr, this) : null;
+    }
+
+    /**
+     * @param fieldId Field ID.
+     * @return Unmarshalled value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Object unmarshalField(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? PortableUtils.unmarshal(in, ctx, ldr, this) : null;
+    }
+
+    /**
+     * @param fieldId Field ID.
+     * @return Portable object.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable BinaryObject readPortableObject(int fieldId) throws BinaryObjectException {
+        if (findFieldById(fieldId)) {
+            if (checkFlag(PORTABLE_OBJ) == Flag.NULL)
+                return null;
+
+            return new BinaryObjectImpl(ctx, PortableUtils.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 PortableUtils.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 = PortableUtils.positionForHandle(in) - in.readInt();
+
+        Object obj = getHandle(handlePos);
+
+        if (obj == null) {
+            int retPos = in.position();
+
+            streamPosition(handlePos);
+
+            obj = PortableUtils.doReadObject(in, ctx, ldr, this);
+
+            streamPosition(retPos);
+        }
+
+        return (T)obj;
+    }
+    /** {@inheritDoc} */
+    @Override public byte readByte(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(BYTE) == Flag.NORMAL ? in.readByte() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readByteArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadByteArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean readBoolean(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(BOOLEAN) == Flag.NORMAL && in.readBoolean();
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readBooleanArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadBooleanArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public short readShort(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(SHORT) == Flag.NORMAL ? in.readShort() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readShortArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadShortArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public char readChar(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(CHAR) == Flag.NORMAL ? in.readChar() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readCharArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadCharArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public int readInt(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(INT) == Flag.NORMAL ? in.readInt() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readIntArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadIntArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public long readLong(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(LONG) == Flag.NORMAL ? in.readLong() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readLongArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadLongArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public float readFloat(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(FLOAT) == Flag.NORMAL ? in.readFloat() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readFloatArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadFloatArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public double readDouble(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) && checkFlagNoHandles(DOUBLE) == Flag.NORMAL ? in.readDouble() : 0;
+    }
+
+    /**
+     * @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 {
+        return findFieldByName(fieldName) ? this.readDoubleArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadDoubleArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public BigDecimal readDecimal(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDecimal() : null;
+    }
+
+    /**
+     * @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 ? PortableUtils.doReadDecimal(in) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public BigDecimal[] readDecimalArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDecimalArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadDecimalArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public String readString(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readString() : null;
+    }
+
+    /**
+     * @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 ? PortableUtils.doReadString(in) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public String[] readStringArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readStringArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadStringArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public UUID readUuid(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readUuid() : null;
+    }
+
+    /**
+     * @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 ? PortableUtils.doReadUuid(in) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public UUID[] readUuidArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readUuidArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadUuidArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public Date readDate(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDate() : null;
+    }
+
+    /**
+     * @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 ? PortableUtils.doReadDate(in) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public Date[] readDateArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readDateArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadDateArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public Timestamp readTimestamp(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readTimestamp() : null;
+    }
+
+    /**
+     * @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 ? PortableUtils.doReadTimestamp(in) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override @Nullable public Timestamp[] readTimestampArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readTimestampArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.doReadTimestampArray(in);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Nullable @Override public <T> T readObject(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (T)PortableUtils.doReadObject(in, ctx, ldr, this) : null;
+    }
+
+    /**
+     * @param fieldId Field ID.
+     * @return Value.
+     * @throws BinaryObjectException In case of error.
+     */
+    @Nullable Object readObject(int fieldId) throws BinaryObjectException {
+        return findFieldById(fieldId) ? PortableUtils.doReadObject(in, ctx, ldr, this) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object readObject() throws BinaryObjectException {
+        return PortableUtils.doReadObject(in, ctx, ldr, this);
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public Object readObjectDetached() throws BinaryObjectException {
+        return PortableUtils.unmarshal(in, ctx, ldr, this, true);
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public Object[] readObjectArray(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? this.readObjectArray() : null;
+    }
+
+    /**
+     * @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 PortableUtils.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 {
+        return findFieldByName(fieldName) ? (T)readEnum0(null) : null;
+    }
+
+    /**
+     * @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 = PortableUtils.doReadClass(in, ctx, ldr);
+
+            if (cls == null)
+                cls = cls0;
+
+            return PortableUtils.doReadEnum(in, cls);
+        }
+        else
+            return null;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public <T extends Enum<?>> T[] readEnumArray(String fieldName)
+        throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (T[])readEnumArray0(null) : 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 = PortableUtils.doReadClass(in, ctx, ldr);
+
+                if (cls == null)
+                    cls = cls0;
+
+                return PortableUtils.doReadEnumArray(in, ctx, ldr, cls);
+
+            case HANDLE:
+                return readHandleField();
+
+            default:
+                return null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public <T> Collection<T> readCollection(String fieldName) throws BinaryObjectException {
+        return findFieldByName(fieldName) ? (Collection<T>)readCollection0(null) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public <T> Collection<T> readCollection(String fieldName, BinaryCollectionFactory<T> factory)
+        throws BinaryObjectException {
+        return findFieldByName(fieldName) ? readCollection0(factory) : null;
+    }
+
+    /**
+     * @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)PortableUtils.doReadCollection(in, ctx, ldr, this, true, factory);
+
+            case HANDLE: {
+                int handlePos = PortableUtils.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 {
+        return findFieldByName(fieldName) ? (Map<K, V>)readMap0(null) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName, BinaryMapFactory<K, V> factory)
+        throws BinaryObjectException {
+        return findFieldByName(fieldName) ? readMap0(factory) : null;
+    }
+
+    /**
+     * @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)PortableUtils.doReadMap(in, ctx, ldr, this, true, factory);
+
+            case HANDLE: {
+                int handlePos = PortableUtils.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 = PortableUtils.positionForHandle(in);
+
+        throw new BinaryObjectException("Unexpected flag value [pos=" + pos + ", expected=" + expFlag +
+            ", actual=" + 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 = PortableUtils.positionForHandle(in);
+
+        throw new BinaryObjectException("Unexpected flag value [pos=" + pos + ", expected=" + expFlag +
+            ", actual=" + flag + ']');
+    }
+
+    /** {@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 {
+        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 = PortableUtils.doReadObject(in, ctx, ldr, this);
+
+                    streamPosition(retPos);
+                }
+
+                break;
+
+            case OBJ:
+                PortableClassDescriptor 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 = PortableUtils.doReadDecimal(in);
+
+                break;
+
+            case STRING:
+                obj = PortableUtils.doReadString(in);
+
+                break;
+
+            case UUID:
+                obj = PortableUtils.doReadUuid(in);
+
+                break;
+
+            case DATE:
+                obj = PortableUtils.doReadDate(in);
+
+                break;
+
+            case TIMESTAMP:
+                obj = PortableUtils.doReadTimestamp(in);
+
+                break;
+
+            case BYTE_ARR:
+                obj = PortableUtils.doReadByteArray(in);
+
+                break;
+
+            case SHORT_ARR:
+                obj = PortableUtils.doReadShortArray(in);
+
+                break;
+
+            case INT_ARR:
+                obj = PortableUtils.doReadIntArray(in);
+
+                break;
+
+            case LONG_ARR:
+                obj = PortableUtils.doReadLongArray(in);
+
+                break;
+
+            case FLOAT_ARR:
+                obj = PortableUtils.doReadFloatArray(in);
+
+                break;
+
+            case DOUBLE_ARR:
+                obj = PortableUtils.doReadDoubleArray(in);
+
+                break;
+
+            case CHAR_ARR:
+                obj = PortableUtils.doReadCharArray(in);
+
+                break;
+
+            case BOOLEAN_ARR:
+                obj = PortableUtils.doReadBooleanArray(in);
+
+                break;
+
+            case DECIMAL_ARR:
+                obj = PortableUtils.doReadDecimalArray(in);
+
+                break;
+
+            case STRING_ARR:
+                obj = PortableUtils.doReadStringArray(in);
+
+                break;
+
+            case UUID_ARR:
+                obj = PortableUtils.doReadUuidArray(in);
+
+                break;
+
+            case DATE_ARR:
+                obj = PortableUtils.doReadDateArray(in);
+
+                break;
+
+            case TIMESTAMP_ARR:
+                obj = PortableUtils.doReadTimestampArray(in);
+
+                break;
+
+            case OBJ_ARR:
+                obj = PortableUtils.doReadObjectArray(in, ctx, ldr, this, true);
+
+                break;
+
+            case COL:
+                obj = PortableUtils.doReadCollection(in, ctx, ldr, this, true, null);
+
+                break;
+
+            case MAP:
+                obj = PortableUtils.doReadMap(in, ctx, ldr, this, true, null);
+
+                break;
+
+            case PORTABLE_OBJ:
+                obj = PortableUtils.doReadPortableObject(in, ctx);
+
+                ((BinaryObjectImpl)obj).context(ctx);
+
+                if (!GridPortableMarshaller.KEEP_PORTABLES.get())
+                    obj = ((BinaryObject)obj).deserialize();
+
+                break;
+
+            case ENUM:
+                obj = PortableUtils.doReadEnum(in, PortableUtils.doReadClass(in, ctx, ldr));
+
+                break;
+
+            case ENUM_ARR:
+                obj = PortableUtils.doReadEnumArray(in, ctx, ldr, PortableUtils.doReadClass(in, ctx, ldr));
+
+                break;
+
+            case CLASS:
+                obj = PortableUtils.doReadClass(in, ctx, ldr);
+
+                break;
+
+            case OPTM_MARSH:
+                obj = PortableUtils.doReadOptimized(in, ctx, ldr);
+
+                break;
+
+            default:
+                throw new BinaryObjectException("Invalid flag value: " + flag);
+        }
+
+        return obj;
+    }
+
+    /**
+     * @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).deserialize();
+    }
+
+    /**
+     * @param name Field name.
+     * @return Field offset.
+     */
+    private int fieldId(String name) {
+        assert name != null;
+
+        return idMapper.fieldId(typeId, name);
+    }
+
+    /**
+     * Get or create object schema.
+     *
+     * @return Schema.
+     */
+    public PortableSchema getOrCreateSchema() {
+        PortableSchema schema = ctx.schemaRegistry(typeId).schema(schemaId);
+
+        if (schema == null) {
+            if (fieldIdLen != PortableUtils.FIELD_ID_LEN) {
+                BinaryTypeImpl type = (BinaryTypeImpl)ctx.metadata(typeId);
+
+                if (type == null || type.metadata() == null)
+                    throw new BinaryObjectException("Cannot find metadata for object with compact footer: " +
+                        typeId);
+
+                for (PortableSchema typeSchema : type.metadata().schemas()) {
+                    if (schemaId == typeSchema.schemaId()) {
+                        schema = typeSchema;
+
+                        break;
+                    }
+                }
+
+                if (schema == null)
+                    throw new BinaryObjectException("Cannot find schema for object with compact footer [" +
+                        "typeId=" + typeId + ", schemaId=" + schemaId + ']');
+            }
+            else
+                schema = createSchema();
+
+            assert schema != null;
+
+            ctx.schemaRegistry(typeId).addSchema(schemaId, schema);
+        }
+
+        return schema;
+    }
+
+    /**
+     * Create schema.
+     *
+     * @return Schema.
+     */
+    private PortableSchema createSchema() {
+        assert fieldIdLen == PortableUtils.FIELD_ID_LEN;
+
+        PortableSchema.Builder builder = PortableSchema.Builder.newBuilder();
+
+        int searchPos = footerStart;
+        int searchEnd = searchPos + footerLen;
+
+        while (searchPos < searchEnd) {
+            int fieldId = in.readIntPositioned(searchPos);
+
+            builder.addField(fieldId);
+
+            searchPos += PortableUtils.FIELD_ID_LEN + fieldOffsetLen;
+        }
+
+        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++;
+
+                PortableSchema.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 == PortableSchema.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 != PortableSchema.ORDER_NOT_FOUND) {
+            int offsetPos = footerStart + order * (fieldIdLen + fieldOffsetLen) + fieldIdLen;
+
+            int pos = start + PortableUtils.fieldOffsetRelative(in, offsetPos, fieldOffsetLen);
+
+            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 == PortableUtils.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 + PortableUtils.fieldOffsetRelative(in, searchPos + PortableUtils.FIELD_ID_LEN,
+                    fieldOffsetLen);
+
+                streamPosition(pos);
+
+                return true;
+            }
+
+            searchPos += PortableUtils.FIELD_ID_LEN + fieldOffsetLen;
+        }
+    }
+
+    /**
+     * 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.
+    }
+
+    /**
+     * Flag.
+     */
+    private static enum Flag {
+        /** Regular. */
+        NORMAL,
+
+        /** Handle. */
+        HANDLE,
+
+        /** Null. */
+        NULL
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandles.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandles.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandles.java
new file mode 100644
index 0000000..fddb8aa
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandles.java
@@ -0,0 +1,108 @@
+/*
+ * 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 org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Reader handles.
+ */
+public class BinaryReaderHandles {
+    /** Mode: empty. */
+    private static final int MODE_EMPTY = 0;
+
+    /** Mode: single object. */
+    private static final int MODE_SINGLE = 1;
+
+    /** Mode: multiple objects. */
+    private static final int MODE_MULTIPLE = 2;
+
+    /** Position.  */
+    private int singlePos;
+
+    /** Data. This is either an object or a map. */
+    private Object data;
+
+    /** Mode. */
+    private int mode = MODE_EMPTY;
+
+    /**
+     * Get object by position.
+     *
+     * @param pos Position.
+     * @return Object.
+     */
+    @SuppressWarnings("unchecked")
+    public @Nullable <T> T get(int pos) {
+        switch (mode) {
+            case MODE_EMPTY:
+                return null;
+
+            case MODE_SINGLE:
+                return (T)data;
+
+            default:
+                assert mode == MODE_MULTIPLE;
+
+                return (T)((Map<Integer, Object>)data).get(pos);
+        }
+    }
+
+    /**
+     * Put object to registry and return previous position (if any).
+     *
+     * @param pos Position.
+     * @param obj Object.
+     */
+    @SuppressWarnings("unchecked")
+    public void put(int pos, Object obj) {
+        assert pos >= 0;
+        assert obj != null;
+
+        switch (mode) {
+            case MODE_EMPTY:
+                this.singlePos = pos;
+                this.data = obj;
+                this.mode = MODE_SINGLE;
+
+                break;
+
+            case MODE_SINGLE:
+                Map<Integer, Object> newData = new HashMap(3, 1.0f);
+
+                newData.put(singlePos, data);
+                newData.put(pos, obj);
+
+                this.singlePos = -1;
+                this.data = newData;
+                this.mode = MODE_MULTIPLE;
+
+                break;
+
+            default:
+                assert mode == MODE_MULTIPLE;
+
+                Map<Integer, Object> data0 = (Map<Integer, Object>)data;
+
+                data0.put(pos, obj);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolder.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolder.java
new file mode 100644
index 0000000..48c9e8e
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolder.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * Holder for handles.
+ */
+public interface BinaryReaderHandlesHolder {
+    /**
+     * Set handle.
+     *
+     * @param obj Object.
+     * @param pos Position.
+     */
+    public void setHandle(Object obj, int pos);
+
+    /**
+     * Get handle.
+     *
+     * @param pos Position.
+     * @return Handle.
+     */
+    public Object getHandle(int pos);
+
+    /**
+     * Get all handles.
+     *
+     * @return Handles.
+     */
+    public BinaryReaderHandles handles();
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolderImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolderImpl.java
new file mode 100644
index 0000000..83b34a9
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryReaderHandlesHolderImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * Simple holder for handles.
+ */
+public class BinaryReaderHandlesHolderImpl implements BinaryReaderHandlesHolder  {
+    /** Handles. */
+    private BinaryReaderHandles hnds;
+
+    /** {@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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryThreadLocalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryThreadLocalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryThreadLocalContext.java
new file mode 100644
index 0000000..8fff80b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryThreadLocalContext.java
@@ -0,0 +1,70 @@
+/*
+ * 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 org.apache.ignite.internal.binary.streams.PortableMemoryAllocatorChunk;
+import org.apache.ignite.internal.binary.streams.PortableMemoryAllocator;
+import org.apache.ignite.internal.binary.streams.PortableMemoryAllocatorChunk;
+
+/**
+ * Contains thread-local data for binary marshalling.
+ */
+public class BinaryThreadLocalContext {
+    /** Thread-local instance. */
+    private static final ThreadLocal<BinaryThreadLocalContext> CTX = new ThreadLocal<BinaryThreadLocalContext>() {
+        @Override protected BinaryThreadLocalContext initialValue() {
+            return new BinaryThreadLocalContext();
+        }
+    };
+
+    /** Memory chunk. */
+    private final PortableMemoryAllocatorChunk chunk = PortableMemoryAllocator.INSTANCE.chunk();
+
+    /** Schema holder. */
+    private final BinaryWriterSchemaHolder schema = new BinaryWriterSchemaHolder();
+
+    /**
+     * Get current context.
+     *
+     * @return Context.
+     */
+    public static BinaryThreadLocalContext get() {
+        return CTX.get();
+    }
+
+    /**
+     * Private constructor.
+     */
+    private BinaryThreadLocalContext() {
+        // No-op.
+    }
+
+    /**
+     * @return Memory chunk.
+     */
+    public PortableMemoryAllocatorChunk chunk() {
+        return chunk;
+    }
+
+    /**
+     * @return Schema holder.
+     */
+    public BinaryWriterSchemaHolder schemaHolder() {
+        return schema;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java
new file mode 100644
index 0000000..d19076b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryTypeImpl.java
@@ -0,0 +1,93 @@
+/*
+ * 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 org.apache.ignite.binary.BinaryType;
+
+import java.util.Collection;
+
+/**
+ * Binary type implementation.
+ */
+public class BinaryTypeImpl implements BinaryType {
+    /** Portable context. */
+    private final PortableContext ctx;
+
+    /** Type metadata. */
+    private final BinaryMetadata meta;
+
+    /**
+     * Constructor.
+     *
+     * @param ctx Portable context.
+     * @param meta Type  metadata.
+     */
+    public BinaryTypeImpl(PortableContext ctx, BinaryMetadata meta) {
+        this.ctx = ctx;
+        this.meta = meta;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String typeName() {
+        return meta.typeName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int typeId() {
+        return meta.typeId();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<String> fieldNames() {
+        return meta.fields();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String fieldTypeName(String fieldName) {
+        return meta.fieldTypeName(fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public BinaryFieldImpl field(String fieldName) {
+        return ctx.createField(meta.typeId(), fieldName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String affinityKeyFieldName() {
+        return meta.affinityKeyFieldName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isEnum() {
+        return meta.isEnum();
+    }
+
+    /**
+     * @return Context.
+     */
+    public PortableContext context() {
+        return ctx;
+    }
+
+    /**
+     * @return Metadata.
+     */
+    public BinaryMetadata metadata() {
+        return meta;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/1dbf20e0/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriteMode.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriteMode.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriteMode.java
new file mode 100644
index 0000000..a20b5ed
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryWriteMode.java
@@ -0,0 +1,178 @@
+/*
+ * 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;
+
+/**
+ * Various write modes for binary objects.
+ */
+public enum BinaryWriteMode {
+    /** Primitive byte. */
+    P_BYTE(GridPortableMarshaller.BYTE),
+
+    /** Primitive boolean. */
+    P_BOOLEAN(GridPortableMarshaller.BOOLEAN),
+
+    /** Primitive short. */
+    P_SHORT(GridPortableMarshaller.SHORT),
+
+    /** Primitive char. */
+    P_CHAR(GridPortableMarshaller.CHAR),
+
+    /** Primitive int. */
+    P_INT(GridPortableMarshaller.INT),
+
+    /** Primitive long. */
+    P_LONG(GridPortableMarshaller.LONG),
+
+    /** Primitive float. */
+    P_FLOAT(GridPortableMarshaller.FLOAT),
+
+    /** Primitive int. */
+    P_DOUBLE(GridPortableMarshaller.DOUBLE),
+
+    /** */
+    BYTE(GridPortableMarshaller.BYTE),
+
+    /** */
+    SHORT(GridPortableMarshaller.SHORT),
+
+    /** */
+    INT(GridPortableMarshaller.INT),
+
+    /** */
+    LONG(GridPortableMarshaller.LONG),
+
+    /** */
+    FLOAT(GridPortableMarshaller.FLOAT),
+
+    /** */
+    DOUBLE(GridPortableMarshaller.DOUBLE),
+
+    /** */
+    CHAR(GridPortableMarshaller.CHAR),
+
+    /** */
+    BOOLEAN(GridPortableMarshaller.BOOLEAN),
+
+    /** */
+    DECIMAL(GridPortableMarshaller.DECIMAL),
+
+    /** */
+    STRING(GridPortableMarshaller.STRING),
+
+    /** */
+    UUID(GridPortableMarshaller.UUID),
+
+    /** */
+    DATE(GridPortableMarshaller.DATE),
+
+    /** */
+    TIMESTAMP(GridPortableMarshaller.TIMESTAMP),
+
+    /** */
+    BYTE_ARR(GridPortableMarshaller.BYTE_ARR),
+
+    /** */
+    SHORT_ARR(GridPortableMarshaller.SHORT_ARR),
+
+    /** */
+    INT_ARR(GridPortableMarshaller.INT_ARR),
+
+    /** */
+    LONG_ARR(GridPortableMarshaller.LONG_ARR),
+
+    /** */
+    FLOAT_ARR(GridPortableMarshaller.FLOAT_ARR),
+
+    /** */
+    DOUBLE_ARR(GridPortableMarshaller.DOUBLE_ARR),
+
+    /** */
+    CHAR_ARR(GridPortableMarshaller.CHAR_ARR),
+
+    /** */
+    BOOLEAN_ARR(GridPortableMarshaller.BOOLEAN_ARR),
+
+    /** */
+    DECIMAL_ARR(GridPortableMarshaller.DECIMAL_ARR),
+
+    /** */
+    STRING_ARR(GridPortableMarshaller.STRING_ARR),
+
+    /** */
+    UUID_ARR(GridPortableMarshaller.UUID_ARR),
+
+    /** */
+    DATE_ARR(GridPortableMarshaller.DATE_ARR),
+
+    /** */
+    TIMESTAMP_ARR(GridPortableMarshaller.TIMESTAMP_ARR),
+
+    /** */
+    OBJECT_ARR(GridPortableMarshaller.OBJ_ARR),
+
+    /** */
+    COL(GridPortableMarshaller.COL),
+
+    /** */
+    MAP(GridPortableMarshaller.MAP),
+
+    /** */
+    PORTABLE_OBJ(GridPortableMarshaller.OBJ),
+
+    /** */
+    ENUM(GridPortableMarshaller.ENUM),
+
+    /** Portable enum. */
+    PORTABLE_ENUM(GridPortableMarshaller.ENUM),
+
+    /** */
+    ENUM_ARR(GridPortableMarshaller.ENUM_ARR),
+
+    /** */
+    CLASS(GridPortableMarshaller.CLASS),
+
+    /** */
+    PORTABLE(GridPortableMarshaller.PORTABLE_OBJ),
+
+    /** */
+    EXTERNALIZABLE(GridPortableMarshaller.OBJ),
+
+    /** */
+    OBJECT(GridPortableMarshaller.OBJ),
+
+    /** */
+    EXCLUSION(GridPortableMarshaller.OBJ);
+
+    /** Type ID. */
+    private final int typeId;
+
+    /**
+     * @param typeId Type ID.
+     */
+    private BinaryWriteMode(int typeId) {
+        this.typeId = typeId;
+    }
+
+    /**
+     * @return Type ID.
+     */
+    public int typeId() {
+        return typeId;
+    }
+}