You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2015/11/19 15:07:53 UTC

[04/13] ignite git commit: IGNITE-1816: Implemented compact footers.

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b4a8f83/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java
new file mode 100644
index 0000000..0e31451
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderAdditionalSelfTest.java
@@ -0,0 +1,1291 @@
+/*
+ * 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 com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteBinary;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.portable.builder.PortableBuilderEnum;
+import org.apache.ignite.internal.portable.builder.BinaryObjectBuilderImpl;
+import org.apache.ignite.internal.portable.mutabletest.GridBinaryMarshalerAwareTestClass;
+import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
+import org.apache.ignite.internal.processors.cache.portable.IgniteBinaryImpl;
+import org.apache.ignite.internal.util.lang.GridMapEntry;
+import org.apache.ignite.marshaller.portable.PortableMarshaller;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Assert;
+
+import static org.apache.ignite.cache.CacheMode.REPLICATED;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.Address;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.AddressBook;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.Company;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectAllTypes;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectArrayList;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectContainer;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectEnum;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectInner;
+import static org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectOuter;
+
+/**
+ *
+ */
+public class BinaryObjectBuilderAdditionalSelfTest extends GridCommonAbstractTest {
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        CacheConfiguration cacheCfg = new CacheConfiguration();
+
+        cacheCfg.setCacheMode(REPLICATED);
+
+        cfg.setCacheConfiguration(cacheCfg);
+
+        PortableMarshaller marsh = new PortableMarshaller();
+
+        marsh.setCompactFooter(compactFooter());
+
+        marsh.setClassNames(Arrays.asList("org.apache.ignite.internal.portable.mutabletest.*"));
+
+        cfg.setMarshaller(marsh);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrids(1);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        jcache(0).clear();
+    }
+
+    /**
+     * @return Compact footer.
+     */
+    protected boolean compactFooter() {
+        return true;
+    }
+
+    /**
+     * @return Portables API.
+     */
+    protected IgniteBinary portables() {
+        return grid(0).binary();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testSimpleTypeFieldRead() throws Exception {
+        TestObjectAllTypes exp = new TestObjectAllTypes();
+
+        exp.setDefaultData();
+
+        BinaryObjectBuilder mutPo = wrap(exp);
+
+        for (Field field : TestObjectAllTypes.class.getDeclaredFields()) {
+            Object expVal = field.get(exp);
+            Object actVal = mutPo.getField(field.getName());
+
+            switch (field.getName()) {
+                case "anEnum":
+                    assertEquals(((PortableBuilderEnum)actVal).getOrdinal(), ((Enum)expVal).ordinal());
+                    break;
+
+                case "enumArr": {
+                    PortableBuilderEnum[] actArr = (PortableBuilderEnum[])actVal;
+                    Enum[] expArr = (Enum[])expVal;
+
+                    assertEquals(expArr.length, actArr.length);
+
+                    for (int i = 0; i < actArr.length; i++)
+                        assertEquals(expArr[i].ordinal(), actArr[i].getOrdinal());
+
+                    break;
+                }
+
+                case "entry":
+                    assertEquals(((Map.Entry)expVal).getKey(), ((Map.Entry)actVal).getKey());
+                    assertEquals(((Map.Entry)expVal).getValue(), ((Map.Entry)actVal).getValue());
+                    break;
+
+                default:
+                    assertTrue(field.getName(), Objects.deepEquals(expVal, actVal));
+                    break;
+            }
+        }
+    }
+
+    /**
+     *
+     */
+    public void testSimpleTypeFieldSerialize() {
+        TestObjectAllTypes exp = new TestObjectAllTypes();
+
+        exp.setDefaultData();
+
+        BinaryObjectBuilderImpl mutPo = wrap(exp);
+
+        TestObjectAllTypes res = mutPo.build().deserialize();
+
+        GridTestUtils.deepEquals(exp, res);
+    }
+
+    /**
+     * @throws Exception If any error occurs.
+     */
+    public void testSimpleTypeFieldOverride() throws Exception {
+        TestObjectAllTypes exp = new TestObjectAllTypes();
+
+        exp.setDefaultData();
+
+        BinaryObjectBuilderImpl mutPo = wrap(new TestObjectAllTypes());
+
+        for (Field field : TestObjectAllTypes.class.getDeclaredFields())
+            mutPo.setField(field.getName(), field.get(exp));
+
+        TestObjectAllTypes res = mutPo.build().deserialize();
+
+        GridTestUtils.deepEquals(exp, res);
+    }
+
+    /**
+     * @throws Exception If any error occurs.
+     */
+    public void testSimpleTypeFieldSetNull() throws Exception {
+        TestObjectAllTypes exp = new TestObjectAllTypes();
+
+        exp.setDefaultData();
+
+        BinaryObjectBuilderImpl mutPo = wrap(exp);
+
+        for (Field field : TestObjectAllTypes.class.getDeclaredFields()) {
+            if (!field.getType().isPrimitive())
+                mutPo.setField(field.getName(), null);
+        }
+
+        TestObjectAllTypes res = mutPo.build().deserialize();
+
+        for (Field field : TestObjectAllTypes.class.getDeclaredFields()) {
+            if (!field.getType().isPrimitive())
+                assertNull(field.getName(), field.get(res));
+        }
+    }
+
+    /**
+     * @throws IgniteCheckedException If any error occurs.
+     */
+    public void testMakeCyclicDependency() throws IgniteCheckedException {
+        TestObjectOuter outer = new TestObjectOuter();
+        outer.inner = new TestObjectInner();
+
+        BinaryObjectBuilderImpl mutOuter = wrap(outer);
+
+        BinaryObjectBuilderImpl mutInner = mutOuter.getField("inner");
+
+        mutInner.setField("outer", mutOuter);
+        mutInner.setField("foo", mutInner);
+
+        TestObjectOuter res = mutOuter.build().deserialize();
+
+        assertEquals(res, res.inner.outer);
+        assertEquals(res.inner, res.inner.foo);
+    }
+
+    /**
+     *
+     */
+    public void testDateArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.dateArr =  new Date[] {new Date(11111), new Date(11111), new Date(11111)};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Date[] arr = mutObj.getField("dateArr");
+        arr[0] = new Date(22222);
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new Date[] {new Date(22222), new Date(11111), new Date(11111)}, res.dateArr);
+    }
+
+    /**
+     *
+     */
+    public void testTimestampArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.tsArr = new Timestamp[] {new Timestamp(111222333), new Timestamp(222333444)};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Timestamp[] arr = mutObj.getField("tsArr");
+        arr[0] = new Timestamp(333444555);
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new Timestamp[] {new Timestamp(333444555), new Timestamp(222333444)}, res.tsArr);
+    }
+
+    /**
+     *
+     */
+    public void testUUIDArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.uuidArr = new UUID[] {new UUID(1, 1), new UUID(1, 1), new UUID(1, 1)};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        UUID[] arr = mutObj.getField("uuidArr");
+        arr[0] = new UUID(2, 2);
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new UUID[] {new UUID(2, 2), new UUID(1, 1), new UUID(1, 1)}, res.uuidArr);
+    }
+
+    /**
+     *
+     */
+    public void testDecimalArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.bdArr = new BigDecimal[] {new BigDecimal(1000), new BigDecimal(1000), new BigDecimal(1000)};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        BigDecimal[] arr = mutObj.getField("bdArr");
+        arr[0] = new BigDecimal(2000);
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new BigDecimal[] {new BigDecimal(1000), new BigDecimal(1000), new BigDecimal(1000)},
+            res.bdArr);
+    }
+
+    /**
+     *
+     */
+    public void testBooleanArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.zArr = new boolean[] {false, false, false};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        boolean[] arr = mutObj.getField("zArr");
+        arr[0] = true;
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        boolean[] expected = new boolean[] {true, false, false};
+
+        assertEquals(expected.length, res.zArr.length);
+
+        for (int i = 0; i < expected.length; i++)
+            assertEquals(expected[i], res.zArr[i]);
+    }
+
+    /**
+     *
+     */
+    public void testCharArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.cArr = new char[] {'a', 'a', 'a'};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        char[] arr = mutObj.getField("cArr");
+        arr[0] = 'b';
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new char[] {'b', 'a', 'a'}, res.cArr);
+    }
+
+    /**
+     *
+     */
+    public void testDoubleArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.dArr = new double[] {1.0, 1.0, 1.0};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        double[] arr = mutObj.getField("dArr");
+        arr[0] = 2.0;
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new double[] {2.0, 1.0, 1.0}, res.dArr, 0);
+    }
+
+    /**
+     *
+     */
+    public void testFloatArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.fArr = new float[] {1.0f, 1.0f, 1.0f};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        float[] arr = mutObj.getField("fArr");
+        arr[0] = 2.0f;
+
+        BinaryObject resBinary = mutObj.build();
+
+        TestObjectAllTypes res = resBinary.deserialize();
+
+        Assert.assertArrayEquals(new float[] {2.0f, 1.0f, 1.0f}, res.fArr, 0);
+    }
+
+    /**
+     *
+     */
+    public void testLongArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.lArr = new long[] {1, 1, 1};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        long[] arr = mutObj.getField("lArr");
+        arr[0] = 2;
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new long[] {2, 1, 1}, res.lArr);
+    }
+
+    /**
+     *
+     */
+    public void testIntArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.iArr = new int[] {1, 1, 1};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        int[] arr = mutObj.getField("iArr");
+        arr[0] = 2;
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new int[] {2, 1, 1}, res.iArr);
+    }
+
+    /**
+     *
+     */
+    public void testShortArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.sArr = new short[] {1, 1, 1};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        short[] arr = mutObj.getField("sArr");
+        arr[0] = 2;
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new short[] {2, 1, 1}, res.sArr);
+    }
+
+    /**
+     *
+     */
+    public void testByteArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.bArr = new byte[] {1, 1, 1};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        byte[] arr = mutObj.getField("bArr");
+        arr[0] = 2;
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new byte[] {2, 1, 1}, res.bArr);
+    }
+
+    /**
+     *
+     */
+    public void testStringArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.strArr = new String[] {"a", "a", "a"};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        String[] arr = mutObj.getField("strArr");
+        arr[0] = "b";
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new String[] {"b", "a", "a"}, res.strArr);
+    }
+
+    /**
+     *
+     */
+    public void testModifyObjectArray() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = new Object[] {"a"};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Object[] arr = mutObj.getField("foo");
+
+        Assert.assertArrayEquals(new Object[] {"a"}, arr);
+
+        arr[0] = "b";
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new Object[] {"b"}, (Object[])res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testOverrideObjectArrayField() {
+        BinaryObjectBuilderImpl mutObj = wrap(new TestObjectContainer());
+
+        Object[] createdArr = {mutObj, "a", 1, new String[] {"s", "s"}, new byte[] {1, 2}, new UUID(3, 0)};
+
+        mutObj.setField("foo", createdArr.clone());
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        createdArr[0] = res;
+
+        assertTrue(Objects.deepEquals(createdArr, res.foo));
+    }
+
+    /**
+     *
+     */
+    public void testDeepArray() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = new Object[] {new Object[] {"a", obj}};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Object[] arr = (Object[])mutObj.<Object[]>getField("foo")[0];
+
+        assertEquals("a", arr[0]);
+        assertSame(mutObj, arr[1]);
+
+        arr[0] = mutObj;
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        arr = (Object[])((Object[])res.foo)[0];
+
+        assertSame(arr[0], res);
+        assertSame(arr[0], arr[1]);
+    }
+
+    /**
+     *
+     */
+    public void testArrayListRead() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Lists.newArrayList(obj, "a");
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        List<Object> list = mutObj.getField("foo");
+
+        assert list.equals(Lists.newArrayList(mutObj, "a"));
+    }
+
+    /**
+     *
+     */
+    public void testArrayListOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        ArrayList<Object> list = Lists.newArrayList(mutObj, "a", Lists.newArrayList(1, 2));
+
+        mutObj.setField("foo", list);
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        list.set(0, res);
+
+        assertNotSame(list, res.foo);
+        assertEquals(list, res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testArrayListModification() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Lists.newArrayList("a", "b", "c");
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        List<String> list = mutObj.getField("foo");
+
+        list.add("!"); // "a", "b", "c", "!"
+        list.add(0, "_"); // "_", "a", "b", "c", "!"
+
+        String s = list.remove(1); // "_", "b", "c", "!"
+        assertEquals("a", s);
+
+        assertEquals(Arrays.asList("c", "!"), list.subList(2, 4));
+        assertEquals(1, list.indexOf("b"));
+        assertEquals(1, list.lastIndexOf("b"));
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        assertTrue(res.foo instanceof ArrayList);
+        assertEquals(Arrays.asList("_", "b", "c", "!"), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testArrayListClear() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Lists.newArrayList("a", "b", "c");
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        List<String> list = mutObj.getField("foo");
+
+        list.clear();
+
+        assertEquals(Collections.emptyList(), mutObj.build().<TestObjectContainer>deserialize().foo);
+    }
+
+    /**
+     *
+     */
+    public void testArrayListWriteUnmodifiable() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        ArrayList<Object> src = Lists.newArrayList(obj, "a", "b", "c");
+
+        obj.foo = src;
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        TestObjectContainer deserialized = mutObj.build().deserialize();
+
+        List<Object> res = (List<Object>)deserialized.foo;
+
+        src.set(0, deserialized);
+
+        assertEquals(src, res);
+    }
+
+    /**
+     *
+     */
+    public void testLinkedListRead() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Lists.newLinkedList(Arrays.asList(obj, "a"));
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        List<Object> list = mutObj.getField("foo");
+
+        assert list.equals(Lists.newLinkedList(Arrays.asList(mutObj, "a")));
+    }
+
+    /**
+     *
+     */
+    public void testLinkedListOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        List<Object> list = Lists.newLinkedList(Arrays.asList(mutObj, "a", Lists.newLinkedList(Arrays.asList(1, 2))));
+
+        mutObj.setField("foo", list);
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        list.set(0, res);
+
+        assertNotSame(list, res.foo);
+        assertEquals(list, res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testLinkedListModification() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        obj.foo = Lists.newLinkedList(Arrays.asList("a", "b", "c"));
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        List<String> list = mutObj.getField("foo");
+
+        list.add("!"); // "a", "b", "c", "!"
+        list.add(0, "_"); // "_", "a", "b", "c", "!"
+
+        String s = list.remove(1); // "_", "b", "c", "!"
+        assertEquals("a", s);
+
+        assertEquals(Arrays.asList("c", "!"), list.subList(2, 4));
+        assertEquals(1, list.indexOf("b"));
+        assertEquals(1, list.lastIndexOf("b"));
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        assertTrue(res.foo instanceof LinkedList);
+        assertEquals(Arrays.asList("_", "b", "c", "!"), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testLinkedListWriteUnmodifiable() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        LinkedList<Object> src = Lists.newLinkedList(Arrays.asList(obj, "a", "b", "c"));
+
+        obj.foo = src;
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        TestObjectContainer deserialized = mutObj.build().deserialize();
+
+        List<Object> res = (List<Object>)deserialized.foo;
+
+        src.set(0, deserialized);
+
+        assertEquals(src, res);
+    }
+
+    /**
+     *
+     */
+    public void testHashSetRead() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Sets.newHashSet(obj, "a");
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Set<Object> set = mutObj.getField("foo");
+
+        assert set.equals(Sets.newHashSet(mutObj, "a"));
+    }
+
+    /**
+     *
+     */
+    public void testHashSetOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Set<Object> c = Sets.newHashSet(mutObj, "a", Sets.newHashSet(1, 2));
+
+        mutObj.setField("foo", c);
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        c.remove(mutObj);
+        c.add(res);
+
+        assertNotSame(c, res.foo);
+        assertEquals(c, res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testHashSetModification() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Sets.newHashSet("a", "b", "c");
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Set<String> set = mutObj.getField("foo");
+
+        set.remove("b");
+        set.add("!");
+
+        assertEquals(Sets.newHashSet("a", "!", "c"), set);
+        assertTrue(set.contains("a"));
+        assertTrue(set.contains("!"));
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        assertTrue(res.foo instanceof HashSet);
+        assertEquals(Sets.newHashSet("a", "!", "c"), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testHashSetWriteUnmodifiable() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        Set<Object> src = Sets.newHashSet(obj, "a", "b", "c");
+
+        obj.foo = src;
+
+        TestObjectContainer deserialized = wrap(obj).build().deserialize();
+
+        Set<Object> res = (Set<Object>)deserialized.foo;
+
+        src.remove(obj);
+        src.add(deserialized);
+
+        assertEquals(src, res);
+    }
+
+    /**
+     *
+     */
+    public void testMapRead() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Maps.newHashMap(ImmutableMap.of(obj, "a", "b", obj));
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Map<Object, Object> map = mutObj.getField("foo");
+
+        assert map.equals(ImmutableMap.of(mutObj, "a", "b", mutObj));
+    }
+
+    /**
+     *
+     */
+    public void testMapOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Map<Object, Object> map = Maps.newHashMap(ImmutableMap.of(mutObj, "a", "b", mutObj));
+
+        mutObj.setField("foo", map);
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        assertEquals(ImmutableMap.of(res, "a", "b", res), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testMapModification() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Maps.newHashMap(ImmutableMap.of(1, "a", 2, "b"));
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        Map<Object, Object> map = mutObj.getField("foo");
+
+        map.put(3, mutObj);
+        Object rmv = map.remove(1);
+
+        assertEquals("a", rmv);
+
+        TestObjectContainer res = mutObj.build().deserialize();
+
+        assertEquals(ImmutableMap.of(2, "b", 3, res), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testEnumArrayModification() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+
+        obj.enumArr = new TestObjectEnum[] {TestObjectEnum.A, TestObjectEnum.B};
+
+        BinaryObjectBuilderImpl mutObj = wrap(obj);
+
+        PortableBuilderEnum[] arr = mutObj.getField("enumArr");
+        arr[0] = new PortableBuilderEnum(mutObj.typeId(), TestObjectEnum.B);
+
+        TestObjectAllTypes res = mutObj.build().deserialize();
+
+        Assert.assertArrayEquals(new TestObjectEnum[] {TestObjectEnum.A, TestObjectEnum.B}, res.enumArr);
+    }
+
+    /**
+     *
+     */
+    public void testEditObjectWithRawData() {
+        GridBinaryMarshalerAwareTestClass obj = new GridBinaryMarshalerAwareTestClass();
+
+        obj.s = "a";
+        obj.sRaw = "aa";
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        mutableObj.setField("s", "z");
+
+        GridBinaryMarshalerAwareTestClass res = mutableObj.build().deserialize();
+        assertEquals("z", res.s);
+        assertEquals("aa", res.sRaw);
+    }
+
+    /**
+     *
+     */
+    public void testHashCode() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        assertEquals(obj.hashCode(), mutableObj.build().hashCode());
+
+        mutableObj.hashCode(25);
+
+        assertEquals(25, mutableObj.build().hashCode());
+    }
+
+    /**
+     *
+     */
+    public void testCollectionsInCollection() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = Lists.newArrayList(
+            Lists.newArrayList(1, 2),
+            Lists.newLinkedList(Arrays.asList(1, 2)),
+            Sets.newHashSet("a", "b"),
+            Sets.newLinkedHashSet(Arrays.asList("a", "b")),
+            Maps.newHashMap(ImmutableMap.of(1, "a", 2, "b")));
+
+        TestObjectContainer deserialized = wrap(obj).build().deserialize();
+
+        assertEquals(obj.foo, deserialized.foo);
+    }
+
+    /**
+     *
+     */
+    public void testMapEntryModification() {
+        TestObjectContainer obj = new TestObjectContainer();
+        obj.foo = ImmutableMap.of(1, "a").entrySet().iterator().next();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        Map.Entry<Object, Object> entry = mutableObj.getField("foo");
+
+        assertEquals(1, entry.getKey());
+        assertEquals("a", entry.getValue());
+
+        entry.setValue("b");
+
+        TestObjectContainer res = mutableObj.build().deserialize();
+
+        assertEquals(new GridMapEntry<>(1, "b"), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testMapEntryOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        mutableObj.setField("foo", new GridMapEntry<>(1, "a"));
+
+        TestObjectContainer res = mutableObj.build().deserialize();
+
+        assertEquals(new GridMapEntry<>(1, "a"), res.foo);
+    }
+
+    /**
+     *
+     */
+    public void testMetadataChangingDoublePut() {
+        BinaryObjectBuilderImpl mutableObj = wrap(new TestObjectContainer());
+
+        mutableObj.setField("xx567", "a");
+        mutableObj.setField("xx567", "b");
+
+        mutableObj.build();
+
+        BinaryType metadata = portables().metadata(TestObjectContainer.class);
+
+        assertEquals("String", metadata.fieldTypeName("xx567"));
+    }
+
+    /**
+     *
+     */
+    public void testMetadataChangingDoublePut2() {
+        BinaryObjectBuilderImpl mutableObj = wrap(new TestObjectContainer());
+
+        mutableObj.setField("xx567", "a");
+        mutableObj.setField("xx567", "b");
+
+        mutableObj.build();
+
+        BinaryType metadata = portables().metadata(TestObjectContainer.class);
+
+        assertEquals("String", metadata.fieldTypeName("xx567"));
+    }
+
+    /**
+     *
+     */
+    public void testMetadataChanging() {
+        TestObjectContainer c = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(c);
+
+        mutableObj.setField("intField", 1);
+        mutableObj.setField("intArrField", new int[] {1});
+        mutableObj.setField("arrField", new String[] {"1"});
+        mutableObj.setField("strField", "1");
+        mutableObj.setField("colField", Lists.newArrayList("1"));
+        mutableObj.setField("mapField", Maps.newHashMap(ImmutableMap.of(1, "1")));
+        mutableObj.setField("enumField", TestObjectEnum.A);
+        mutableObj.setField("enumArrField", new Enum[] {TestObjectEnum.A});
+
+        mutableObj.build();
+
+        BinaryType metadata = portables().metadata(c.getClass());
+
+        assertTrue(metadata.fieldNames().containsAll(Arrays.asList("intField", "intArrField", "arrField", "strField",
+            "colField", "mapField", "enumField", "enumArrField")));
+
+        assertEquals("int", metadata.fieldTypeName("intField"));
+        assertEquals("int[]", metadata.fieldTypeName("intArrField"));
+        assertEquals("String[]", metadata.fieldTypeName("arrField"));
+        assertEquals("String", metadata.fieldTypeName("strField"));
+        assertEquals("Collection", metadata.fieldTypeName("colField"));
+        assertEquals("Map", metadata.fieldTypeName("mapField"));
+        assertEquals("Enum", metadata.fieldTypeName("enumField"));
+        assertEquals("Enum[]", metadata.fieldTypeName("enumArrField"));
+    }
+
+    /**
+     *
+     */
+    public void testDateInObjectField() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        obj.foo = new Date();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        assertEquals(Date.class, mutableObj.getField("foo").getClass());
+    }
+
+    /**
+     *
+     */
+    public void testTimestampInObjectField() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        obj.foo = new Timestamp(100020003);
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        assertEquals(Timestamp.class, mutableObj.getField("foo").getClass());
+    }
+
+    /**
+     *
+     */
+    public void testDateInCollection() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        obj.foo = Lists.newArrayList(new Date());
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        assertEquals(Date.class, ((List<?>)mutableObj.getField("foo")).get(0).getClass());
+    }
+
+    /**
+     *
+     */
+    public void testTimestampInCollection() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        obj.foo = Lists.newArrayList(new Timestamp(100020003));
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        assertEquals(Timestamp.class, ((List<?>)mutableObj.getField("foo")).get(0).getClass());
+    }
+
+    /**
+     *
+     */
+    @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
+    public void testDateArrayOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        Date[] arr = { new Date() };
+
+        mutableObj.setField("foo", arr);
+
+        TestObjectContainer res = mutableObj.build().deserialize();
+
+        assertEquals(Date[].class, res.foo.getClass());
+        assertTrue(Objects.deepEquals(arr, res.foo));
+    }
+
+    /**
+     *
+     */
+    @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
+    public void testTimestampArrayOverride() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl mutableObj = wrap(obj);
+
+        Timestamp[] arr = { new Timestamp(100020003) };
+
+        mutableObj.setField("foo", arr);
+
+        TestObjectContainer res = mutableObj.build().deserialize();
+
+        assertEquals(Timestamp[].class, res.foo.getClass());
+        assertTrue(Objects.deepEquals(arr, res.foo));
+    }
+
+    /**
+     *
+     */
+    public void testChangeMap() {
+        AddressBook addrBook = new AddressBook();
+
+        addrBook.addCompany(new Company(1, "Google inc", 100, new Address("Saint-Petersburg", "Torzhkovskya", 1, 53), "occupation"));
+        addrBook.addCompany(new Company(2, "Apple inc", 100, new Address("Saint-Petersburg", "Torzhkovskya", 1, 54), "occupation"));
+        addrBook.addCompany(new Company(3, "Microsoft", 100, new Address("Saint-Petersburg", "Torzhkovskya", 1, 55), "occupation"));
+        addrBook.addCompany(new Company(4, "Oracle", 100, new Address("Saint-Petersburg", "Nevskiy", 1, 1), "occupation"));
+
+        BinaryObjectBuilderImpl mutableObj = wrap(addrBook);
+
+        Map<String, List<BinaryObjectBuilderImpl>> map = mutableObj.getField("companyByStreet");
+
+        List<BinaryObjectBuilderImpl> list = map.get("Torzhkovskya");
+
+        BinaryObjectBuilderImpl company = list.get(0);
+
+        assert "Google inc".equals(company.<String>getField("name"));
+
+        list.remove(0);
+
+        AddressBook res = mutableObj.build().deserialize();
+
+        assertEquals(Arrays.asList("Nevskiy", "Torzhkovskya"), new ArrayList<>(res.getCompanyByStreet().keySet()));
+
+        List<Company> torzhkovskyaCompanies = res.getCompanyByStreet().get("Torzhkovskya");
+
+        assertEquals(2, torzhkovskyaCompanies.size());
+        assertEquals("Apple inc", torzhkovskyaCompanies.get(0).name);
+    }
+
+    /**
+     *
+     */
+    public void testSavingObjectWithNotZeroStart() {
+        TestObjectOuter out = new TestObjectOuter();
+        TestObjectInner inner = new TestObjectInner();
+
+        out.inner = inner;
+        inner.outer = out;
+
+        BinaryObjectBuilderImpl builder = wrap(out);
+
+        BinaryObjectBuilderImpl innerBuilder = builder.getField("inner");
+
+        TestObjectInner res = innerBuilder.build().deserialize();
+
+        assertSame(res, res.outer.inner);
+    }
+
+    /**
+     *
+     */
+    public void testPortableObjectField() {
+        TestObjectContainer container = new TestObjectContainer(toPortable(new TestObjectArrayList()));
+
+        BinaryObjectBuilderImpl wrapper = wrap(container);
+
+        assertTrue(wrapper.getField("foo") instanceof BinaryObject);
+
+        TestObjectContainer deserialized = wrapper.build().deserialize();
+        assertTrue(deserialized.foo instanceof BinaryObject);
+    }
+
+    /**
+     *
+     */
+    public void testAssignPortableObject() {
+        TestObjectContainer container = new TestObjectContainer();
+
+        BinaryObjectBuilderImpl wrapper = wrap(container);
+
+        wrapper.setField("foo", toPortable(new TestObjectArrayList()));
+
+        TestObjectContainer deserialized = wrapper.build().deserialize();
+        assertTrue(deserialized.foo instanceof TestObjectArrayList);
+    }
+
+    /**
+     *
+     */
+    public void testRemoveFromNewObject() {
+        BinaryObjectBuilderImpl wrapper = newWrapper(TestObjectAllTypes.class);
+
+        wrapper.setField("str", "a");
+
+        wrapper.removeField("str");
+
+        assertNull(wrapper.build().<TestObjectAllTypes>deserialize().str);
+    }
+
+    /**
+     *
+     */
+    public void testRemoveFromExistingObject() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+        obj.setDefaultData();
+
+        BinaryObjectBuilderImpl wrapper = wrap(toPortable(obj));
+
+        wrapper.removeField("str");
+
+        assertNull(wrapper.build().<TestObjectAllTypes>deserialize().str);
+    }
+
+    /**
+     *
+     */
+    public void testCyclicArrays() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        Object[] arr1 = new Object[1];
+        Object[] arr2 = new Object[] {arr1};
+
+        arr1[0] = arr2;
+
+        obj.foo = arr1;
+
+        TestObjectContainer res = toPortable(obj).deserialize();
+
+        Object[] resArr = (Object[])res.foo;
+
+        assertSame(((Object[])resArr[0])[0], resArr);
+    }
+
+    /**
+     *
+     */
+    @SuppressWarnings("TypeMayBeWeakened")
+    public void testCyclicArrayList() {
+        TestObjectContainer obj = new TestObjectContainer();
+
+        List<Object> arr1 = new ArrayList<>();
+        List<Object> arr2 = new ArrayList<>();
+
+        arr1.add(arr2);
+        arr2.add(arr1);
+
+        obj.foo = arr1;
+
+        TestObjectContainer res = toPortable(obj).deserialize();
+
+        List<?> resArr = (List<?>)res.foo;
+
+        assertSame(((List<Object>)resArr.get(0)).get(0), resArr);
+    }
+
+    /**
+     * @param obj Object.
+     * @return Object in portable format.
+     */
+    private BinaryObject toPortable(Object obj) {
+        return portables().toBinary(obj);
+    }
+
+    /**
+     * @param obj Object.
+     * @return GridMutablePortableObject.
+     */
+    private BinaryObjectBuilderImpl wrap(Object obj) {
+        return BinaryObjectBuilderImpl.wrap(toPortable(obj));
+    }
+
+    /**
+     * @param aCls Class.
+     * @return Wrapper.
+     */
+    private BinaryObjectBuilderImpl newWrapper(Class<?> aCls) {
+        CacheObjectBinaryProcessorImpl processor = (CacheObjectBinaryProcessorImpl)(
+            (IgniteBinaryImpl)portables()).processor();
+
+        return new BinaryObjectBuilderImpl(processor.portableContext(), processor.typeId(aCls.getName()),
+            aCls.getSimpleName());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/0b4a8f83/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java
new file mode 100644
index 0000000..e88db99
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/portable/BinaryObjectBuilderSelfTest.java
@@ -0,0 +1,1066 @@
+/*
+ * 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 java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteBinary;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.portable.builder.BinaryObjectBuilderImpl;
+import org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectAllTypes;
+import org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectContainer;
+import org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectInner;
+import org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectOuter;
+import org.apache.ignite.internal.portable.mutabletest.GridPortableTestClasses.TestObjectPlainPortable;
+import org.apache.ignite.internal.processors.cache.portable.CacheObjectBinaryProcessorImpl;
+import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.marshaller.portable.PortableMarshaller;
+import org.apache.ignite.binary.BinaryObjectBuilder;
+import org.apache.ignite.binary.BinaryIdMapper;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.binary.BinaryObject;
+import org.apache.ignite.binary.BinaryTypeConfiguration;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import sun.misc.Unsafe;
+
+/**
+ * Portable builder test.
+ */
+public class BinaryObjectBuilderSelfTest extends GridCommonAbstractTest {
+    /** */
+    private static final Unsafe UNSAFE = GridUnsafe.unsafe();
+
+    /** */
+    protected static final long BYTE_ARR_OFF = UNSAFE.arrayBaseOffset(byte[].class);
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        PortableMarshaller marsh = new PortableMarshaller();
+
+        marsh.setCompactFooter(compactFooter());
+
+        marsh.setClassNames(Arrays.asList(Key.class.getName(), Value.class.getName(),
+            "org.gridgain.grid.internal.util.portable.mutabletest.*"));
+
+        BinaryTypeConfiguration customIdMapper = new BinaryTypeConfiguration();
+
+        customIdMapper.setClassName(CustomIdMapper.class.getName());
+        customIdMapper.setIdMapper(new BinaryIdMapper() {
+            @Override public int typeId(String clsName) {
+                return ~PortableContext.DFLT_ID_MAPPER.typeId(clsName);
+            }
+
+            @Override public int fieldId(int typeId, String fieldName) {
+                return typeId + ~PortableContext.DFLT_ID_MAPPER.fieldId(typeId, fieldName);
+            }
+        });
+
+        marsh.setTypeConfigurations(Collections.singleton(customIdMapper));
+
+        cfg.setMarshaller(marsh);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        startGrids(1);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @return Whether to use compact footer.
+     */
+    protected boolean compactFooter() {
+        return true;
+    }
+
+    /**
+     *
+     */
+    public void testAllFieldsSerialization() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+        obj.setDefaultData();
+        obj.enumArr = null;
+
+        TestObjectAllTypes deserialized = builder(toPortable(obj)).build().deserialize();
+
+        GridTestUtils.deepEquals(obj, deserialized);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testByteField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("byteField", (byte)1);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals((byte) 1, po.<Byte>field("byteField").byteValue());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testShortField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("shortField", (short)1);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals((short)1, po.<Short>field("shortField").shortValue());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testIntField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("intField", 1);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(1, po.<Integer>field("intField").intValue());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testLongField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("longField", 1L);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(1L, po.<Long>field("longField").longValue());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testFloatField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("floatField", 1.0f);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(1.0f, po.<Float>field("floatField").floatValue(), 0);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDoubleField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("doubleField", 1.0d);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(1.0d, po.<Double>field("doubleField").doubleValue(), 0);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCharField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("charField", (char)1);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals((char)1, po.<Character>field("charField").charValue());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBooleanField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("booleanField", true);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(po.<Boolean>field("booleanField"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDecimalField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("decimalField", BigDecimal.TEN);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(BigDecimal.TEN, po.<String>field("decimalField"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testStringField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("stringField", "str");
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals("str", po.<String>field("stringField"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDateField() throws Exception {
+        Date date = new Date();
+
+        assertEquals(date, builder("C").setField("d", date).build().<Date>field("d"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testTimestampField() throws Exception {
+        Timestamp ts = new Timestamp(new Date().getTime());
+        ts.setNanos(1000);
+
+        assertEquals(ts, builder("C").setField("t", ts).build().<Timestamp>field("t"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testUuidField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        UUID uuid = UUID.randomUUID();
+
+        builder.setField("uuidField", uuid);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(uuid, po.<UUID>field("uuidField"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testByteArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("byteArrayField", new byte[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new byte[] {1, 2, 3}, po.<byte[]>field("byteArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testShortArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("shortArrayField", new short[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new short[] {1, 2, 3}, po.<short[]>field("shortArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testIntArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("intArrayField", new int[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new int[] {1, 2, 3}, po.<int[]>field("intArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testLongArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("longArrayField", new long[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new long[] {1, 2, 3}, po.<long[]>field("longArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testFloatArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("floatArrayField", new float[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new float[] {1, 2, 3}, po.<float[]>field("floatArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDoubleArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("doubleArrayField", new double[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new double[] {1, 2, 3}, po.<double[]>field("doubleArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCharArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("charArrayField", new char[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new char[] {1, 2, 3}, po.<char[]>field("charArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBooleanArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("booleanArrayField", new boolean[] {true, false});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        boolean[] arr = po.field("booleanArrayField");
+
+        assertEquals(2, arr.length);
+
+        assertTrue(arr[0]);
+        assertFalse(arr[1]);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDecimalArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("decimalArrayField", new BigDecimal[] {BigDecimal.ONE, BigDecimal.TEN});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new BigDecimal[] {BigDecimal.ONE, BigDecimal.TEN}, po.<String[]>field("decimalArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testStringArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("stringArrayField", new String[] {"str1", "str2", "str3"});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(new String[] {"str1", "str2", "str3"}, po.<String[]>field("stringArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDateArrayField() throws Exception {
+        Date date1 = new Date();
+        Date date2 = new Date(date1.getTime() + 1000);
+
+        Date[] dateArr = new Date[] { date1, date2 };
+
+        assertTrue(Arrays.equals(dateArr, builder("C").setField("da", dateArr).build().<Date[]>field("da")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testTimestampArrayField() throws Exception {
+        Timestamp ts1 = new Timestamp(new Date().getTime());
+        Timestamp ts2 = new Timestamp(new Date().getTime() + 1000);
+
+        ts1.setNanos(1000);
+        ts2.setNanos(2000);
+
+        Timestamp[] tsArr = new Timestamp[] { ts1, ts2 };
+
+        assertTrue(Arrays.equals(tsArr, builder("C").setField("ta", tsArr).build().<Timestamp[]>field("ta")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testUuidArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        UUID[] arr = new UUID[] {UUID.randomUUID(), UUID.randomUUID()};
+
+        builder.setField("uuidArrayField", arr);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertTrue(Arrays.equals(arr, po.<UUID[]>field("uuidArrayField")));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testObjectField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("objectField", new Value(1));
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(1, po.<BinaryObject>field("objectField").<Value>deserialize().i);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testObjectArrayField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("objectArrayField", new Value[] {new Value(1), new Value(2)});
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        Object[] arr = po.field("objectArrayField");
+
+        assertEquals(2, arr.length);
+
+        assertEquals(1, ((BinaryObject)arr[0]).<Value>deserialize().i);
+        assertEquals(2, ((BinaryObject)arr[1]).<Value>deserialize().i);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCollectionField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("collectionField", Arrays.asList(new Value(1), new Value(2)));
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        List<BinaryObject> list = po.field("collectionField");
+
+        assertEquals(2, list.size());
+
+        assertEquals(1, list.get(0).<Value>deserialize().i);
+        assertEquals(2, list.get(1).<Value>deserialize().i);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMapField() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("mapField", F.asMap(new Key(1), new Value(1), new Key(2), new Value(2)));
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        Map<BinaryObject, BinaryObject> map = po.field("mapField");
+
+        assertEquals(2, map.size());
+
+        for (Map.Entry<BinaryObject, BinaryObject> e : map.entrySet())
+            assertEquals(e.getKey().<Key>deserialize().i, e.getValue().<Value>deserialize().i);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testSeveralFields() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("i", 111);
+        builder.setField("f", 111.111f);
+        builder.setField("iArr", new int[] {1, 2, 3});
+        builder.setField("obj", new Key(1));
+        builder.setField("col", Arrays.asList(new Value(1), new Value(2)));
+
+        BinaryObject po = builder.build();
+
+        assertEquals("class".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(111, po.<Integer>field("i").intValue());
+        assertEquals(111.111f, po.<Float>field("f").floatValue(), 0);
+        assertTrue(Arrays.equals(new int[] {1, 2, 3}, po.<int[]>field("iArr")));
+        assertEquals(1, po.<BinaryObject>field("obj").<Key>deserialize().i);
+
+        List<BinaryObject> list = po.field("col");
+
+        assertEquals(2, list.size());
+
+        assertEquals(1, list.get(0).<Value>deserialize().i);
+        assertEquals(2, list.get(1).<Value>deserialize().i);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testOffheapPortable() throws Exception {
+        BinaryObjectBuilder builder = builder("Class");
+
+        builder.hashCode(100);
+
+        builder.setField("i", 111);
+        builder.setField("f", 111.111f);
+        builder.setField("iArr", new int[] {1, 2, 3});
+        builder.setField("obj", new Key(1));
+        builder.setField("col", Arrays.asList(new Value(1), new Value(2)));
+
+        BinaryObject po = builder.build();
+
+        byte[] arr = ((CacheObjectBinaryProcessorImpl)(grid(0)).context().cacheObjects()).marshal(po);
+
+        long ptr = UNSAFE.allocateMemory(arr.length + 5);
+
+        try {
+            long ptr0 = ptr;
+
+            UNSAFE.putBoolean(null, ptr0++, false);
+
+            UNSAFE.putInt(ptr0, arr.length);
+
+            UNSAFE.copyMemory(arr, BYTE_ARR_OFF, null, ptr0 + 4, arr.length);
+
+            BinaryObject offheapObj = (BinaryObject)
+                ((CacheObjectBinaryProcessorImpl)(grid(0)).context().cacheObjects()).unmarshal(ptr, false);
+
+            assertEquals(BinaryObjectOffheapImpl.class, offheapObj.getClass());
+
+            assertEquals("class".hashCode(), offheapObj.typeId());
+            assertEquals(100, offheapObj.hashCode());
+
+            assertEquals(111, offheapObj.<Integer>field("i").intValue());
+            assertEquals(111.111f, offheapObj.<Float>field("f").floatValue(), 0);
+            assertTrue(Arrays.equals(new int[] {1, 2, 3}, offheapObj.<int[]>field("iArr")));
+            assertEquals(1, offheapObj.<BinaryObject>field("obj").<Key>deserialize().i);
+
+            List<BinaryObject> list = offheapObj.field("col");
+
+            assertEquals(2, list.size());
+
+            assertEquals(1, list.get(0).<Value>deserialize().i);
+            assertEquals(2, list.get(1).<Value>deserialize().i);
+
+            assertEquals(po, offheapObj);
+            assertEquals(offheapObj, po);
+        }
+        finally {
+            UNSAFE.freeMemory(ptr);
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBuildAndDeserialize() throws Exception {
+        BinaryObjectBuilder builder = builder(Value.class.getName());
+
+        builder.hashCode(100);
+
+        builder.setField("i", 1);
+
+        BinaryObject po = builder.build();
+
+        assertEquals("value".hashCode(), po.typeId());
+        assertEquals(100, po.hashCode());
+
+        assertEquals(1, po.<Value>deserialize().i);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMetaData2() throws Exception {
+        BinaryObjectBuilder builder = builder("org.test.MetaTest2");
+
+        builder.setField("objectField", "a", Object.class);
+
+        BinaryObject po = builder.build();
+
+        BinaryType meta = po.type();
+
+        assertEquals("MetaTest2", meta.typeName());
+        assertEquals("Object", meta.fieldTypeName("objectField"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMetaData() throws Exception {
+        BinaryObjectBuilder builder = builder("org.test.MetaTest");
+
+        builder.hashCode(100);
+
+        builder.setField("intField", 1);
+        builder.setField("byteArrayField", new byte[] {1, 2, 3});
+
+        BinaryObject po = builder.build();
+
+        BinaryType meta = po.type();
+
+        assertEquals("MetaTest", meta.typeName());
+
+        Collection<String> fields = meta.fieldNames();
+
+        assertEquals(2, fields.size());
+
+        assertTrue(fields.contains("intField"));
+        assertTrue(fields.contains("byteArrayField"));
+
+        assertEquals("int", meta.fieldTypeName("intField"));
+        assertEquals("byte[]", meta.fieldTypeName("byteArrayField"));
+
+        builder = builder("org.test.MetaTest");
+
+        builder.hashCode(100);
+
+        builder.setField("intField", 2);
+        builder.setField("uuidField", UUID.randomUUID());
+
+        po = builder.build();
+
+        meta = po.type();
+
+        assertEquals("MetaTest", meta.typeName());
+
+        fields = meta.fieldNames();
+
+        assertEquals(3, fields.size());
+
+        assertTrue(fields.contains("intField"));
+        assertTrue(fields.contains("byteArrayField"));
+        assertTrue(fields.contains("uuidField"));
+
+        assertEquals("int", meta.fieldTypeName("intField"));
+        assertEquals("byte[]", meta.fieldTypeName("byteArrayField"));
+        assertEquals("UUID", meta.fieldTypeName("uuidField"));
+    }
+
+    /**
+     *
+     */
+    public void testGetFromCopiedObj() {
+        BinaryObject objStr = builder(TestObjectAllTypes.class.getName()).setField("str", "aaa").build();
+
+        BinaryObjectBuilderImpl builder = builder(objStr);
+        assertEquals("aaa", builder.getField("str"));
+
+        builder.setField("str", "bbb");
+        assertEquals("bbb", builder.getField("str"));
+
+        assertNull(builder.getField("i_"));
+        assertEquals("bbb", builder.build().<TestObjectAllTypes>deserialize().str);
+    }
+
+    /**
+     *
+     */
+    public void testCopyFromInnerObjects() {
+        ArrayList<Object> list = new ArrayList<>();
+        list.add(new TestObjectAllTypes());
+        list.add(list.get(0));
+
+        TestObjectContainer c = new TestObjectContainer(list);
+
+        BinaryObjectBuilderImpl builder = builder(toPortable(c));
+        builder.<List>getField("foo").add("!!!");
+
+        BinaryObject res = builder.build();
+
+        TestObjectContainer deserialized = res.deserialize();
+
+        List deserializedList = (List)deserialized.foo;
+
+        assertSame(deserializedList.get(0), deserializedList.get(1));
+        assertEquals("!!!", deserializedList.get(2));
+        assertTrue(deserializedList.get(0) instanceof TestObjectAllTypes);
+    }
+
+    /**
+     *
+     */
+    public void testSetPortableObject() {
+        BinaryObject portableObj = builder(TestObjectContainer.class.getName())
+            .setField("foo", toPortable(new TestObjectAllTypes()))
+            .build();
+
+        assertTrue(portableObj.<TestObjectContainer>deserialize().foo instanceof TestObjectAllTypes);
+    }
+
+    /**
+     *
+     */
+    public void testPlainPortableObjectCopyFrom() {
+        TestObjectPlainPortable obj = new TestObjectPlainPortable(toPortable(new TestObjectAllTypes()));
+
+        BinaryObjectBuilderImpl builder = builder(toPortable(obj));
+        assertTrue(builder.getField("plainPortable") instanceof BinaryObject);
+
+        TestObjectPlainPortable deserialized = builder.build().deserialize();
+        assertTrue(deserialized.plainPortable instanceof BinaryObject);
+    }
+
+    /**
+     *
+     */
+    public void testRemoveFromNewObject() {
+        BinaryObjectBuilder builder = builder(TestObjectAllTypes.class.getName());
+
+        builder.setField("str", "a");
+
+        builder.removeField("str");
+
+        assertNull(builder.build().<TestObjectAllTypes>deserialize().str);
+    }
+
+    /**
+     *
+     */
+    public void testRemoveFromExistingObject() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+        obj.setDefaultData();
+        obj.enumArr = null;
+
+        BinaryObjectBuilder builder = builder(toPortable(obj));
+
+        builder.removeField("str");
+
+        BinaryObject binary = builder.build();
+
+        TestObjectAllTypes deserialzied = binary.deserialize();
+
+        assertNull(deserialzied.str);
+    }
+
+    /**
+     *
+     */
+    public void testRemoveFromExistingObjectAfterGet() {
+        TestObjectAllTypes obj = new TestObjectAllTypes();
+        obj.setDefaultData();
+        obj.enumArr = null;
+
+        BinaryObjectBuilderImpl builder = builder(toPortable(obj));
+
+        builder.getField("i_");
+
+        builder.removeField("str");
+
+        assertNull(builder.build().<TestObjectAllTypes>deserialize().str);
+    }
+
+    /**
+     * @throws IgniteCheckedException If any error occurs.
+     */
+    public void testDontBrokeCyclicDependency() throws IgniteCheckedException {
+        TestObjectOuter outer = new TestObjectOuter();
+        outer.inner = new TestObjectInner();
+        outer.inner.outer = outer;
+        outer.foo = "a";
+
+        BinaryObjectBuilder builder = builder(toPortable(outer));
+
+        builder.setField("foo", "b");
+
+        TestObjectOuter res = builder.build().deserialize();
+
+        assertEquals("b", res.foo);
+        assertSame(res, res.inner.outer);
+    }
+
+    /**
+     * @return Portables.
+     */
+    private IgniteBinary portables() {
+        return grid(0).binary();
+    }
+
+    /**
+     * @param obj Object.
+     * @return Portable object.
+     */
+    private BinaryObject toPortable(Object obj) {
+        return portables().toBinary(obj);
+    }
+
+    /**
+     * @return Builder.
+     */
+    private <T> BinaryObjectBuilder builder(String clsName) {
+        return portables().builder(clsName);
+    }
+
+    /**
+     * @return Builder.
+     */
+    private <T> BinaryObjectBuilderImpl builder(BinaryObject obj) {
+        return (BinaryObjectBuilderImpl)portables().builder(obj);
+    }
+
+    /**
+     *
+     */
+    private static class CustomIdMapper {
+        /** */
+        private String str = "a";
+
+        /** */
+        private int i = 10;
+    }
+
+    /**
+     */
+    private static class Key {
+        /** */
+        private int i;
+
+        /**
+         */
+        private Key() {
+            // No-op.
+        }
+
+        /**
+         * @param i Index.
+         */
+        private Key(int i) {
+            this.i = i;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Key key = (Key)o;
+
+            return i == key.i;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return i;
+        }
+    }
+
+    /**
+     */
+    private static class Value {
+        /** */
+        private int i;
+
+        /**
+         */
+        private Value() {
+            // No-op.
+        }
+
+        /**
+         * @param i Index.
+         */
+        private Value(int i) {
+            this.i = i;
+        }
+    }
+}
\ No newline at end of file