http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java
----------------------------------------------------------------------
diff --cc 
modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java
index de2b810,0000000..5421bea
mode 100644,000000..100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/IgniteObjectWriterExImpl.java
@@@ -1,1892 -1,0 +1,1855 @@@
 +/*
 + * 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.portable;
 +
 +import org.apache.ignite.IgniteCheckedException;
++import org.apache.ignite.igniteobject.IgniteObjectIdMapper;
 +import org.apache.ignite.internal.portable.streams.PortableHeapOutputStream;
 +import org.apache.ignite.internal.portable.streams.PortableOutputStream;
 +import org.apache.ignite.internal.util.typedef.internal.A;
 +import org.apache.ignite.igniteobject.IgniteObjectException;
 +import org.apache.ignite.igniteobject.IgniteObjectRawWriter;
 +import org.apache.ignite.igniteobject.IgniteObjectWriter;
 +import org.jetbrains.annotations.Nullable;
 +
 +import java.io.IOException;
 +import java.io.ObjectOutput;
 +import java.lang.reflect.InvocationTargetException;
 +import java.math.BigDecimal;
 +import java.math.BigInteger;
 +import java.sql.Timestamp;
 +import java.util.Collection;
 +import java.util.Date;
 +import java.util.IdentityHashMap;
 +import java.util.Map;
 +import java.util.UUID;
 +
 +import static java.nio.charset.StandardCharsets.UTF_8;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.BOOLEAN_ARR;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.BYTE_ARR;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.CHAR_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.CLASS;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.COL;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.DATE;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.DATE_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.DECIMAL;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.DECIMAL_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.DOUBLE_ARR;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.ENUM;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.ENUM_ARR;
++import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.FLAGS_POS;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.FLOAT_ARR;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.INT;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.INT_ARR;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.LONG;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.LONG_ARR;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.MAP;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.MAP_ENTRY;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.NULL;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.OBJ_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.OPTM_MARSH;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.PORTABLE_OBJ;
- import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.RAW_DATA_OFF_POS;
++import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.SCHEMA_ID_POS;
++import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.SHORT_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.STRING;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.STRING_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.TIMESTAMP;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.TIMESTAMP_ARR;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.TOTAL_LEN_POS;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.UNREGISTERED_TYPE_ID;
 +import static org.apache.ignite.internal.portable.GridPortableMarshaller.UUID;
 +import static 
org.apache.ignite.internal.portable.GridPortableMarshaller.UUID_ARR;
 +
-  /**
++/**
 + * Portable writer implementation.
 + */
 +public class IgniteObjectWriterExImpl implements IgniteObjectWriter, 
