ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject [64/67] [abbrv] ignite git commit: Merge branch 'ignite-1847' into ignite-1816
Date Wed, 11 Nov 2015 08:26:00 GMT
http://git-wip-us.apache.org/repos/asf/ignite/blob/2c9378a8/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
----------------------------------------------------------------------
diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
index 0000000,cedf1c8..f1ecb0f
mode 000000,100644..100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/BinaryWriterExImpl.java
@@@ -1,0 -1,1901 +1,1902 @@@
+ /*
+  * 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.binary.BinaryIdMapper;
+ 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.binary.BinaryObjectException;
+ import org.apache.ignite.binary.BinaryRawWriter;
+ import org.apache.ignite.binary.BinaryWriter;
+ 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.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 BinaryWriterExImpl implements BinaryWriter, BinaryRawWriterEx, ObjectOutput {
+     /** Length: integer. */
+     private static final int LEN_INT = 4;
+ 
 -    /** */
++    /** Initial capacity. */
+     private static final int INIT_CAP = 1024;
+ 
+     /** FNV1 hash offset basis. */
+     private static final int FNV1_OFFSET_BASIS = 0x811C9DC5;
+ 
+     /** FNV1 hash prime. */
+     private static final int FNV1_PRIME = 0x01000193;
+ 
+     /** Maximum offset which fits in 1 byte. */
+     private static final int MAX_OFFSET_1 = 1 << 8;
+ 
+     /** Maximum offset which fits in 2 bytes. */
+     private static final int MAX_OFFSET_2 = 1 << 16;
+ 
+     /** Thread-local schema. */
+     private static final ThreadLocal<SchemaHolder> SCHEMA = new ThreadLocal<>();
+ 
+     /** */
+     private final PortableContext ctx;
+ 
+     /** */
+     private final int start;
+ 
+     /** */
+     private Class<?> cls;
+ 
+     /** */
+     private int typeId;
+ 
+     /** Raw offset position. */
+     private int rawOffPos;
+ 
+     /** */
+     private boolean metaEnabled;
+ 
+     /** */
+     private int metaHashSum;
+ 
+     /** Handles. */
+     private Map<Object, Integer> handles;
+ 
+     /** Output stream. */
+     private PortableOutputStream out;
+ 
+     /** Schema. */
+     private SchemaHolder schema;
+ 
+     /** Schema ID. */
+     private int schemaId;
+ 
+     /** Amount of written fields. */
+     private int fieldCnt;
+ 
+     /** ID mapper. */
+     private BinaryIdMapper idMapper;
+ 
+     /**
+      * @param ctx Context.
+      */
+     BinaryWriterExImpl(PortableContext ctx) {
+         this(ctx, new PortableHeapOutputStream(INIT_CAP));
+     }
+ 
+     /**
+      * @param ctx Context.
+      * @param out Output stream.
+      */
+     BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out) {
+         this(ctx, out, new IdentityHashMap<Object, Integer>());
+     }
+ 
+      /**
+       * @param ctx Context.
+       * @param out Output stream.
+       * @param handles Handles.
+       */
+      private BinaryWriterExImpl(PortableContext ctx, PortableOutputStream out, Map<Object, Integer> handles) {
+          this.ctx = ctx;
+          this.out = out;
+          this.handles = handles;
+ 
+          start = out.position();
+      }
+ 
+     /**
+      * @param ctx Context.
+      * @param typeId Type ID.
+      */
+     public BinaryWriterExImpl(PortableContext ctx, int typeId, boolean metaEnabled) {
+         this(ctx);
+ 
+         this.typeId = typeId;
+         this.metaEnabled = metaEnabled;
+     }
+ 
+     /**
+      * Close the writer releasing resources if necessary.
+      */
+     @Override public void 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.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void marshal(Object obj) throws BinaryObjectException {
+         marshal(obj, true);
+     }
+ 
+     /**
+      * @param obj Object.
+      * @param enableReplace Object replacing enabled flag.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void marshal(Object obj, boolean enableReplace) throws BinaryObjectException {
+         assert obj != null;
+ 
+         cls = obj.getClass();
+ 
+         PortableClassDescriptor desc = ctx.descriptorForClass(cls);
+ 
+         if (desc == null)
+             throw new BinaryObjectException("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 BinaryObjectException("Failed to marshal object with optimized marshaller: " + obj, e);
+             }
+ 
+             return;
+         }
+ 
+         if (enableReplace && desc.getWriteReplaceMethod() != null) {
+             Object replacedObj;
+ 
+             try {
+                 replacedObj = desc.getWriteReplaceMethod().invoke(obj);
+             }
+             catch (IllegalAccessException e) {
+                 throw new RuntimeException(e);
+             }
+             catch (InvocationTargetException e) {
+                 if (e.getTargetException() instanceof BinaryObjectException)
+                     throw (BinaryObjectException)e.getTargetException();
+ 
+                 throw new BinaryObjectException("Failed to execute writeReplace() method on " + obj, e);
+             }
+ 
+             if (replacedObj == null) {
+                 doWriteByte(NULL);
+                 return;
+             }
+ 
+             marshal(replacedObj, false);
+ 
+             return;
+         }
+ 
+         typeId = desc.typeId();
+         metaEnabled = desc.userType();
+ 
+         desc.write(obj, this);
+     }
+ 
+     /**
+      * @param obj Object.
+      * @return Handle.
+      */
+     int handle(Object obj) {
+         assert obj != null;
+ 
+         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 out.arrayCopy();
+     }
+ 
+     /**
+      * @return Stream current position.
+      */
+     int position() {
+         return out.position();
+     }
+ 
+     /**
+      * Sets new position.
+      *
+      * @param pos Position.
+      */
+     void position(int pos) {
+         out.position(pos);
+     }
+ 
+     /**
+      * @param bytes Number of bytes to reserve.
+      * @return Offset.
+      */
+     public int reserve(int bytes) {
+         int pos = out.position();
+ 
+         out.position(pos + bytes);
+ 
+         return pos;
+     }
+ 
+     /**
+      * Perform post-write activity. This includes:
++     * - writing flags;
+      * - writing object length;
+      * - writing schema offset;
+      * - writing schema to the tail.
+      *
+      * @param userType User type flag.
+      */
+     public void postWrite(boolean userType) {
++        short flags = userType ? PortableUtils.FLAG_USR_TYP : 0;
++
++        if (ctx.isNoFieldIds())
++            flags |= PortableUtils.FLAG_NO_FIELD_IDS;
++
+         if (schema != null) {
+             // Write schema ID.
+             out.writeInt(start + SCHEMA_ID_POS, schemaId);
+ 
+             // Write schema offset.
+             out.writeInt(start + SCHEMA_OR_RAW_OFF_POS, out.position() - start);
+ 
+             // Write the schema.
+             int offsetByteCnt = schema.write(this, fieldCnt);
+ 
+             // Write raw offset if needed.
+             if (rawOffPos != 0)
+                 out.writeInt(rawOffPos - start);
+ 
 -            if (offsetByteCnt == PortableUtils.OFFSET_1) {
 -                int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_OFFSET_ONE_BYTE;
 -
 -                out.writeShort(start + FLAGS_POS, (short)flags);
 -            }
 -            else if (offsetByteCnt == PortableUtils.OFFSET_2) {
 -                int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_OFFSET_TWO_BYTES;
 -
 -                out.writeShort(start + FLAGS_POS, (short)flags);
 -            }
++            if (offsetByteCnt == PortableUtils.OFFSET_1)
++                flags |= PortableUtils.FLAG_OFFSET_ONE_BYTE;
++            else if (offsetByteCnt == PortableUtils.OFFSET_2)
++                flags |= PortableUtils.FLAG_OFFSET_TWO_BYTES;
+         }
+         else {
+             // Write raw-only flag is needed.
 -            int flags = (userType ? PortableUtils.FLAG_USR_TYP : 0) | PortableUtils.FLAG_RAW_ONLY;
 -
 -            out.writeShort(start + FLAGS_POS, (short)flags);
++            flags |= PortableUtils.FLAG_RAW_ONLY;
+ 
+             // 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.
++        // Write flags as we know them at this point.
++        out.writeShort(start + FLAGS_POS, flags);
++
++        // Write length.
+         out.writeInt(start + TOTAL_LEN_POS, out.position() - start);
+     }
+ 
+     /**
+      * Pop schema.
+      */
+     public void popSchema() {
+         if (schema != null) {
+             assert fieldCnt > 0;
+ 
+             schema.pop(fieldCnt);
+         }
+     }
+ 
+     /**
+      * @param val Byte array.
+      */
+     public void write(byte[] val) {
+         assert val != null;
+ 
+         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;
+ 
+         out.write(val, off, len);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteByte(byte val) {
+         out.writeByte(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteShort(short val) {
+         out.writeShort(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteInt(int val) {
+         out.writeInt(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteLong(long val) {
+         out.writeLong(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteFloat(float val) {
+         out.writeFloat(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteDouble(double val) {
+         out.writeDouble(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteChar(char val) {
+         out.writeChar(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     public void doWriteBoolean(boolean 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();
+ 
+                 out.writeInt(val.scale() | 0x80000000);
+             }
+             else
+                 out.writeInt(val.scale());
+ 
+             byte[] vals = intVal.toByteArray();
+ 
+             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);
+ 
+             byte[] strArr = val.getBytes(UTF_8);
+ 
+             doWriteInt(strArr.length);
+ 
+             out.writeByteArray(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);
+         }
+     }
+ 
+     /**
+      * Write object.
+      *
+      * @param obj Object.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     public void doWriteObject(@Nullable Object obj) throws BinaryObjectException {
+         if (obj == null)
+             doWriteByte(NULL);
+         else {
+             BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, handles);
+ 
+             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);
+ 
+             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);
+ 
+             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);
+ 
+             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);
+ 
+             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);
+ 
+             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);
+ 
+             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);
+ 
+             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);
+ 
+             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.binary.BinaryObjectException In case of error.
+      */
+     void doWriteObjectArray(@Nullable Object[] val) throws BinaryObjectException {
+         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);
+         }
+     }
+ 
+     /**
+      * @param col Collection.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void doWriteCollection(@Nullable Collection<?> col) throws BinaryObjectException {
+         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);
+         }
+     }
+ 
+     /**
+      * @param map Map.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void doWriteMap(@Nullable Map<?, ?> map) throws BinaryObjectException {
+         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());
+                 doWriteObject(e.getValue());
+             }
+         }
+     }
+ 
+     /**
+      * @param e Map entry.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void doWriteMapEntry(@Nullable Map.Entry<?, ?> e) throws BinaryObjectException {
+         if (e == null)
+             doWriteByte(NULL);
+         else {
+             if (tryWriteAsHandle(e))
+                 return;
+ 
+             doWriteByte(MAP_ENTRY);
+             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 BinaryObjectImpl po) {
+         if (po == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(PORTABLE_OBJ);
+ 
+             byte[] poArr = po.array();
+ 
+             doWriteInt(poArr.length);
+ 
+             out.writeByteArray(poArr);
+ 
+             doWriteInt(po.start());
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeByteField(@Nullable Byte val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(BYTE);
+             doWriteByte(val);
+         }
+     }
+ 
+     /**
+      * @param val Class.
+      */
+     void writeClassField(@Nullable Class val) {
+         doWriteClass(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeShortField(@Nullable Short val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(SHORT);
+             doWriteShort(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeIntField(@Nullable Integer val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(INT);
+             doWriteInt(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeLongField(@Nullable Long val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(LONG);
+             doWriteLong(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeFloatField(@Nullable Float val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(FLOAT);
+             doWriteFloat(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeDoubleField(@Nullable Double val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(DOUBLE);
+             doWriteDouble(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeCharField(@Nullable Character val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(CHAR);
+             doWriteChar(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeBooleanField(@Nullable Boolean val) {
+         if (val == null)
+             doWriteByte(NULL);
+         else {
+             doWriteByte(BOOLEAN);
+             doWriteBoolean(val);
+         }
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeDecimalField(@Nullable BigDecimal val) {
+         doWriteDecimal(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeStringField(@Nullable String val) {
+         doWriteString(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeUuidField(@Nullable UUID val) {
+         doWriteUuid(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeDateField(@Nullable Date val) {
+         doWriteDate(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeTimestampField(@Nullable Timestamp val) {
+         doWriteTimestamp(val);
+     }
+ 
+     /**
+      * @param obj Object.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void writeObjectField(@Nullable Object obj) throws BinaryObjectException {
+         doWriteObject(obj);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeByteArrayField(@Nullable byte[] val) {
+         doWriteByteArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeShortArrayField(@Nullable short[] val) {
+         doWriteShortArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeIntArrayField(@Nullable int[] val) {
+         doWriteIntArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeLongArrayField(@Nullable long[] val) {
+         doWriteLongArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeFloatArrayField(@Nullable float[] val) {
+         doWriteFloatArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeDoubleArrayField(@Nullable double[] val) {
+         doWriteDoubleArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeCharArrayField(@Nullable char[] val) {
+         doWriteCharArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeBooleanArrayField(@Nullable boolean[] val) {
+         doWriteBooleanArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeDecimalArrayField(@Nullable BigDecimal[] val) {
+         doWriteDecimalArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeStringArrayField(@Nullable String[] val) {
+         doWriteStringArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeUuidArrayField(@Nullable UUID[] val) {
+         doWriteUuidArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeDateArrayField(@Nullable Date[] val) {
+         doWriteDateArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeTimestampArrayField(@Nullable Timestamp[] val) {
+         doWriteTimestampArray(val);
+     }
+ 
+     /**
+      * @param val Value.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void writeObjectArrayField(@Nullable Object[] val) throws BinaryObjectException {
+         doWriteObjectArray(val);
+     }
+ 
+     /**
+      * @param col Collection.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void writeCollectionField(@Nullable Collection<?> col) throws BinaryObjectException {
+         doWriteCollection(col);
+     }
+ 
+     /**
+      * @param map Map.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void writeMapField(@Nullable Map<?, ?> map) throws BinaryObjectException {
+         doWriteMap(map);
+     }
+ 
+     /**
+      * @param e Map entry.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void writeMapEntryField(@Nullable Map.Entry<?, ?> e) throws BinaryObjectException {
+         doWriteMapEntry(e);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeEnumField(@Nullable Enum<?> val) {
+         doWriteEnum(val);
+     }
+ 
+     /**
+      * @param val Value.
+      */
+     void writeEnumArrayField(@Nullable Object[] val) {
+         doWriteEnumArray(val);
+     }
+ 
+     /**
+      * @param po Portable object.
+      * @throws org.apache.ignite.binary.BinaryObjectException In case of error.
+      */
+     void writePortableObjectField(@Nullable BinaryObjectImpl po) throws BinaryObjectException {
+         doWritePortableObject(po);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeByte(String fieldName, byte val) throws BinaryObjectException {
+         writeFieldId(fieldName, BYTE);
+         writeByteField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeByte(byte val) throws BinaryObjectException {
+         doWriteByte(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeShort(String fieldName, short val) throws BinaryObjectException {
+         writeFieldId(fieldName, SHORT);
+         writeShortField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeShort(short val) throws BinaryObjectException {
+         doWriteShort(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeInt(String fieldName, int val) throws BinaryObjectException {
+         writeFieldId(fieldName, INT);
+         writeIntField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeInt(int val) throws BinaryObjectException {
+         doWriteInt(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeLong(String fieldName, long val) throws BinaryObjectException {
+         writeFieldId(fieldName, LONG);
+         writeLongField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeLong(long val) throws BinaryObjectException {
+         doWriteLong(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeFloat(String fieldName, float val) throws BinaryObjectException {
+         writeFieldId(fieldName, FLOAT);
+         writeFloatField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeFloat(float val) throws BinaryObjectException {
+         doWriteFloat(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDouble(String fieldName, double val) throws BinaryObjectException {
+         writeFieldId(fieldName, DOUBLE);
+         writeDoubleField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDouble(double val) throws BinaryObjectException {
+         doWriteDouble(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeChar(String fieldName, char val) throws BinaryObjectException {
+         writeFieldId(fieldName, CHAR);
+         writeCharField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeChar(char val) throws BinaryObjectException {
+         doWriteChar(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeBoolean(String fieldName, boolean val) throws BinaryObjectException {
+         writeFieldId(fieldName, BOOLEAN);
+         writeBooleanField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeBoolean(boolean val) throws BinaryObjectException {
+         doWriteBoolean(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDecimal(String fieldName, @Nullable BigDecimal val) throws BinaryObjectException {
+         writeFieldId(fieldName, DECIMAL);
+         writeDecimalField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDecimal(@Nullable BigDecimal val) throws BinaryObjectException {
+         doWriteDecimal(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeString(String fieldName, @Nullable String val) throws BinaryObjectException {
+         writeFieldId(fieldName, STRING);
+         writeStringField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeString(@Nullable String val) throws BinaryObjectException {
+         doWriteString(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeUuid(String fieldName, @Nullable UUID val) throws BinaryObjectException {
+         writeFieldId(fieldName, UUID);
+         writeUuidField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeUuid(@Nullable UUID val) throws BinaryObjectException {
+         doWriteUuid(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDate(String fieldName, @Nullable Date val) throws BinaryObjectException {
+         writeFieldId(fieldName, DATE);
+         writeDateField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDate(@Nullable Date val) throws BinaryObjectException {
+         doWriteDate(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeTimestamp(String fieldName, @Nullable Timestamp val) throws BinaryObjectException {
+         writeFieldId(fieldName, TIMESTAMP);
+         writeTimestampField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeTimestamp(@Nullable Timestamp val) throws BinaryObjectException {
+         doWriteTimestamp(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeObject(String fieldName, @Nullable Object obj) throws BinaryObjectException {
+         writeFieldId(fieldName, OBJ);
+         writeObjectField(obj);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeObject(@Nullable Object obj) throws BinaryObjectException {
+         doWriteObject(obj);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeObjectDetached(@Nullable Object obj) throws BinaryObjectException {
+         if (obj == null)
+             doWriteByte(NULL);
+         else {
+             BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, out, new IdentityHashMap<Object, Integer>());
+ 
+             writer.marshal(obj);
+         }
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeByteArray(String fieldName, @Nullable byte[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, BYTE_ARR);
+         writeByteArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeByteArray(@Nullable byte[] val) throws BinaryObjectException {
+         doWriteByteArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeShortArray(String fieldName, @Nullable short[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, SHORT_ARR);
+         writeShortArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeShortArray(@Nullable short[] val) throws BinaryObjectException {
+         doWriteShortArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeIntArray(String fieldName, @Nullable int[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, INT_ARR);
+         writeIntArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeIntArray(@Nullable int[] val) throws BinaryObjectException {
+         doWriteIntArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeLongArray(String fieldName, @Nullable long[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, LONG_ARR);
+         writeLongArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeLongArray(@Nullable long[] val) throws BinaryObjectException {
+         doWriteLongArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeFloatArray(String fieldName, @Nullable float[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, FLOAT_ARR);
+         writeFloatArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeFloatArray(@Nullable float[] val) throws BinaryObjectException {
+         doWriteFloatArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDoubleArray(String fieldName, @Nullable double[] val)
+         throws BinaryObjectException {
+         writeFieldId(fieldName, DOUBLE_ARR);
+         writeDoubleArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDoubleArray(@Nullable double[] val) throws BinaryObjectException {
+         doWriteDoubleArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeCharArray(String fieldName, @Nullable char[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, CHAR_ARR);
+         writeCharArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeCharArray(@Nullable char[] val) throws BinaryObjectException {
+         doWriteCharArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeBooleanArray(String fieldName, @Nullable boolean[] val)
+         throws BinaryObjectException {
+         writeFieldId(fieldName, BOOLEAN_ARR);
+         writeBooleanArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeBooleanArray(@Nullable boolean[] val) throws BinaryObjectException {
+         doWriteBooleanArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDecimalArray(String fieldName, @Nullable BigDecimal[] val)
+         throws BinaryObjectException {
+         writeFieldId(fieldName, DECIMAL_ARR);
+         writeDecimalArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDecimalArray(@Nullable BigDecimal[] val) throws BinaryObjectException {
+         doWriteDecimalArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeStringArray(String fieldName, @Nullable String[] val)
+         throws BinaryObjectException {
+         writeFieldId(fieldName, STRING_ARR);
+         writeStringArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeStringArray(@Nullable String[] val) throws BinaryObjectException {
+         doWriteStringArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeUuidArray(String fieldName, @Nullable UUID[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, UUID_ARR);
+         writeUuidArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeUuidArray(@Nullable UUID[] val) throws BinaryObjectException {
+         doWriteUuidArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDateArray(String fieldName, @Nullable Date[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, DATE_ARR);
+         writeDateArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeDateArray(@Nullable Date[] val) throws BinaryObjectException {
+         doWriteDateArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeTimestampArray(String fieldName, @Nullable Timestamp[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, TIMESTAMP_ARR);
+         writeTimestampArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeTimestampArray(@Nullable Timestamp[] val) throws BinaryObjectException {
+         doWriteTimestampArray(val);
+     }
+ 
+      /** {@inheritDoc} */
+     @Override public void writeObjectArray(String fieldName, @Nullable Object[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, OBJ_ARR);
+         writeObjectArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeObjectArray(@Nullable Object[] val) throws BinaryObjectException {
+         doWriteObjectArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T> void writeCollection(String fieldName, @Nullable Collection<T> col)
+         throws BinaryObjectException {
+         writeFieldId(fieldName, COL);
+         writeCollectionField(col);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T> void writeCollection(@Nullable Collection<T> col) throws BinaryObjectException {
+         doWriteCollection(col);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <K, V> void writeMap(String fieldName, @Nullable Map<K, V> map)
+         throws BinaryObjectException {
+         writeFieldId(fieldName, MAP);
+         writeMapField(map);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <K, V> void writeMap(@Nullable Map<K, V> map) throws BinaryObjectException {
+         doWriteMap(map);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T extends Enum<?>> void writeEnum(String fieldName, T val) throws BinaryObjectException {
+         writeFieldId(fieldName, ENUM);
+         writeEnumField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T extends Enum<?>> void writeEnum(T val) throws BinaryObjectException {
+         doWriteEnum(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T extends Enum<?>> void writeEnumArray(String fieldName, T[] val) throws BinaryObjectException {
+         writeFieldId(fieldName, ENUM_ARR);
+         writeEnumArrayField(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T extends Enum<?>> void writeEnumArray(T[] val) throws BinaryObjectException {
+         doWriteEnumArray(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public BinaryRawWriter rawWriter() {
+         if (rawOffPos == 0)
+             rawOffPos = out.position();
+ 
+         return this;
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public PortableOutputStream 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);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeShort(int v) throws IOException {
+         doWriteShort((short) v);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeChar(int v) throws IOException {
+         doWriteChar((char) v);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void write(int b) throws IOException {
+         doWriteByte((byte) b);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void flush() throws IOException {
+         // No-op.
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public int reserveInt() {
+         return reserve(LEN_INT);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public void writeInt(int pos, int val) throws BinaryObjectException {
+         out.writeInt(pos, val);
+     }
+ 
+     /**
+      * @param fieldName Field name.
+      * @throws org.apache.ignite.binary.BinaryObjectException If fields are not allowed.
+      */
+     private void writeFieldId(String fieldName, byte fieldType) throws BinaryObjectException {
+         A.notNull(fieldName, "fieldName");
+ 
+         if (rawOffPos != 0)
+             throw new BinaryObjectException("Individual field can't be written after raw writer is acquired " +
+                 "via rawWriter() method. Consider fixing serialization logic for class: " + cls.getName());
+ 
+         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;
+ 
+         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);
+ 
+         if (handle >= 0) {
+             doWriteByte(GridPortableMarshaller.HANDLE);
+             doWriteInt(handle);
+ 
+             return true;
+         }
+ 
+         return false;
+     }
+ 
+     /**
+      * Create new writer with same context.
+      *
+      * @param typeId type
+      * @return New writer.
+      */
+     public BinaryWriterExImpl newWriter(int typeId) {
+         BinaryWriterExImpl res = new BinaryWriterExImpl(ctx, out, handles);
+ 
+         res.typeId = typeId;
+ 
+         return res;
+     }
+ 
+     /**
+      * @return Portable context.
+      */
+     public PortableContext context() {
+         return ctx;
+     }
+ 
+     /**
+      * Schema holder.
+      */
+     private static class SchemaHolder {
+         /** Grow step. */
+         private static final int GROW_STEP = 64;
+ 
+         /** Maximum stable size. */
+         private static final int MAX_SIZE = 1024;
+ 
+         /** Data. */
+         private int[] data;
+ 
+         /** Index. */
+         private int idx;
+ 
+         /**
+          * Constructor.
+          */
+         public SchemaHolder() {
+             data = new int[GROW_STEP];
+         }
+ 
+         /**
+          * Push another frame.
+          *
+          * @param id Field ID.
+          * @param off Field offset.
+          */
+         public void push(int id, int off) {
+             if (idx == data.length) {
+                 int[] data0 = new int[data.length + GROW_STEP];
+ 
+                 System.arraycopy(data, 0, data0, 0, data.length);
+ 
+                 data = data0;
+             }
+ 
+             data[idx] = id;
+             data[idx + 1] = off;
+ 
+             idx += 2;
+         }
+ 
+         /**
+          * Write collected frames and pop them.
+          *
+          * @param writer Writer.
+          * @param fieldCnt Count.
+          * @return Amount of bytes dedicated to
+          */
+         public int write(BinaryWriterExImpl writer, int fieldCnt) {
+             int startIdx = idx - fieldCnt * 2;
+ 
+             assert startIdx >= 0;
+ 
+             int lastOffset = data[idx - 1];
+ 
+             int res;
+ 
+             if (lastOffset < MAX_OFFSET_1) {
+                 for (int idx0 = startIdx; idx0 < idx; ) {
+                     writer.writeInt(data[idx0++]);
+                     writer.writeByte((byte) data[idx0++]);
+                 }
+ 
+                 res = PortableUtils.OFFSET_1;
+             }
+             else if (lastOffset < MAX_OFFSET_2) {
+                 for (int idx0 = startIdx; idx0 < idx; ) {
+                     writer.writeInt(data[idx0++]);
+                     writer.writeShort((short)data[idx0++]);
+                 }
+ 
+                 res = PortableUtils.OFFSET_2;
+             }
+             else {
+                 for (int idx0 = startIdx; idx0 < idx; ) {
+                     writer.writeInt(data[idx0++]);
+                     writer.writeInt(data[idx0++]);
+                 }
+ 
+                 res = PortableUtils.OFFSET_4;
+             }
+ 
+             return res;
+         }
+ 
+         /**
+          * Pop current object's frame.
+          */
+         public void pop(int fieldCnt) {
+             idx = idx - fieldCnt * 2;
+ 
+             // 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/2c9378a8/modules/core/src/main/java/org/apache/ignite/internal/portable/PortableClassDescriptor.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/ignite/blob/2c9378a8/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 970aeea,f721f12..f5e0ce3
--- 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
@@@ -850,20 -846,6 +846,13 @@@ public class PortableContext implement
      }
  
      /**
 +     * @return Whether field IDs should be skipped in footer or not.
 +     */
 +    public boolean isNoFieldIds() {
 +        return false; // TODO: IGNITE-1816: Take from config.
 +    }
 +
 +    /**
-      * @return Whether to convert string to UTF8 bytes.
-      */
-     public boolean isConvertString() {
-         return convertStrings;
-     }
- 
-     /**
       * Get schema registry for type ID.
       *
       * @param typeId Type ID.

http://git-wip-us.apache.org/repos/asf/ignite/blob/2c9378a8/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 b760849,31f2bf9..8d2fab5
--- 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
@@@ -118,18 -117,91 +120,18 @@@ public class PortableUtils 
  
      /** Offset which fits into 4 bytes. */
      public static final int OFFSET_4 = 4;
 -
 -    /** Field type names. */
 -    private static final String[] FIELD_TYPE_NAMES;
 -
 -    static {
 -        FIELD_TYPE_NAMES = new String[104];
 -
 -        FIELD_TYPE_NAMES[BYTE] = "byte";
 -        FIELD_TYPE_NAMES[SHORT] = "short";
 -        FIELD_TYPE_NAMES[INT] = "int";
 -        FIELD_TYPE_NAMES[LONG] = "long";
 -        FIELD_TYPE_NAMES[BOOLEAN] = "boolean";
 -        FIELD_TYPE_NAMES[FLOAT] = "float";
 -        FIELD_TYPE_NAMES[DOUBLE] = "double";
 -        FIELD_TYPE_NAMES[CHAR] = "char";
 -        FIELD_TYPE_NAMES[UUID] = "UUID";
 -        FIELD_TYPE_NAMES[DECIMAL] = "decimal";
 -        FIELD_TYPE_NAMES[STRING] = "String";
 -        FIELD_TYPE_NAMES[DATE] = "Date";
 -        FIELD_TYPE_NAMES[TIMESTAMP] = "Timestamp";
 -        FIELD_TYPE_NAMES[ENUM] = "Enum";
 -        FIELD_TYPE_NAMES[OBJ] = "Object";
 -        FIELD_TYPE_NAMES[PORTABLE_OBJ] = "Object";
 -        FIELD_TYPE_NAMES[COL] = "Collection";
 -        FIELD_TYPE_NAMES[MAP] = "Map";
 -        FIELD_TYPE_NAMES[MAP_ENTRY] = "Entry";
 -        FIELD_TYPE_NAMES[CLASS] = "Class";
 -        FIELD_TYPE_NAMES[BYTE_ARR] = "byte[]";
 -        FIELD_TYPE_NAMES[SHORT_ARR] = "short[]";
 -        FIELD_TYPE_NAMES[INT_ARR] = "int[]";
 -        FIELD_TYPE_NAMES[LONG_ARR] = "long[]";
 -        FIELD_TYPE_NAMES[BOOLEAN_ARR] = "boolean[]";
 -        FIELD_TYPE_NAMES[FLOAT_ARR] = "float[]";
 -        FIELD_TYPE_NAMES[DOUBLE_ARR] = "double[]";
 -        FIELD_TYPE_NAMES[CHAR_ARR] = "char[]";
 -        FIELD_TYPE_NAMES[UUID_ARR] = "UUID[]";
 -        FIELD_TYPE_NAMES[DECIMAL_ARR] = "decimal[]";
 -        FIELD_TYPE_NAMES[STRING_ARR] = "String[]";
 -        FIELD_TYPE_NAMES[DATE_ARR] = "Date[]";
 -        FIELD_TYPE_NAMES[TIMESTAMP_ARR] = "Timestamp[]";
 -        FIELD_TYPE_NAMES[OBJ_ARR] = "Object[]";
 -        FIELD_TYPE_NAMES[ENUM_ARR] = "Enum[]";
 -    }
 -
 -    /**
 -     * @param typeName Field type name.
 -     * @return Field type ID;
 -     */
 -    @SuppressWarnings("StringEquality")
 -    public static int fieldTypeId(String typeName) {
 -        for (int i = 0; i < FIELD_TYPE_NAMES.length; i++) {
 -            String typeName0 = FIELD_TYPE_NAMES[i];
 -
 -            if (typeName.equals(typeName0))
 -                return i;
 -        }
--
 -        throw new IllegalArgumentException("Invalid metadata type name: " + typeName);
 -    }
++    
 +    /** Length of a single field ID value. */
 +    public static final int FIELD_ID_LEN = 4;
  
      /**
 -     * @param typeId Field type ID.
 -     * @return Field type name.
 -     */
 -    public static String fieldTypeName(int typeId) {
 -        assert typeId >= 0 && typeId < FIELD_TYPE_NAMES.length : typeId;
 -
 -        String typeName = FIELD_TYPE_NAMES[typeId];
 -
 -        assert typeName != null : typeId;
 -
 -        return typeName;
 -    }
 -
 -    /**
 -     * @param typeIds Field type IDs.
 -     * @return Field type names.
 +     * Check if user type flag is set.
 +     *
 +     * @param flags Flags.
 +     * @return {@code True} if set.
       */
 -    public static Map<String, String> fieldTypeNames(Map<String, Integer> typeIds) {
 -        Map<String, String> names = U.newHashMap(typeIds.size());
 -
 -        for (Map.Entry<String, Integer> e : typeIds.entrySet())
 -            names.put(e.getKey(), fieldTypeName(e.getValue()));
 -
 -        return names;
 +    public static boolean isUserType(short flags) {
 +        return isFlagSet(flags, FLAG_USR_TYP);
      }
  
      /**
@@@ -569,7 -629,8 +555,7 @@@
       * @param clsName Class name (optional).
       * @return Position where length should be written.
       */
-     public static int writeHeader(PortableWriterExImpl writer, int typeId, int hashCode, @Nullable String clsName) {
 -    public static int writeHeader(BinaryWriterExImpl writer, boolean usrTyp, int typeId, int hashCode,
 -        @Nullable String clsName) {
++    public static int writeHeader(BinaryWriterExImpl writer, int typeId, int hashCode, @Nullable String clsName) {
          writer.doWriteByte(GridPortableMarshaller.OBJ);
          writer.doWriteByte(GridPortableMarshaller.PROTO_VER);
  

http://git-wip-us.apache.org/repos/asf/ignite/blob/2c9378a8/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
----------------------------------------------------------------------
diff --cc modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
index 0000000,ca8f09b..2cc597f
mode 000000,100644..100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/portable/builder/BinaryObjectBuilderImpl.java
@@@ -1,0 -1,555 +1,559 @@@
+ /*
+  * 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.builder;
+ 
+ import org.apache.ignite.binary.BinaryInvalidTypeException;
+ import org.apache.ignite.binary.BinaryObject;
+ import org.apache.ignite.binary.BinaryObjectBuilder;
+ import org.apache.ignite.binary.BinaryObjectException;
+ import org.apache.ignite.binary.BinaryType;
+ import org.apache.ignite.internal.portable.BinaryObjectImpl;
+ import org.apache.ignite.internal.portable.BinaryObjectOffheapImpl;
+ import org.apache.ignite.internal.portable.BinaryWriterExImpl;
+ import org.apache.ignite.internal.portable.GridPortableMarshaller;
+ import org.apache.ignite.internal.portable.PortableContext;
+ import org.apache.ignite.internal.portable.PortableUtils;
+ import org.apache.ignite.internal.util.GridArgumentCheck;
+ 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.jetbrains.annotations.Nullable;
+ 
+ import java.util.Collections;
+ import java.util.HashMap;
+ import java.util.LinkedHashMap;
+ import java.util.Map;
+ import java.util.Set;
+ 
+ import static org.apache.ignite.internal.portable.GridPortableMarshaller.DFLT_HDR_LEN;
+ import static org.apache.ignite.internal.portable.GridPortableMarshaller.FLAGS_POS;
+ import static org.apache.ignite.internal.portable.GridPortableMarshaller.HASH_CODE_POS;
+ import static org.apache.ignite.internal.portable.GridPortableMarshaller.PROTO_VER_POS;
+ import static org.apache.ignite.internal.portable.GridPortableMarshaller.TYPE_ID_POS;
+ import static org.apache.ignite.internal.portable.GridPortableMarshaller.UNREGISTERED_TYPE_ID;
+ 
+ /**
+  *
+  */
+ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
+     /** */
+     private static final Object REMOVED_FIELD_MARKER = new Object();
+ 
+     /** */
+     private final PortableContext ctx;
+ 
+     /** */
+     private final int typeId;
+ 
+     /** May be null. */
+     private String typeName;
+ 
+     /** May be null. */
+     private String clsNameToWrite;
+ 
+     /** */
+     private boolean registeredType = true;
+ 
+     /** */
+     private Map<String, Object> assignedVals;
+ 
+     /** */
+     private Map<Integer, Object> readCache;
+ 
+     /** Position of object in source array, or -1 if object is not created from PortableObject. */
+     private final int start;
+ 
+     /** Flags. */
+     private final short flags;
+ 
+     /** Total header length */
+     private final int hdrLen;
+ 
+     /** Context of PortableObject reading process. Or {@code null} if object is not created from PortableObject. */
+     private final PortableBuilderReader reader;
+ 
+     /** */
+     private int hashCode;
+ 
+     /**
+      * @param clsName Class name.
+      * @param ctx Portable context.
+      */
+     public BinaryObjectBuilderImpl(PortableContext ctx, String clsName) {
+         this(ctx, ctx.typeId(clsName), PortableContext.typeName(clsName));
+     }
+ 
+     /**
+      * @param typeName Type name.
+      * @param ctx Context.
+      * @param typeId Type id.
+      */
+     public BinaryObjectBuilderImpl(PortableContext ctx, int typeId, String typeName) {
+         this.typeId = typeId;
+         this.typeName = typeName;
+         this.ctx = ctx;
+ 
+         start = -1;
+         flags = -1;
+         reader = null;
+         hdrLen = DFLT_HDR_LEN;
+ 
+         readCache = Collections.emptyMap();
+     }
+ 
+     /**
+      * @param obj Object to wrap.
+      */
+     public BinaryObjectBuilderImpl(BinaryObjectImpl obj) {
+         this(new PortableBuilderReader(obj), obj.start());
+ 
+         reader.registerObject(this);
+     }
+ 
+     /**
+      * @param reader ctx
+      * @param start Start.
+      */
+     BinaryObjectBuilderImpl(PortableBuilderReader reader, int start) {
+         this.reader = reader;
+         this.start = start;
+         this.flags = reader.readShortPositioned(start + FLAGS_POS);
+ 
+         byte ver = reader.readBytePositioned(start + PROTO_VER_POS);
+ 
+         PortableUtils.checkProtocolVersion(ver);
+ 
+         int typeId = reader.readIntPositioned(start + TYPE_ID_POS);
+         ctx = reader.portableContext();
+         hashCode = reader.readIntPositioned(start + HASH_CODE_POS);
+ 
+         if (typeId == UNREGISTERED_TYPE_ID) {
+             int mark = reader.position();
+ 
+             reader.position(start + DFLT_HDR_LEN);
+ 
+             clsNameToWrite = reader.readString();
+ 
+             Class cls;
+ 
+             try {
+                 // TODO: IGNITE-1272 - Is class loader needed here?
+                 cls = U.forName(clsNameToWrite, null);
+             }
+             catch (ClassNotFoundException e) {
+                 throw new BinaryInvalidTypeException("Failed to load the class: " + clsNameToWrite, e);
+             }
+ 
+             this.typeId = ctx.descriptorForClass(cls).typeId();
+ 
+             registeredType = false;
+ 
+             hdrLen = reader.position() - mark;
+ 
+             reader.position(mark);
+         }
+         else {
+             this.typeId = typeId;
+             hdrLen = DFLT_HDR_LEN;
+         }
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public BinaryObject build() {
+         try (BinaryWriterExImpl writer = new BinaryWriterExImpl(ctx, typeId, false)) {
+ 
+             PortableBuilderSerializer serializationCtx = new PortableBuilderSerializer();
+ 
+             serializationCtx.registerObjectWriting(this, 0);
+ 
+             serializeTo(writer, serializationCtx);
+ 
+             byte[] arr = writer.array();
+ 
+             return new BinaryObjectImpl(ctx, arr, 0);
+         }
+     }
+ 
+     /**
+      * @param writer Writer.
+      * @param serializer Serializer.
+      */
+     void serializeTo(BinaryWriterExImpl writer, PortableBuilderSerializer serializer) {
+         try {
+             PortableUtils.writeHeader(writer,
 -                true,
+                 registeredType ? typeId : UNREGISTERED_TYPE_ID,
+                 hashCode,
 -                registeredType ? null : clsNameToWrite);
++                registeredType ? null : clsNameToWrite
++            );
+ 
+             Set<Integer> remainsFlds = null;
+ 
+             if (reader != null) {
+                 Map<Integer, Object> assignedFldsById;
+ 
+                 if (assignedVals != null) {
+                     assignedFldsById = U.newHashMap(assignedVals.size());
+ 
+                     for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
+                         int fldId = ctx.fieldId(typeId, entry.getKey());
+ 
+                         assignedFldsById.put(fldId, entry.getValue());
+                     }
+ 
+                     remainsFlds = assignedFldsById.keySet();
+                 } else
+                     assignedFldsById = Collections.emptyMap();
+ 
+                 // Get footer details.
 -                int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
++                int fieldIdLen = PortableUtils.fieldIdLength(flags);
++                int fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
+ 
 -                IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetSize);
++                IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetLen);
+ 
+                 int footerPos = footer.get1();
+                 int footerEnd = footer.get2();
+ 
+                 // Get raw position.
 -                int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
++                int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetLen);
+ 
+                 // Position reader on data.
+                 reader.position(start + hdrLen);
+ 
 -                while (reader.position() + 4 < rawPos) {
++                while (reader.position() + fieldIdLen < rawPos) {
+                     int fieldId = reader.readIntPositioned(footerPos);
 -                    int fieldLen = fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldOffsetSize).get2();
++                    int fieldLen =
++                        fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldIdLen, fieldOffsetLen).get2();
+ 
+                     int postPos = reader.position() + fieldLen; // Position where reader will be placed afterwards.
+ 
 -                    footerPos += 4 + fieldOffsetSize;
++                    footerPos += fieldIdLen + fieldOffsetLen;
+ 
+                     if (assignedFldsById.containsKey(fieldId)) {
+                         Object assignedVal = assignedFldsById.remove(fieldId);
+ 
+                         if (assignedVal != REMOVED_FIELD_MARKER) {
+                             writer.writeFieldId(fieldId);
+ 
+                             serializer.writeValue(writer, assignedVal);
+                         }
+                     }
+                     else {
+                         int type = fieldLen != 0 ? reader.readByte(0) : 0;
+ 
+                         if (fieldLen != 0 && !PortableUtils.isPlainArrayType(type) && PortableUtils.isPlainType(type)) {
+                             writer.writeFieldId(fieldId);
+ 
+                             writer.write(reader.array(), reader.position(), fieldLen);
+                         }
+                         else {
+                             writer.writeFieldId(fieldId);
+ 
+                             Object val;
+ 
+                             if (fieldLen == 0)
+                                 val = null;
+                             else if (readCache == null) {
+                                 val = reader.parseValue();
+ 
+                                 assert reader.position() == postPos;
+                             }
+                             else
+                                 val = readCache.get(fieldId);
+ 
+                             serializer.writeValue(writer, val);
+                         }
+                     }
+ 
+                     reader.position(postPos);
+                 }
+             }
+ 
+             if (assignedVals != null && (remainsFlds == null || !remainsFlds.isEmpty())) {
+                 BinaryType metadata = ctx.metaData(typeId);
+ 
+                 Map<String, Integer> newFldsMetadata = null;
+ 
+                 for (Map.Entry<String, Object> entry : assignedVals.entrySet()) {
+                     Object val = entry.getValue();
+ 
+                     if (val == REMOVED_FIELD_MARKER)
+                         continue;
+ 
+                     String name = entry.getKey();
+ 
+                     int fldId = ctx.fieldId(typeId, name);
+ 
+                     if (remainsFlds != null && !remainsFlds.contains(fldId))
+                         continue;
+ 
+                     writer.writeFieldId(fldId);
+ 
+                     serializer.writeValue(writer, val);
+ 
+                     String oldFldTypeName = metadata == null ? null : metadata.fieldTypeName(name);
+ 
+                     int newFldTypeId;
+ 
+                     if (val instanceof PortableValueWithType)
+                         newFldTypeId = ((PortableValueWithType) val).typeId();
+                     else
+                         newFldTypeId = PortableUtils.typeByClass(val.getClass());
+ 
+                     String newFldTypeName = PortableUtils.fieldTypeName(newFldTypeId);
+ 
+                     if (oldFldTypeName == null) {
+                         // It's a new field, we have to add it to metadata.
+ 
+                         if (newFldsMetadata == null)
+                             newFldsMetadata = new HashMap<>();
+ 
+                         newFldsMetadata.put(name, PortableUtils.fieldTypeId(newFldTypeName));
+                     }
+                     else {
+                         String objTypeName = PortableUtils.fieldTypeName(GridPortableMarshaller.OBJ);
+ 
+                         if (!objTypeName.equals(oldFldTypeName) && !oldFldTypeName.equals(newFldTypeName)) {
+                             throw new BinaryObjectException(
+                                 "Wrong value has been set [" +
+                                     "typeName=" + (typeName == null ? metadata.typeName() : typeName) +
+                                     ", fieldName=" + name +
+                                     ", fieldType=" + oldFldTypeName +
+                                     ", assignedValueType=" + newFldTypeName + ']'
+                             );
+                         }
+                     }
+                 }
+ 
+                 if (newFldsMetadata != null) {
+                     String typeName = this.typeName;
+ 
+                     if (typeName == null) {
+                         assert metadata != null;
+ 
+                         typeName = metadata.typeName();
+                     }
+ 
+                     ctx.updateMetaData(typeId, typeName, newFldsMetadata);
+                 }
+             }
+ 
+             if (reader != null) {
+                 // Write raw data if any.
 -                int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
++                int fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
+ 
 -                int rawOff = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
++                int rawOff = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetLen);
+                 int footerStart = PortableUtils.footerStartAbsolute(reader, start);
+ 
+                 if (rawOff < footerStart) {
+                     writer.rawWriter();
+ 
+                     writer.write(reader.array(), rawOff, footerStart - rawOff);
+                 }
+ 
+                 // Shift reader to the end of the object.
+                 reader.position(start + PortableUtils.length(reader, start));
+             }
+ 
+             writer.postWrite(true);
+         }
+         finally {
+             writer.popSchema();
+         }
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public BinaryObjectBuilderImpl hashCode(int hashCode) {
+         this.hashCode = hashCode;
+ 
+         return this;
+     }
+ 
+     /**
+      * Get field position and length.
+      *
+      * @param footerPos Field position inside the footer (absolute).
+      * @param footerEnd Footer end (absolute).
+      * @param rawPos Raw data position (absolute).
 -     * @param fieldOffsetSize Size of field's offset.
++     * @param fieldIdLen Field ID length.
++     * @param fieldOffsetLen Field offset length.
+      * @return Tuple with field position and length.
+      */
+     private IgniteBiTuple<Integer, Integer> fieldPositionAndLength(int footerPos, int footerEnd, int rawPos,
 -        int fieldOffsetSize) {
++        int fieldIdLen, int fieldOffsetLen) {
+         // Get field offset first.
 -        int fieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + 4, fieldOffsetSize);
++        int fieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + fieldIdLen, fieldOffsetLen);
+         int fieldPos = start + fieldOffset;
+ 
+         // Get field length.
+         int fieldLen;
+ 
 -        if (footerPos + 4 + fieldOffsetSize == footerEnd)
++        if (footerPos + fieldIdLen + fieldOffsetLen == footerEnd)
+             // This is the last field, compare to raw offset.
+             fieldLen = rawPos - fieldPos;
+         else {
+             // Field is somewhere in the middle, get difference with the next offset.
 -            int nextFieldOffset = PortableUtils.fieldOffsetRelative(reader, footerPos + 4 + fieldOffsetSize + 4,
 -                fieldOffsetSize);
++            int nextFieldOffset = PortableUtils.fieldOffsetRelative(reader,
++                footerPos + fieldIdLen + fieldOffsetLen + fieldIdLen, fieldOffsetLen);
+ 
+             fieldLen = nextFieldOffset - fieldOffset;
+         }
+ 
+         return F.t(fieldPos, fieldLen);
+     }
+ 
+     /**
+      * Initialize read cache if needed.
+      */
+     private void ensureReadCacheInit() {
+         if (readCache == null) {
 -            int fieldOffsetSize = PortableUtils.fieldOffsetSize(flags);
++            int fieldIdLen = PortableUtils.fieldIdLength(flags);
++            int fieldOffsetLen = PortableUtils.fieldOffsetLength(flags);
+ 
+             Map<Integer, Object> readCache = new HashMap<>();
+ 
 -            IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetSize);
++            IgniteBiTuple<Integer, Integer> footer = PortableUtils.footerAbsolute(reader, start, fieldOffsetLen);
+ 
+             int footerPos = footer.get1();
+             int footerEnd = footer.get2();
+ 
 -            int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetSize);
++            int rawPos = PortableUtils.rawOffsetAbsolute(reader, start, fieldOffsetLen);
+ 
 -            while (footerPos + 4 < footerEnd) {
++            while (footerPos + fieldIdLen < footerEnd) {
+                 int fieldId = reader.readIntPositioned(footerPos);
+ 
+                 IgniteBiTuple<Integer, Integer> posAndLen =
 -                    fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldOffsetSize);
++                    fieldPositionAndLength(footerPos, footerEnd, rawPos, fieldIdLen, fieldOffsetLen);
+ 
+                 Object val = reader.getValueQuickly(posAndLen.get1(), posAndLen.get2());
+ 
+                 readCache.put(fieldId, val);
+ 
+                 // Shift current footer position.
 -                footerPos += 4 + fieldOffsetSize;
++                footerPos += fieldIdLen + fieldOffsetLen;
+             }
+ 
+             this.readCache = readCache;
+         }
+     }
+ 
+     /** {@inheritDoc} */
+     @SuppressWarnings("unchecked")
+     @Override public <T> T getField(String name) {
+         Object val;
+ 
+         if (assignedVals != null && assignedVals.containsKey(name)) {
+             val = assignedVals.get(name);
+ 
+             if (val == REMOVED_FIELD_MARKER)
+                 return null;
+         }
+         else {
+             ensureReadCacheInit();
+ 
+             int fldId = ctx.fieldId(typeId, name);
+ 
+             val = readCache.get(fldId);
+         }
+ 
+         return (T)PortableUtils.unwrapLazy(val);
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public BinaryObjectBuilder setField(String name, Object val) {
+         GridArgumentCheck.notNull(val, name);
+ 
+         if (assignedVals == null)
+             assignedVals = new LinkedHashMap<>();
+ 
+         Object oldVal = assignedVals.put(name, val);
+ 
+         if (oldVal instanceof PortableValueWithType) {
+             ((PortableValueWithType)oldVal).value(val);
+ 
+             assignedVals.put(name, oldVal);
+         }
+ 
+         return this;
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public <T> BinaryObjectBuilder setField(String name, @Nullable T val, Class<? super T> type) {
+         if (assignedVals == null)
+             assignedVals = new LinkedHashMap<>();
+ 
+         //int fldId = ctx.fieldId(typeId, fldName);
+ 
+         assignedVals.put(name, new PortableValueWithType(PortableUtils.typeByClass(type), val));
+ 
+         return this;
+     }
+ 
+     /** {@inheritDoc} */
+     @Override public BinaryObjectBuilder setField(String name, @Nullable BinaryObjectBuilder builder) {
+         if (builder == null)
+             return setField(name, null, Object.class);
+         else
+             return setField(name, (Object)builder);
+     }
+ 
+     /**
+      * Removes field from portable object.
+      *
+      * @param name Field name.
+      * @return {@code this} instance for chaining.
+      */
+     @Override public BinaryObjectBuilderImpl removeField(String name) {
+         if (assignedVals == null)
+             assignedVals = new LinkedHashMap<>();
+ 
+         assignedVals.put(name, REMOVED_FIELD_MARKER);
+ 
+         return this;
+     }
+ 
+     /**
+      * Creates builder initialized by specified portable object.
+      *
+      * @param obj Portable object to initialize builder.
+      * @return New builder.
+      */
+     public static BinaryObjectBuilderImpl wrap(BinaryObject obj) {
+         BinaryObjectImpl heapObj;
+ 
+         if (obj instanceof BinaryObjectOffheapImpl)
+             heapObj = (BinaryObjectImpl)((BinaryObjectOffheapImpl)obj).heapCopy();
+         else
+             heapObj = (BinaryObjectImpl)obj;
+ 
+         return new BinaryObjectBuilderImpl(heapObj);
+     }
+ 
+     /**
+      * @return Object start position in source array.
+      */
+     int start() {
+         return start;
+     }
+ 
+     /**
+      * @return Object type id.
+      */
+     public int typeId() {
+         return typeId;
+     }
+ }


Mime
View raw message