IgniteObjectRawWriterEx, ObjectOutput {
 +    /** Length: integer. */
 +    private static final int LEN_INT = 4;
 +
 +    /** */
 +    private static final int INIT_CAP = 1024;
 +
-     /** */
-     private final PortableContext ctx;
++    /** FNV1 hash offset basis. */
++    private static final int FNV1_OFFSET_BASIS = 0x811C9DC5;
 +
-     /** */
-     private final WriterContext wCtx;
++    /** FNV1 hash prime. */
++    private static final int FNV1_PRIME = 0x01000193;
++
++    /** Thread-local schema. */
++    private static final ThreadLocal<SchemaHolder> SCHEMA = new 
ThreadLocal<>();
 +
 +    /** */
-     private final int start;
++    private final PortableContext ctx;
 +
 +    /** */
-     private int mark;
++    private final int start;
 +
 +    /** */
 +    private Class<?> cls;
 +
 +    /** */
 +    private int typeId;
 +
-     /** */
-     private boolean allowFields = true;
++    /** Raw offset position. */
++    private int rawOffPos;
 +
 +    /** */
 +    private boolean metaEnabled;
 +
 +    /** */
 +    private int metaHashSum;
 +
-     /**
-      * @param ctx Context.
-      * @param off Start offset.
-      */
-     IgniteObjectWriterExImpl(PortableContext ctx, int off) {
-         this.ctx = ctx;
++    /** Handles. */
++    private Map<Object, Integer> handles;
 +
-         PortableOutputStream out = new PortableHeapOutputStream(off + 
INIT_CAP);
++    /** Output stream. */
++    private PortableOutputStream out;
 +
-         out.position(off);
++    /** Schema. */
++    private SchemaHolder schema;
 +
-         wCtx = new WriterContext(out, null);
++    /** Schema ID. */
++    private int schemaId;
 +
-         start = off;
-     }
++    /** Amount of written fields. */
++    private int fieldCnt;
++
++    /** ID mapper. */
++    private IgniteObjectIdMapper idMapper;
 +
 +    /**
 +     * @param ctx Context.
-      * @param out Output stream.
-      * @param off Start offset.
 +     */
-     IgniteObjectWriterExImpl(PortableContext ctx, PortableOutputStream out, 
int off) {
-         this.ctx = ctx;
- 
-         wCtx = new WriterContext(out, null);
- 
-         start = off;
++    IgniteObjectWriterExImpl(PortableContext ctx) {
++        this(ctx, new PortableHeapOutputStream(INIT_CAP));
 +    }
 +
 +    /**
 +     * @param ctx Context.
-      * @param off Start offset.
-      * @param typeId Type ID.
++     * @param out Output stream.
 +     */
-     public IgniteObjectWriterExImpl(PortableContext ctx, int off, int typeId, 
boolean metaEnabled) {
-         this(ctx, off);
++    IgniteObjectWriterExImpl(PortableContext ctx, PortableOutputStream out) {
++        this(ctx, out, new IdentityHashMap<Object, Integer>());
++    }
 +
-         this.typeId = typeId;
++     /**
++      * @param ctx Context.
++      * @param out Output stream.
++      * @param handles Handles.
++      */
++     private IgniteObjectWriterExImpl(PortableContext ctx, 
PortableOutputStream out, Map<Object, Integer> handles) {
++         this.ctx = ctx;
++         this.out = out;
++         this.handles = handles;
 +
-         this.metaEnabled = metaEnabled;
-     }
++         start = out.position();
++     }
 +
 +    /**
 +     * @param ctx Context.
-      * @param wCtx Writer context.
++     * @param typeId Type ID.
 +     */
-     private IgniteObjectWriterExImpl(PortableContext ctx, WriterContext wCtx) 
{
-         this.ctx = ctx;
-         this.wCtx = wCtx;
++    public IgniteObjectWriterExImpl(PortableContext ctx, int typeId, boolean 
metaEnabled) {
++        this(ctx);
 +
-         start = wCtx.out.position();
++        this.typeId = typeId;
++        this.metaEnabled = metaEnabled;
 +    }
 +
 +    /**
 +     * Close the writer releasing resources if necessary.
 +     */
 +    @Override public void close() {
-         wCtx.out.close();
++        out.close();
 +    }
 +
 +    /**
 +     * @return Meta data hash sum or {@code null} if meta data is disabled.
 +     */
 +    @Nullable Integer metaDataHashSum() {
 +        return metaEnabled ? metaHashSum : null;
 +    }
 +
 +    /**
 +     * @param obj Object.
-      * @param detached Detached or not.
-      * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
++     * @throws IgniteObjectException In case of error.
++     */
++    void marshal(Object obj) throws IgniteObjectException {
++        marshal(obj, true);
++    }
++
++    /**
++     * @param obj Object.
++     * @param enableReplace Object replacing enabled flag.
++     * @throws IgniteObjectException In case of error.
 +     */
-     void marshal(Object obj, boolean detached) throws IgniteObjectException {
++    void marshal(Object obj, boolean enableReplace) throws 
IgniteObjectException {
 +        assert obj != null;
 +
 +        cls = obj.getClass();
 +
 +        PortableClassDescriptor desc = ctx.descriptorForClass(cls);
 +
 +        if (desc == null)
 +            throw new IgniteObjectException("Object is not portable: [class=" 
+ cls + ']');
 +
 +        if (desc.excluded()) {
 +            doWriteByte(NULL);
 +            return;
 +        }
 +
 +        if (desc.useOptimizedMarshaller()) {
 +            writeByte(OPTM_MARSH);
 +
 +            try {
 +                byte[] arr = ctx.optimizedMarsh().marshal(obj);
 +
 +                writeInt(arr.length);
 +
 +                write(arr);
 +            }
 +            catch (IgniteCheckedException e) {
 +                throw new IgniteObjectException("Failed to marshal object 
with optimized marshaller: " + obj, e);
 +            }
 +
 +            return;
 +        }
 +
-         if (desc.getWriteReplaceMethod() != null) {
-             Object replace;
++        if (enableReplace && desc.getWriteReplaceMethod() != null) {
++            Object replacedObj;
 +
 +            try {
-                 replace = desc.getWriteReplaceMethod().invoke(obj);
++                replacedObj = desc.getWriteReplaceMethod().invoke(obj);
 +            }
 +            catch (IllegalAccessException e) {
 +                throw new RuntimeException(e);
 +            }
 +            catch (InvocationTargetException e) {
 +                if (e.getTargetException() instanceof IgniteObjectException)
 +                    throw (IgniteObjectException)e.getTargetException();
 +
 +                throw new IgniteObjectException("Failed to execute 
writeReplace() method on " + obj, e);
 +            }
 +
-             if (replace == null) {
++            if (replacedObj == null) {
 +                doWriteByte(NULL);
 +                return;
 +            }
 +
-             if (cls != replace.getClass()) {
-                 cls = replace.getClass();
- 
-                 desc = ctx.descriptorForClass(cls);
- 
-                 if (desc == null)
-                     throw new IgniteObjectException("Object is not portable: 
[class=" + cls + ']');
-             }
++            marshal(replacedObj, false);
 +
-             obj = replace;
++            return;
 +        }
 +
 +        typeId = desc.typeId();
 +
 +        metaEnabled = ctx.isMetaDataEnabled(typeId);
 +
-         if (detached)
-             wCtx.resetHandles();
- 
 +        desc.write(obj, this);
 +    }
 +
 +    /**
 +     * @param obj Object.
 +     * @return Handle.
 +     */
 +    int handle(Object obj) {
 +        assert obj != null;
 +
-         return wCtx.handle(obj);
++        Integer h = handles.get(obj);
++
++        if (h != null)
++            return out.position() - h;
++        else {
++            handles.put(obj, out.position());
++
++            return -1;
++        }
 +    }
 +
 +    /**
 +     * @return Array.
 +     */
 +    public byte[] array() {
-         return wCtx.out.arrayCopy();
-     }
- 
-     /**
-      * @return Output stream.
-      */
-     public PortableOutputStream outputStream() {
-         return wCtx.out;
++        return out.arrayCopy();
 +    }
 +
 +    /**
 +     * @return Stream current position.
 +     */
 +    int position() {
-         return wCtx.out.position();
++        return out.position();
 +    }
 +
 +    /**
 +     * Sets new position.
 +     *
 +     * @param pos Position.
 +     */
 +    void position(int pos) {
-         wCtx.out.position(pos);
++        out.position(pos);
 +    }
 +
-      /**
++    /**
 +     * @param bytes Number of bytes to reserve.
 +     * @return Offset.
 +     */
 +    public int reserve(int bytes) {
-         int pos = wCtx.out.position();
++        int pos = out.position();
 +
-         wCtx.out.position(pos + bytes);
++        out.position(pos + bytes);
 +
 +        return pos;
 +    }
 +
 +    /**
-      * @param bytes Number of bytes to reserve.
-      * @return Offset.
++     * Perform post-write activity. This includes:
++     * - writing object length;
++     * - writing schema offset;
++     * - writing schema to the tail.
++     *
++     * @param userType User type flag.
 +     */
-     public int reserveAndMark(int bytes) {
-         int off0 = reserve(bytes);
++    public void postWrite(boolean userType) {
++        if (schema != null) {
++            // Write schema ID.
++            out.writeInt(start + SCHEMA_ID_POS, schemaId);
 +
-         mark = wCtx.out.position();
++            // Write schema offset.
++            out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - 
start);
 +
-         return off0;
-     }
++            // Write the schema.
++            schema.writeAndPop(this, fieldCnt);
 +
-     /**
-      * @param off Offset.
-      */
-     public void writeDelta(int off) {
-         wCtx.out.writeInt(off, wCtx.out.position() - mark);
-     }
++            // Write raw offset if needed.
++            if (rawOffPos != 0)
++                out.writeInt(rawOffPos - start);
++        }
++        else {
++            // Write raw-only flag is needed.
++            int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | 
PortableUtils.FLAG_RAW_ONLY;
 +
-     /**
-      *
-      */
-     public void writeLength() {
-         wCtx.out.writeInt(start + TOTAL_LEN_POS, wCtx.out.position() - start);
-     }
++            out.writeShort(start + FLAGS_POS, (short)flags);
 +
-     /**
-      *
-      */
-     public void writeRawOffsetIfNeeded() {
-         if (allowFields)
-             wCtx.out.writeInt(start + RAW_DATA_OFF_POS, wCtx.out.position() - 
start);
++            // If there are no schema, we are free to write raw offset to 
schema offset.
++            out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, (rawOffPos == 0 ? 
out.position() : rawOffPos) - start);
++        }
++
++        // 5. Write length.
++        out.writeInt(start + TOTAL_LEN_POS, out.position() - start);
 +    }
 +
 +    /**
 +     * @param val Byte array.
 +     */
 +    public void write(byte[] val) {
 +        assert val != null;
 +
-         wCtx.out.writeByteArray(val);
++        out.writeByteArray(val);
 +    }
 +
 +    /**
 +     * @param val Byte array.
 +     * @param off Offset.
 +     * @param len Length.
 +     */
 +    public void write(byte[] val, int off, int len) {
 +        assert val != null;
 +
-         wCtx.out.write(val, off, len);
++        out.write(val, off, len);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteByte(byte val) {
-         wCtx.out.writeByte(val);
++        out.writeByte(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteShort(short val) {
-         wCtx.out.writeShort(val);
++        out.writeShort(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteInt(int val) {
-         wCtx.out.writeInt(val);
++        out.writeInt(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteLong(long val) {
-         wCtx.out.writeLong(val);
++        out.writeLong(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteFloat(float val) {
-         wCtx.out.writeFloat(val);
++        out.writeFloat(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteDouble(double val) {
-         wCtx.out.writeDouble(val);
++        out.writeDouble(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteChar(char val) {
-         wCtx.out.writeChar(val);
++        out.writeChar(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    public void doWriteBoolean(boolean val) {
-         wCtx.out.writeBoolean(val);
++        out.writeBoolean(val);
 +    }
 +
 +    /**
 +     * @param val String value.
 +     */
 +    public void doWriteDecimal(@Nullable BigDecimal val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(DECIMAL);
 +
 +            BigInteger intVal = val.unscaledValue();
 +
 +            if (intVal.signum() == -1) {
 +                intVal = intVal.negate();
 +
-                 wCtx.out.writeInt(val.scale() | 0x80000000);
++                out.writeInt(val.scale() | 0x80000000);
 +            }
 +            else
-                 wCtx.out.writeInt(val.scale());
++                out.writeInt(val.scale());
 +
 +            byte[] vals = intVal.toByteArray();
 +
-             wCtx.out.writeInt(vals.length);
-             wCtx.out.writeByteArray(vals);
++            out.writeInt(vals.length);
++            out.writeByteArray(vals);
 +        }
 +    }
 +
 +    /**
 +     * @param val String value.
 +     */
 +    public void doWriteString(@Nullable String val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(STRING);
 +
 +            if (ctx.isConvertString()) {
 +                doWriteBoolean(true);
 +
 +                byte[] strArr = val.getBytes(UTF_8);
 +
 +                doWriteInt(strArr.length);
 +
-                 wCtx.out.writeByteArray(strArr);
++                out.writeByteArray(strArr);
 +            }
 +            else {
 +                doWriteBoolean(false);
 +
 +                char[] strArr = val.toCharArray();
 +
 +                doWriteInt(strArr.length);
 +
-                 wCtx.out.writeCharArray(strArr);
++                out.writeCharArray(strArr);
 +            }
 +        }
 +    }
 +
 +    /**
 +     * @param uuid UUID.
 +     */
 +    public void doWriteUuid(@Nullable UUID uuid) {
 +        if (uuid == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(UUID);
 +            doWriteLong(uuid.getMostSignificantBits());
 +            doWriteLong(uuid.getLeastSignificantBits());
 +        }
 +    }
 +
 +    /**
 +     * @param date Date.
 +     */
 +    public void doWriteDate(@Nullable Date date) {
 +        if (date == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(DATE);
 +            doWriteLong(date.getTime());
 +        }
 +    }
 +
-      /**
-       * @param ts Timestamp.
-       */
-      public void doWriteTimestamp(@Nullable Timestamp ts) {
-          if (ts== null)
-              doWriteByte(NULL);
-          else {
-              doWriteByte(TIMESTAMP);
-              doWriteLong(ts.getTime());
-              doWriteInt(ts.getNanos() % 1000000);
-          }
-      }
++    /**
++     * @param ts Timestamp.
++     */
++    public void doWriteTimestamp(@Nullable Timestamp ts) {
++        if (ts== null)
++            doWriteByte(NULL);
++        else {
++            doWriteByte(TIMESTAMP);
++            doWriteLong(ts.getTime());
++            doWriteInt(ts.getNanos() % 1000000);
++        }
++    }
 +
 +    /**
++     * Write object.
++     *
 +     * @param obj Object.
-      * @param detached Detached or not.
-      * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
++     * @throws IgniteObjectException In case of error.
 +     */
-     public void doWriteObject(@Nullable Object obj, boolean detached) throws 
IgniteObjectException {
++    public void doWriteObject(@Nullable Object obj) throws 
IgniteObjectException {
 +        if (obj == null)
 +            doWriteByte(NULL);
 +        else {
-             WriterContext wCtx = detached ? new WriterContext(this.wCtx.out, 
this.wCtx.handles) : this.wCtx;
- 
-             IgniteObjectWriterExImpl writer = new 
IgniteObjectWriterExImpl(ctx, wCtx);
- 
-             writer.marshal(obj, detached);
++            IgniteObjectWriterExImpl writer = new 
IgniteObjectWriterExImpl(ctx, out, handles);
 +
-             if (detached)
-                 this.wCtx.out = wCtx.out;
++            writer.marshal(obj);
 +        }
 +    }
 +
 +    /**
 +     * @param val Byte array.
 +     */
 +    void doWriteByteArray(@Nullable byte[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(BYTE_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeByteArray(val);
++            out.writeByteArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Short array.
 +     */
 +    void doWriteShortArray(@Nullable short[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(SHORT_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeShortArray(val);
++            out.writeShortArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Integer array.
 +     */
 +    void doWriteIntArray(@Nullable int[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(INT_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeIntArray(val);
++            out.writeIntArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Long array.
 +     */
 +    void doWriteLongArray(@Nullable long[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(LONG_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeLongArray(val);
++            out.writeLongArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Float array.
 +     */
 +    void doWriteFloatArray(@Nullable float[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(FLOAT_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeFloatArray(val);
++            out.writeFloatArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Double array.
 +     */
 +    void doWriteDoubleArray(@Nullable double[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(DOUBLE_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeDoubleArray(val);
++            out.writeDoubleArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Char array.
 +     */
 +    void doWriteCharArray(@Nullable char[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(CHAR_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeCharArray(val);
++            out.writeCharArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Boolean array.
 +     */
 +    void doWriteBooleanArray(@Nullable boolean[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(BOOLEAN_ARR);
 +            doWriteInt(val.length);
 +
-             wCtx.out.writeBooleanArray(val);
++            out.writeBooleanArray(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Array of strings.
 +     */
 +    void doWriteDecimalArray(@Nullable BigDecimal[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(DECIMAL_ARR);
 +            doWriteInt(val.length);
 +
 +            for (BigDecimal str : val)
 +                doWriteDecimal(str);
 +        }
 +    }
 +
 +    /**
 +     * @param val Array of strings.
 +     */
 +    void doWriteStringArray(@Nullable String[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(STRING_ARR);
 +            doWriteInt(val.length);
 +
 +            for (String str : val)
 +                doWriteString(str);
 +        }
 +    }
 +
 +    /**
 +     * @param val Array of UUIDs.
 +     */
 +    void doWriteUuidArray(@Nullable UUID[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(UUID_ARR);
 +            doWriteInt(val.length);
 +
 +            for (UUID uuid : val)
 +                doWriteUuid(uuid);
 +        }
 +    }
 +
 +    /**
 +     * @param val Array of dates.
 +     */
 +    void doWriteDateArray(@Nullable Date[] val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            doWriteByte(DATE_ARR);
 +            doWriteInt(val.length);
 +
 +            for (Date date : val)
 +                doWriteDate(date);
 +        }
 +    }
 +
 +     /**
 +      * @param val Array of timestamps.
 +      */
 +     void doWriteTimestampArray(@Nullable Timestamp[] val) {
 +         if (val == null)
 +             doWriteByte(NULL);
 +         else {
 +             if (tryWriteAsHandle(val))
 +                 return;
 +
 +             doWriteByte(TIMESTAMP_ARR);
 +             doWriteInt(val.length);
 +
 +             for (Timestamp ts : val)
 +                 doWriteTimestamp(ts);
 +         }
 +     }
 +
 +    /**
 +     * @param val Array of objects.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void doWriteObjectArray(@Nullable Object[] val) throws 
IgniteObjectException {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(val))
 +                return;
 +
 +            PortableClassDescriptor desc = 
ctx.descriptorForClass(val.getClass().getComponentType());
 +
 +            doWriteByte(OBJ_ARR);
 +
 +            if (desc.registered())
 +                doWriteInt(desc.typeId());
 +            else {
 +                doWriteInt(UNREGISTERED_TYPE_ID);
 +                doWriteString(val.getClass().getComponentType().getName());
 +            }
 +
 +            doWriteInt(val.length);
 +
 +            for (Object obj : val)
-                 doWriteObject(obj, false);
++                doWriteObject(obj);
 +        }
 +    }
 +
 +    /**
 +     * @param col Collection.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void doWriteCollection(@Nullable Collection<?> col) throws 
IgniteObjectException {
 +        if (col == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(col))
 +                return;
 +
 +            doWriteByte(COL);
 +            doWriteInt(col.size());
 +            doWriteByte(ctx.collectionType(col.getClass()));
 +
 +            for (Object obj : col)
-                 doWriteObject(obj, false);
++                doWriteObject(obj);
 +        }
 +    }
 +
 +    /**
 +     * @param map Map.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void doWriteMap(@Nullable Map<?, ?> map) throws IgniteObjectException {
 +        if (map == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(map))
 +                return;
 +
 +            doWriteByte(MAP);
 +            doWriteInt(map.size());
 +            doWriteByte(ctx.mapType(map.getClass()));
 +
 +            for (Map.Entry<?, ?> e : map.entrySet()) {
-                 doWriteObject(e.getKey(), false);
-                 doWriteObject(e.getValue(), false);
++                doWriteObject(e.getKey());
++                doWriteObject(e.getValue());
 +            }
 +        }
 +    }
 +
 +    /**
 +     * @param e Map entry.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void doWriteMapEntry(@Nullable Map.Entry<?, ?> e) throws 
IgniteObjectException {
 +        if (e == null)
 +            doWriteByte(NULL);
 +        else {
 +            if (tryWriteAsHandle(e))
 +                return;
 +
 +            doWriteByte(MAP_ENTRY);
-             doWriteObject(e.getKey(), false);
-             doWriteObject(e.getValue(), false);
++            doWriteObject(e.getKey());
++            doWriteObject(e.getValue());
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void doWriteEnum(@Nullable Enum<?> val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            PortableClassDescriptor desc = 
ctx.descriptorForClass(val.getClass());
 +
 +            doWriteByte(ENUM);
 +
 +            if (desc.registered())
 +                doWriteInt(desc.typeId());
 +            else {
 +                doWriteInt(UNREGISTERED_TYPE_ID);
 +                doWriteString(val.getClass().getName());
 +            }
 +
 +            doWriteInt(val.ordinal());
 +        }
 +    }
 +
 +    /**
 +     * @param val Array.
 +     */
 +    void doWriteEnumArray(@Nullable Object[] val) {
 +        assert val == null || val.getClass().getComponentType().isEnum();
 +
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            PortableClassDescriptor desc = 
ctx.descriptorForClass(val.getClass().getComponentType());
 +            doWriteByte(ENUM_ARR);
 +
 +            if (desc.registered())
 +                doWriteInt(desc.typeId());
 +            else {
 +                doWriteInt(UNREGISTERED_TYPE_ID);
 +                doWriteString(val.getClass().getComponentType().getName());
 +            }
 +
 +            doWriteInt(val.length);
 +
 +            // TODO: Denis: Redundant data for each element of the array.
 +            for (Object o : val)
 +                doWriteEnum((Enum<?>)o);
 +        }
 +    }
 +
 +    /**
 +     * @param val Class.
 +     */
 +    void doWriteClass(@Nullable Class val) {
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            PortableClassDescriptor desc = ctx.descriptorForClass(val);
 +
 +            doWriteByte(CLASS);
 +
 +            if (desc.registered())
 +                doWriteInt(desc.typeId());
 +            else {
 +                doWriteInt(UNREGISTERED_TYPE_ID);
 +                doWriteString(val.getClass().getName());
 +            }
 +        }
 +    }
 +
 +    /**
 +     * @param po Portable object.
 +     */
 +    public void doWritePortableObject(@Nullable IgniteObjectImpl po) {
 +        if (po == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(PORTABLE_OBJ);
 +
 +            byte[] poArr = po.array();
 +
 +            doWriteInt(poArr.length);
 +
-             wCtx.out.writeByteArray(poArr);
++            out.writeByteArray(poArr);
 +
 +            doWriteInt(po.start());
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeByteField(@Nullable Byte val) {
-         doWriteInt(val != null ? 2 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(BYTE);
 +            doWriteByte(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Class.
 +     */
 +    void writeClassField(@Nullable Class val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteClass(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeShortField(@Nullable Short val) {
-         doWriteInt(val != null ? 3 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(SHORT);
 +            doWriteShort(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeIntField(@Nullable Integer val) {
-         doWriteInt(val != null ? 5 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(INT);
 +            doWriteInt(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeLongField(@Nullable Long val) {
-         doWriteInt(val != null ? 9 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(LONG);
 +            doWriteLong(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeFloatField(@Nullable Float val) {
-         doWriteInt(val != null ? 5 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(FLOAT);
 +            doWriteFloat(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeDoubleField(@Nullable Double val) {
-         doWriteInt(val != null ? 9 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(DOUBLE);
 +            doWriteDouble(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeCharField(@Nullable Character val) {
-         doWriteInt(val != null ? 3 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(CHAR);
 +            doWriteChar(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeBooleanField(@Nullable Boolean val) {
-         doWriteInt(val != null ? 2 : 1);
- 
 +        if (val == null)
 +            doWriteByte(NULL);
 +        else {
 +            doWriteByte(BOOLEAN);
 +            doWriteBoolean(val);
 +        }
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeDecimalField(@Nullable BigDecimal val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteDecimal(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeStringField(@Nullable String val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteString(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeUuidField(@Nullable UUID val) {
-         doWriteInt(val != null ? 17 : 1);
 +        doWriteUuid(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeDateField(@Nullable Date val) {
-         doWriteInt(val != null ? 9 : 1);
 +        doWriteDate(val);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeTimestampField(@Nullable Timestamp val) {
-         doWriteInt(val != null ? 13 : 1);
 +        doWriteTimestamp(val);
 +    }
 +
 +    /**
 +     * @param obj Object.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void writeObjectField(@Nullable Object obj) throws IgniteObjectException {
-         int lenPos = reserveAndMark(4);
- 
-         doWriteObject(obj, false);
- 
-         writeDelta(lenPos);
++        doWriteObject(obj);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeByteArrayField(@Nullable byte[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteByteArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeShortArrayField(@Nullable short[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteShortArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeIntArrayField(@Nullable int[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteIntArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeLongArrayField(@Nullable long[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteLongArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeFloatArrayField(@Nullable float[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteFloatArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeDoubleArrayField(@Nullable double[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteDoubleArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeCharArrayField(@Nullable char[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteCharArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeBooleanArrayField(@Nullable boolean[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteBooleanArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeDecimalArrayField(@Nullable BigDecimal[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteDecimalArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeStringArrayField(@Nullable String[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteStringArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeUuidArrayField(@Nullable UUID[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteUuidArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeDateArrayField(@Nullable Date[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteDateArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeTimestampArrayField(@Nullable Timestamp[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteTimestampArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void writeObjectArrayField(@Nullable Object[] val) throws 
IgniteObjectException {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteObjectArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param col Collection.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void writeCollectionField(@Nullable Collection<?> col) throws 
IgniteObjectException {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteCollection(col);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param map Map.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void writeMapField(@Nullable Map<?, ?> map) throws IgniteObjectException {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteMap(map);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param e Map entry.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void writeMapEntryField(@Nullable Map.Entry<?, ?> e) throws 
IgniteObjectException {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteMapEntry(e);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeEnumField(@Nullable Enum<?> val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteEnum(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param val Value.
 +     */
 +    void writeEnumArrayField(@Nullable Object[] val) {
-         int lenPos = reserveAndMark(4);
- 
 +        doWriteEnumArray(val);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /**
 +     * @param po Portable object.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException In case 
of error.
 +     */
 +    void writePortableObjectField(@Nullable IgniteObjectImpl po) throws 
IgniteObjectException {
-         int lenPos = reserveAndMark(4);
- 
 +        doWritePortableObject(po);
- 
-         writeDelta(lenPos);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeByte(String fieldName, byte val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, BYTE);
 +        writeByteField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeByte(byte val) throws IgniteObjectException {
 +        doWriteByte(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeShort(String fieldName, short val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, SHORT);
 +        writeShortField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeShort(short val) throws IgniteObjectException {
 +        doWriteShort(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeInt(String fieldName, int val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, INT);
 +        writeIntField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeInt(int val) throws IgniteObjectException {
 +        doWriteInt(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeLong(String fieldName, long val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, LONG);
 +        writeLongField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeLong(long val) throws IgniteObjectException {
 +        doWriteLong(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeFloat(String fieldName, float val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, FLOAT);
 +        writeFloatField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeFloat(float val) throws IgniteObjectException {
 +        doWriteFloat(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDouble(String fieldName, double val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, DOUBLE);
 +        writeDoubleField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDouble(double val) throws 
IgniteObjectException {
 +        doWriteDouble(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeChar(String fieldName, char val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, CHAR);
 +        writeCharField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeChar(char val) throws IgniteObjectException {
 +        doWriteChar(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeBoolean(String fieldName, boolean val) throws 
IgniteObjectException {
 +        writeFieldId(fieldName, BOOLEAN);
 +        writeBooleanField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeBoolean(boolean val) throws 
IgniteObjectException {
 +        doWriteBoolean(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDecimal(String fieldName, @Nullable BigDecimal 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, DECIMAL);
 +        writeDecimalField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDecimal(@Nullable BigDecimal val) throws 
IgniteObjectException {
 +        doWriteDecimal(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeString(String fieldName, @Nullable String val) 
throws IgniteObjectException {
 +        writeFieldId(fieldName, STRING);
 +        writeStringField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeString(@Nullable String val) throws 
IgniteObjectException {
 +        doWriteString(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeUuid(String fieldName, @Nullable UUID val) 
throws IgniteObjectException {
 +        writeFieldId(fieldName, UUID);
 +        writeUuidField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeUuid(@Nullable UUID val) throws 
IgniteObjectException {
 +        doWriteUuid(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDate(String fieldName, @Nullable Date val) 
throws IgniteObjectException {
 +        writeFieldId(fieldName, DATE);
 +        writeDateField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDate(@Nullable Date val) throws 
IgniteObjectException {
 +        doWriteDate(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeTimestamp(String fieldName, @Nullable 
Timestamp val) throws IgniteObjectException {
 +        writeFieldId(fieldName, TIMESTAMP);
 +        writeTimestampField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeTimestamp(@Nullable Timestamp val) throws 
IgniteObjectException {
 +        doWriteTimestamp(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeObject(String fieldName, @Nullable Object obj) 
throws IgniteObjectException {
 +        writeFieldId(fieldName, OBJ);
 +        writeObjectField(obj);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeObject(@Nullable Object obj) throws 
IgniteObjectException {
-         doWriteObject(obj, false);
++        doWriteObject(obj);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeObjectDetached(@Nullable Object obj) throws 
IgniteObjectException {
-         doWriteObject(obj, true);
++        if (obj == null)
++            doWriteByte(NULL);
++        else {
++            IgniteObjectWriterExImpl writer = new 
IgniteObjectWriterExImpl(ctx, out, new IdentityHashMap<Object, Integer>());
++
++            writer.marshal(obj);
++        }
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeByteArray(String fieldName, @Nullable byte[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, BYTE_ARR);
 +        writeByteArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeByteArray(@Nullable byte[] val) throws 
IgniteObjectException {
 +        doWriteByteArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeShortArray(String fieldName, @Nullable short[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, SHORT_ARR);
 +        writeShortArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeShortArray(@Nullable short[] val) throws 
IgniteObjectException {
 +        doWriteShortArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeIntArray(String fieldName, @Nullable int[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, INT_ARR);
 +        writeIntArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeIntArray(@Nullable int[] val) throws 
IgniteObjectException {
 +        doWriteIntArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeLongArray(String fieldName, @Nullable long[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, LONG_ARR);
 +        writeLongArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeLongArray(@Nullable long[] val) throws 
IgniteObjectException {
 +        doWriteLongArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeFloatArray(String fieldName, @Nullable float[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, FLOAT_ARR);
 +        writeFloatArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeFloatArray(@Nullable float[] val) throws 
IgniteObjectException {
 +        doWriteFloatArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDoubleArray(String fieldName, @Nullable 
double[] val)
 +        throws IgniteObjectException {
 +        writeFieldId(fieldName, DOUBLE_ARR);
 +        writeDoubleArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDoubleArray(@Nullable double[] val) throws 
IgniteObjectException {
 +        doWriteDoubleArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeCharArray(String fieldName, @Nullable char[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, CHAR_ARR);
 +        writeCharArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeCharArray(@Nullable char[] val) throws 
IgniteObjectException {
 +        doWriteCharArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeBooleanArray(String fieldName, @Nullable 
boolean[] val)
 +        throws IgniteObjectException {
 +        writeFieldId(fieldName, BOOLEAN_ARR);
 +        writeBooleanArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeBooleanArray(@Nullable boolean[] val) throws 
IgniteObjectException {
 +        doWriteBooleanArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDecimalArray(String fieldName, @Nullable 
BigDecimal[] val)
 +        throws IgniteObjectException {
 +        writeFieldId(fieldName, DECIMAL_ARR);
 +        writeDecimalArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDecimalArray(@Nullable BigDecimal[] val) 
throws IgniteObjectException {
 +        doWriteDecimalArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeStringArray(String fieldName, @Nullable 
String[] val)
 +        throws IgniteObjectException {
 +        writeFieldId(fieldName, STRING_ARR);
 +        writeStringArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeStringArray(@Nullable String[] val) throws 
IgniteObjectException {
 +        doWriteStringArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeUuidArray(String fieldName, @Nullable UUID[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, UUID_ARR);
 +        writeUuidArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeUuidArray(@Nullable UUID[] val) throws 
IgniteObjectException {
 +        doWriteUuidArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDateArray(String fieldName, @Nullable Date[] 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, DATE_ARR);
 +        writeDateArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeDateArray(@Nullable Date[] val) throws 
IgniteObjectException {
 +        doWriteDateArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeTimestampArray(String fieldName, @Nullable 
Timestamp[] val) throws IgniteObjectException {
 +        writeFieldId(fieldName, TIMESTAMP_ARR);
 +        writeTimestampArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeTimestampArray(@Nullable Timestamp[] val) 
throws IgniteObjectException {
 +        doWriteTimestampArray(val);
 +    }
 +
 +     /** {@inheritDoc} */
 +    @Override public void writeObjectArray(String fieldName, @Nullable 
Object[] val) throws IgniteObjectException {
 +        writeFieldId(fieldName, OBJ_ARR);
 +        writeObjectArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeObjectArray(@Nullable Object[] val) throws 
IgniteObjectException {
 +        doWriteObjectArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <T> void writeCollection(String fieldName, @Nullable 
Collection<T> col)
 +        throws IgniteObjectException {
 +        writeFieldId(fieldName, COL);
 +        writeCollectionField(col);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <T> void writeCollection(@Nullable Collection<T> col) 
throws IgniteObjectException {
 +        doWriteCollection(col);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, 
V> map)
 +        throws IgniteObjectException {
 +        writeFieldId(fieldName, MAP);
 +        writeMapField(map);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <K, V> void writeMap(@Nullable Map<K, V> map) throws 
IgniteObjectException {
 +        doWriteMap(map);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <T extends Enum<?>> void writeEnum(String fieldName, T 
val) throws IgniteObjectException {
 +        writeFieldId(fieldName, ENUM);
 +        writeEnumField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <T extends Enum<?>> void writeEnum(T val) throws 
IgniteObjectException {
 +        doWriteEnum(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <T extends Enum<?>> void writeEnumArray(String 
fieldName, T[] val) throws IgniteObjectException {
 +        writeFieldId(fieldName, ENUM_ARR);
 +        writeEnumArrayField(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public <T extends Enum<?>> void writeEnumArray(T[] val) throws 
IgniteObjectException {
 +        doWriteEnumArray(val);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public IgniteObjectRawWriter rawWriter() {
-         if (allowFields) {
-             wCtx.out.writeInt(start + RAW_DATA_OFF_POS, wCtx.out.position() - 
start);
- 
-             allowFields = false;
-         }
++        if (rawOffPos == 0)
++            rawOffPos = out.position();
 +
 +        return this;
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public PortableOutputStream out() {
-         return wCtx.out;
++        return out;
 +    }
 +
 +    /** {@inheritDoc} */
++    @SuppressWarnings("NullableProblems")
 +    @Override public void writeBytes(String s) throws IOException {
 +        int len = s.length();
 +
 +        writeInt(len);
 +
 +        for (int i = 0; i < len; i++)
 +            writeByte(s.charAt(i));
 +    }
 +
 +    /** {@inheritDoc} */
++    @SuppressWarnings("NullableProblems")
 +    @Override public void writeChars(String s) throws IOException {
 +        int len = s.length();
 +
 +        writeInt(len);
 +
 +        for (int i = 0; i < len; i++)
 +            writeChar(s.charAt(i));
 +    }
 +
 +    /** {@inheritDoc} */
++    @SuppressWarnings("NullableProblems")
 +    @Override public void writeUTF(String s) throws IOException {
 +        writeString(s);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeByte(int v) throws IOException {
-         doWriteByte((byte)v);
++        doWriteByte((byte) v);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeShort(int v) throws IOException {
-         doWriteShort((short)v);
++        doWriteShort((short) v);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void writeChar(int v) throws IOException {
-         doWriteChar((char)v);
++        doWriteChar((char) v);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void write(int b) throws IOException {
-         doWriteByte((byte)b);
++        doWriteByte((byte) b);
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public void flush() throws IOException {
 +        // No-op.
 +    }
 +
 +    /** {@inheritDoc} */
 +    @Override public int reserveInt() {
 +        return reserve(LEN_INT);
 +    }
 +
-      /** {@inheritDoc} */
++    /** {@inheritDoc} */
 +    @Override public void writeInt(int pos, int val) throws 
IgniteObjectException {
-         wCtx.out.writeInt(pos, val);
++        out.writeInt(pos, val);
 +    }
 +
 +    /**
 +     * @param fieldName Field name.
 +     * @throws org.apache.ignite.igniteobject.IgniteObjectException If fields 
are not allowed.
 +     */
 +    private void writeFieldId(String fieldName, byte fieldType) throws 
IgniteObjectException {
 +        A.notNull(fieldName, "fieldName");
 +
-         if (!allowFields)
++        if (rawOffPos != 0)
 +            throw new IgniteObjectException("Individual field can't be 
written after raw writer is acquired " +
 +                "via rawWriter() method. Consider fixing serialization logic 
for class: " + cls.getName());
 +
-         int id = ctx.fieldId(typeId, fieldName);
++        if (idMapper == null)
++            idMapper = ctx.userTypeIdMapper(typeId);
++
++        int id = idMapper.fieldId(typeId, fieldName);
++
++        writeFieldId(id);
 +
 +        if (metaEnabled)
 +            metaHashSum = 31 * metaHashSum + (id + fieldType);
++    }
++
++    /**
++     * Write field ID.
++     * @param fieldId Field ID.
++     */
++    public void writeFieldId(int fieldId) {
++        int fieldOff = out.position() - start;
 +
-         doWriteInt(id);
++        if (schema == null) {
++            schema = SCHEMA.get();
++
++            if (schema == null) {
++                schema = new SchemaHolder();
++
++                SCHEMA.set(schema);
++            }
++
++            // Initialize offset when the first field is written.
++            schemaId = FNV1_OFFSET_BASIS;
++        }
++
++        // Advance schema hash.
++        int schemaId0 = schemaId ^ (fieldId & 0xFF);
++        schemaId0 = schemaId0 * FNV1_PRIME;
++        schemaId0 = schemaId0 ^ ((fieldId >> 8) & 0xFF);
++        schemaId0 = schemaId0 * FNV1_PRIME;
++        schemaId0 = schemaId0 ^ ((fieldId >> 16) & 0xFF);
++        schemaId0 = schemaId0 * FNV1_PRIME;
++        schemaId0 = schemaId0 ^ ((fieldId >> 24) & 0xFF);
++        schemaId0 = schemaId0 * FNV1_PRIME;
++
++        schemaId = schemaId0;
++
++        schema.push(fieldId, fieldOff);
++
++        fieldCnt++;
 +    }
 +
-      /**
-       * Attempts to write the object as a handle.
-       *
-       * @param obj Object to write.
-       * @return {@code true} if the object has been written as a handle.
-       */
-      boolean tryWriteAsHandle(Object obj) {
-          int handle = handle(obj);
++    /**
++     * Attempts to write the object as a handle.
++     *
++     * @param obj Object to write.
++     * @return {@code true} if the object has been written as a handle.
++     */
++    boolean tryWriteAsHandle(Object obj) {
++        int handle = handle(obj);
 +
-          if (handle >= 0) {
-              doWriteByte(GridPortableMarshaller.HANDLE);
-              doWriteInt(handle);
++        if (handle >= 0) {
++            doWriteByte(GridPortableMarshaller.HANDLE);
++            doWriteInt(handle);
 +
-              return true;
-          }
++            return true;
++        }
 +
-          return false;
-      }
++        return false;
++    }
 +
 +    /**
 +     * Create new writer with same context.
++     *
 +     * @param typeId type
 +     * @return New writer.
 +     */
 +    public IgniteObjectWriterExImpl newWriter(int typeId) {
-         IgniteObjectWriterExImpl res = new IgniteObjectWriterExImpl(ctx, 
wCtx);
++        IgniteObjectWriterExImpl res = new IgniteObjectWriterExImpl(ctx, out, 
handles);
 +
 +        res.typeId = typeId;
 +
 +        return res;
 +    }
 +
 +    /**
 +     * @return Portable context.
 +     */
 +    public PortableContext context() {
 +        return ctx;
 +    }
 +
-     /** */
-     private static class WriterContext {
-         /** */
-         private Map<Object, Integer> handles = new IdentityHashMap<>();
++    /**
++     * Schema holder.
++     */
++    private static class SchemaHolder {
++        /** Grow step. */
++        private static final int GROW_STEP = 16;
++
++        /** Maximum stable size. */
++        private static final int MAX_SIZE = 256;
++
++        /** Data. */
++        private int[] data;
 +
-         /** Output stream. */
-         private PortableOutputStream out;
++        /** Index. */
++        private int idx;
 +
 +        /**
 +         * Constructor.
-          *
-          * @param out Output stream.
-          * @param handles Handles.
 +         */
-         private WriterContext(PortableOutputStream out, Map<Object, Integer> 
handles) {
-             this.out = out;
-             this.handles = handles == null ? new IdentityHashMap<Object, 
Integer>() : handles;
++        public SchemaHolder() {
++            data = new int[GROW_STEP];
 +        }
 +
 +        /**
-          * @param obj Object.
-          * @return Handle.
++         * Push another frame.
++         *
++         * @param id Field ID.
++         * @param off Field offset.
 +         */
-         private int handle(Object obj) {
-             assert obj != null;
- 
-             Integer h = handles.get(obj);
++        public void push(int id, int off) {
++            if (idx == data.length) {
++                int[] data0 = new int[data.length + GROW_STEP];
 +
-             if (h != null)
-                 return out.position() - h;
-             else {
-                 handles.put(obj, out.position());
++                System.arraycopy(data, 0, data0, 0, data.length);
 +
-                 return -1;
++                data = data0;
 +            }
++
++            data[idx] = id;
++            data[idx + 1] = off;
++
++            idx += 2;
 +        }
 +
 +        /**
++         * Write collected frames and pop them.
 +         *
++         * @param writer Writer.
++         * @param cnt Count.
 +         */
-         private void resetHandles() {
-             handles = new IdentityHashMap<>();
++        public void writeAndPop(PortableWriterExImpl writer, int cnt) {
++            int startIdx = idx - cnt * 2;
++
++            assert startIdx >= 0;
++
++            for (int idx0 = startIdx; idx0 < idx;) {
++                writer.writeInt(data[idx0++]);
++                writer.writeInt(data[idx0++]);
++            }
++
++            idx = startIdx;
++
++            // Shrink data array if needed.
++            if (idx == 0 && data.length > MAX_SIZE)
++                data = new int[MAX_SIZE];
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
----------------------------------------------------------------------
diff --cc 
modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
index 2470837,9f7f0c6..4cad80b
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
@@@ -17,6 -17,18 +17,14 @@@
  
  package org.apache.ignite.internal.portable;
  
+ import org.apache.ignite.IgniteCheckedException;
+ import org.apache.ignite.internal.processors.cache.CacheObjectImpl;
+ import org.apache.ignite.internal.util.typedef.internal.U;
+ import org.apache.ignite.marshaller.MarshallerExclusions;
+ import org.apache.ignite.marshaller.optimized.OptimizedMarshaller;
+ import org.apache.ignite.marshaller.portable.PortableMarshaller;
 -import org.apache.ignite.portable.PortableException;
 -import org.apache.ignite.portable.PortableIdMapper;
 -import org.apache.ignite.portable.PortableMarshalAware;
 -import org.apache.ignite.portable.PortableSerializer;
+ import org.jetbrains.annotations.Nullable;
+ 
  import java.io.Externalizable;
  import java.io.IOException;
  import java.io.ObjectInputStream;
@@@ -61,8 -62,11 +69,11 @@@ public class PortableClassDescriptor 
      private final Class<?> cls;
  
      /** */
 -    private final PortableSerializer serializer;
 +    private final IgniteObjectSerializer serializer;
  
+     /** ID mapper. */
+     private final PortableIdMapper idMapper;
+ 
      /** */
      private final Mode mode;
  
@@@ -513,14 -527,13 +534,13 @@@
                      if (serializer != null)
                          serializer.writePortable(obj, writer);
                      else
 -                        ((PortableMarshalAware)obj).writePortable(writer);
 +                        ((IgniteObjectMarshalAware)obj).writePortable(writer);
  
-                     writer.writeRawOffsetIfNeeded();
-                     writer.writeLength();
+                     writer.postWrite(userType);
  
 -                    if (obj.getClass() != PortableMetaDataImpl.class
 +                    if (obj.getClass() != IgniteObjectMetaDataImpl.class
                          && ctx.isMetaDataChanged(typeId, 
writer.metaDataHashSum())) {
 -                        PortableMetaDataCollector metaCollector = new 
PortableMetaDataCollector(typeName);
 +                        IgniteObjectMetaDataCollector metaCollector = new 
IgniteObjectMetaDataCollector(typeName);
  
                          if (serializer != null)
                              serializer.writePortable(obj, metaCollector);
@@@ -539,10 -554,10 +561,10 @@@
                          ((Externalizable)obj).writeExternal(writer);
                      }
                      catch (IOException e) {
 -                        throw new PortableException("Failed to write 
Externalizable object: " + obj, e);
 +                        throw new IgniteObjectException("Failed to write 
Externalizable object: " + obj, e);
                      }
  
-                     writer.writeLength();
+                     writer.postWrite(userType);
                  }
  
                  break;

http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
----------------------------------------------------------------------
diff --cc 
modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
index 471781c,e61cba7..3b32e67
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableContext.java
@@@ -81,10 -80,13 +103,13 @@@ public class PortableContext implement
      private static final long serialVersionUID = 0L;
  
      /** */
+     private static final ClassLoader dfltLdr = U.gridClassLoader();
+ 
+     /** */
 -    static final PortableIdMapper DFLT_ID_MAPPER = new IdMapperWrapper(null);
 +    static final IgniteObjectIdMapper DFLT_ID_MAPPER = new 
IdMapperWrapper(null);
  
      /** */
 -    static final PortableIdMapper BASIC_CLS_ID_MAPPER = new 
BasicClassIdMapper();
 +    static final IgniteObjectIdMapper BASIC_CLS_ID_MAPPER = new 
BasicClassIdMapper();
  
      /** */
      static final char[] LOWER_CASE_CHARS;
@@@ -124,10 -126,10 +149,10 @@@
      private final Map<Class<? extends Map>, Byte> mapTypes = new HashMap<>();
  
      /** */
-     private final Map<Integer, IgniteObjectIdMapper> mappers = new 
ConcurrentHashMap8<>(0);
 -    private final ConcurrentMap<Integer, PortableIdMapper> mappers = new 
ConcurrentHashMap8<>(0);
++    private final ConcurrentMap<Integer, IgniteObjectIdMapper> mappers = new 
ConcurrentHashMap8<>(0);
  
      /** */
 -    private final Map<String, PortableIdMapper> typeMappers = new 
ConcurrentHashMap8<>(0);
 +    private final Map<String, IgniteObjectIdMapper> typeMappers = new 
ConcurrentHashMap8<>(0);
  
      /** */
      private Map<Integer, Boolean> metaEnabled = new HashMap<>(0);
@@@ -475,10 -471,18 +505,18 @@@
              desc = descByCls.get(cls);
          }
          catch (ClassNotFoundException e) {
+             // Class might have been loaded by default class loader.
+             if (userType && !ldr.equals(dfltLdr) && (desc = 
descriptorForTypeId(true, typeId, dfltLdr)) != null)
+                 return desc;
+ 
 -            throw new PortableInvalidClassException(e);
 +            throw new IgniteObjectInvalidClassException(e);
          }
          catch (IgniteCheckedException e) {
+             // Class might have been loaded by default class loader.
+             if (userType && !ldr.equals(dfltLdr) && (desc = 
descriptorForTypeId(true, typeId, dfltLdr)) != null)
+                 return desc;
+ 
 -            throw new PortableException("Failed resolve class for ID: " + 
typeId, e);
 +            throw new IgniteObjectException("Failed resolve class for ID: " + 
typeId, e);
          }
  
          if (desc == null) {
@@@ -537,7 -541,7 +575,7 @@@
  
          String typeName = typeName(cls.getName());
  
-         IgniteObjectIdMapper idMapper = idMapper(typeName);
 -        PortableIdMapper idMapper = userTypeIdMapper(typeName);
++        IgniteObjectIdMapper idMapper = userTypeIdMapper(typeName);
  
          int typeId = idMapper.typeId(typeName);
  
@@@ -630,8 -639,8 +673,8 @@@
       * @param typeId Type ID.
       * @return Instance of ID mapper.
       */
-     public IgniteObjectIdMapper idMapper(int typeId) {
 -    public PortableIdMapper userTypeIdMapper(int typeId) {
 -        PortableIdMapper idMapper = mappers.get(typeId);
++    public IgniteObjectIdMapper userTypeIdMapper(int typeId) {
 +        IgniteObjectIdMapper idMapper = mappers.get(typeId);
  
          if (idMapper != null)
              return idMapper;
@@@ -646,8 -655,8 +689,8 @@@
       * @param typeName Type name.
       * @return Instance of ID mapper.
       */
-     private IgniteObjectIdMapper idMapper(String typeName) {
 -    private PortableIdMapper userTypeIdMapper(String typeName) {
 -        PortableIdMapper idMapper = typeMappers.get(typeName);
++    private IgniteObjectIdMapper userTypeIdMapper(String typeName) {
 +        IgniteObjectIdMapper idMapper = typeMappers.get(typeName);
  
          return idMapper != null ? idMapper : DFLT_ID_MAPPER;
      }
@@@ -907,10 -966,26 +1000,26 @@@
      }
  
      /**
+      * Undeployment callback invoked when class loader is being undeployed.
+      *
+      * Some marshallers may want to clean their internal state that uses the 
undeployed class loader somehow.
+      *
+      * @param ldr Class loader being undeployed.
+      */
+     public void onUndeploy(ClassLoader ldr) {
+         for (Class<?> cls : descByCls.keySet()) {
+             if (ldr.equals(cls.getClassLoader()))
+                 descByCls.remove(cls);
+         }
+ 
+         U.clearClassCache(ldr);
+     }
+ 
+     /**
       */
 -    private static class IdMapperWrapper implements PortableIdMapper {
 +    private static class IdMapperWrapper implements IgniteObjectIdMapper {
          /** */
 -        private final PortableIdMapper mapper;
 +        private final IgniteObjectIdMapper mapper;
  
          /**
           * @param mapper Custom ID mapper.

http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
----------------------------------------------------------------------
diff --cc 
modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
index bf1c3b6,51fc407..cfe7efe
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableReaderContext.java
@@@ -20,18 -20,19 +20,19 @@@ package org.apache.ignite.internal.port
  import java.util.HashMap;
  import java.util.Map;
  import org.apache.ignite.internal.util.typedef.internal.S;
 +import org.apache.ignite.igniteobject.IgniteObject;
+ import org.apache.ignite.lang.IgniteBiTuple;
 -import org.apache.ignite.portable.PortableObject;
  import org.jetbrains.annotations.Nullable;
  
  /**
-  * Reader context.
-  */
+ * Reader context.
+ */
  class PortableReaderContext {
      /** */
-     private Map<Integer, Object> oHandles;
+     private Object oHandles;
  
      /** */
 -    private Map<Integer, PortableObject> poHandles;
 +    private Map<Integer, IgniteObject> poHandles;
  
      /**
       * @param handle Handle.

http://git-wip-us.apache.org/repos/asf/ignite/blob/b5c70a94/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
----------------------------------------------------------------------
diff --cc 
modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
index d6b526d,eafcbd1..e0e6d21
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableUtils.java
@@@ -18,9 -18,11 +18,11 @@@
  package org.apache.ignite.internal.portable;
  
  import org.apache.ignite.internal.portable.builder.PortableLazyValue;
+ import org.apache.ignite.internal.util.typedef.F;
  import org.apache.ignite.internal.util.typedef.internal.U;
+ import org.apache.ignite.lang.IgniteBiTuple;
 -import org.apache.ignite.portable.PortableException;
 -import org.apache.ignite.portable.PortableObject;
 +import org.apache.ignite.igniteobject.IgniteObjectException;
 +import org.apache.ignite.igniteobject.IgniteObject;
  import org.jetbrains.annotations.Nullable;
  import org.jsr166.ConcurrentHashMap8;
  
@@@ -92,6 -94,47 +94,47 @@@ public class PortableUtils 
      /** Portable classes. */
      private static final Collection<Class<?>> PORTABLE_CLS = new HashSet<>();
  
+     /** Flag: user type. */
+     public static final short FLAG_USR_TYP = 0x1;
+ 
+     /** Flag: only raw data exists. */
+     public static final short FLAG_RAW_ONLY = 0x2;
+ 
+     /**
+      * Write flags.
+      *
+      * @param writer Writer.
+      * @param userType User type flag.
+      */
 -    public static void writeFlags(PortableWriterExImpl writer, boolean 
userType) {
++    public static void writeFlags(IgniteObjectWriterExImpl writer, boolean 
userType) {
+         short val = 0;
+ 
+         if (userType)
+             val |= FLAG_USR_TYP;
+ 
+         writer.doWriteShort(val);
+     }
+ 
+     /**
+      * Check if user type flag is set.
+      *
+      * @param flags Flags.
+      * @return {@code True} if set.
+      */
+     public static boolean isUserType(short flags) {
+         return (flags & FLAG_USR_TYP) == FLAG_USR_TYP;
+     }
+ 
+     /**
+      * Check if raw-only flag is set.
+      *
+      * @param flags Flags.
+      * @return {@code True} if set.
+      */
+     public static boolean isRawOnly(short flags) {
+         return (flags & FLAG_RAW_ONLY) == FLAG_RAW_ONLY;
+     }
+ 
      /**
       *
       */
@@@ -485,6 -528,120 +528,120 @@@
       */
      public static void checkProtocolVersion(byte protoVer) {
          if (PROTO_VER != protoVer)
 -            throw new PortableException("Unsupported protocol version: " + 
protoVer);
 +            throw new IgniteObjectException("Unsupported protocol version: " 
+ protoVer);
      }
+ 
+     /**
+      * Write portable header.
+      *
+      * @param writer Writer.
+      * @param usrTyp User type flag.
+      * @param typeId Type ID.
+      * @param hashCode Hash code.
+      * @param clsName Class name (optional).
+      * @return Position where length should be written.
+      */
 -    public static int writeHeader(PortableWriterExImpl writer, boolean 
usrTyp, int typeId, int hashCode,
++    public static int writeHeader(IgniteObjectWriterExImpl writer, boolean 
usrTyp, int typeId, int hashCode,
+         @Nullable String clsName) {
+         writer.doWriteByte(GridPortableMarshaller.OBJ);
+         writer.doWriteByte(GridPortableMarshaller.PROTO_VER);
+ 
+         PortableUtils.writeFlags(writer, usrTyp);
+ 
+         writer.doWriteInt(typeId);
+         writer.doWriteInt(hashCode);
+ 
+         int reserved = writer.reserve(12);
+ 
+         if (clsName != null)
+             writer.doWriteString(clsName);
+ 
+         return reserved;
+     }
+ 
+     /**
+      * Get portable object length.
+      *
+      * @param in Input stream.
+      * @param start Start position.
+      * @return Length.
+      */
+     public static int length(PortablePositionReadable in, int start) {
+         return in.readIntPositioned(start + 
GridPortableMarshaller.TOTAL_LEN_POS);
+     }
+ 
+     /**
+      * Get footer start of the object.
+      *
+      * @param in Input stream.
+      * @param start Object start position inside the stream.
+      * @return Footer start.
+      */
+     public static int footerStartRelative(PortablePositionReadable in, int 
start) {
+         short flags = in.readShortPositioned(start + 
GridPortableMarshaller.FLAGS_POS);
+ 
+         if (PortableUtils.isRawOnly(flags))
+             // No schema, footer start equals to object end.
+             return length(in, start);
+         else
+             // Schema exists, use offset.
+             return in.readIntPositioned(start + 
GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS);
+     }
+ 
+     /**
+      * Get object's footer.
+      *
+      * @param in Input stream.
+      * @param start Start position.
+      * @return Footer start.
+      */
+     public static int footerStartAbsolute(PortablePositionReadable in, int 
start) {
+         return footerStartRelative(in, start) + start;
+     }
+ 
+     /**
+      * Get object's footer.
+      *
+      * @param in Input stream.
+      * @param start Start position.
+      * @return Footer.
+      */
+     public static IgniteBiTuple<Integer, Integer> 
footerAbsolute(PortablePositionReadable in, int start) {
+         int footerStart = footerStartRelative(in, start);
+         int footerEnd = length(in, start);
+ 
+         // Take in count possible raw offset.
+         if ((((footerEnd - footerStart) >> 2) & 0x1) == 0x1)
+             footerEnd -= 4;
+ 
+         return F.t(start + footerStart, start + footerEnd);
+     }
+ 
+     /**
+      * Get raw offset of the object.
+      *
+      * @param in Input stream.
+      * @param start Object start position inside the stream.
+      * @return Raw offset.
+      */
+     public static int rawOffsetAbsolute(PortablePositionReadable in, int 
start) {
+         int len = length(in, start);
+ 
+         short flags = in.readShortPositioned(start + 
GridPortableMarshaller.FLAGS_POS);
+ 
+         if (PortableUtils.isRawOnly(flags))
+             // No schema, raw offset is located on schema offset position.
+             return start + in.readIntPositioned(start + 
GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS);
+         else {
+             // Schema exists.
+             int schemaOff = in.readIntPositioned(start + 
GridPortableMarshaller.SCHEMA_OR_RAW_OFF_POS);
+ 
+             if ((((len - schemaOff) >> 2) & 0x1) == 0x0)
+                 // Even amount of records in schema => no raw offset.
+                 return start + schemaOff;
+             else
+                 // Odd amount of records in schema => raw offset is the very 
last 4 bytes in object.
+                 return start + in.readIntPositioned(start + len - 4);
+         }
+     }
  }

Reply via email to