You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/06/23 18:30:43 UTC

incubator-ignite git commit: ignite-950: finished implementing OptimizedMarshalAware

Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-950 5749b068d -> d8fbf7107


ignite-950: finished implementing OptimizedMarshalAware


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/d8fbf710
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/d8fbf710
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/d8fbf710

Branch: refs/heads/ignite-950
Commit: d8fbf71071dd3f72550e4f62eb7f9860bc08a689
Parents: 5749b06
Author: Denis Magda <dm...@gridgain.com>
Authored: Tue Jun 23 19:30:20 2015 +0300
Committer: Denis Magda <dm...@gridgain.com>
Committed: Tue Jun 23 19:30:20 2015 +0300

----------------------------------------------------------------------
 .../optimized/OptimizedClassDescriptor.java     |   2 +-
 .../optimized/OptimizedObjectInputStream.java   | 227 +++++++---
 .../optimized/OptimizedObjectMetadata.java      |  15 +-
 .../optimized/OptimizedObjectOutputStream.java  |  10 +-
 .../OptimizedObjectOutputStreamExt.java         |   8 +-
 .../OptimizedMarshallerExtSelfTest.java         | 418 +++++++++++++++++++
 .../ext/OptimizedMarshallerExtSelfTest.java     | 355 ----------------
 .../marshaller/optimized/ext/package-info.java  |  22 -
 .../IgniteMarshallerSelfTestSuite.java          |   1 -
 ...acheOptimizedMarshallerExtQuerySelfTest.java | 130 +++++-
 10 files changed, 728 insertions(+), 460 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java
index 126568e..9773d40 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedClassDescriptor.java
@@ -802,7 +802,7 @@ public class OptimizedClassDescriptor {
             case MARSHAL_AWARE:
                 verifyChecksum(in.readShort());
 
-                return in.readMarshalAware(constructor, readResolveMtd);
+                return in.readMarshalAware(constructor, readResolveMtd, typeId);
 
             default:
                 assert false : "Unexpected type: " + type;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java
index 6eeadc8..2caf0cd 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectInputStream.java
@@ -74,6 +74,9 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
     /** */
     private final HandleTable handles = new HandleTable(10);
 
+    /** */
+    private Stack<HashMap<Integer, Object>> marshalAwareValues;
+
     /**
      * @param in Input.
      * @throws IOException In case of error.
@@ -151,6 +154,7 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
 
         curObj = null;
         curFields = null;
+        marshalAwareValues = null;
     }
 
     /** {@inheritDoc} */
@@ -467,6 +471,97 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         }
     }
 
+
+    /**
+     * Reads all the fields that are specified in {@link OptimizedObjectMetadata} and places them in {@link HashMap}
+     * for furher usage.
+     *
+     * @param meta Metadata.
+     * @return Map containing field ID to value mapping.
+     * @throws ClassNotFoundException In case of error.
+     * @throws IOException In case of error.
+     */
+    HashMap<Integer, Object> readFields( OptimizedObjectMetadata meta) throws ClassNotFoundException,
+        IOException {
+
+        HashMap<Integer, Object> fieldsValues = new HashMap<>();
+
+        for (OptimizedObjectMetadata.FieldInfo fieldInfo : meta.getMeta()) {
+            Object val;
+
+            switch ((fieldInfo.type())) {
+                case BYTE:
+                    readFieldType();
+
+                    val = readByte();
+
+                    break;
+
+                case SHORT:
+                    readFieldType();
+
+                    val = readShort();
+
+                    break;
+
+                case INT:
+                    readFieldType();
+
+                    val = readInt();
+
+                    break;
+
+                case LONG:
+                    readFieldType();
+
+                    val = readLong();
+
+                    break;
+
+                case FLOAT:
+                    readFieldType();
+
+                    val = readFloat();
+
+                    break;
+
+                case DOUBLE:
+                    readFieldType();
+
+                    val = readDouble();
+
+                    break;
+
+                case CHAR:
+                    readFieldType();
+
+                    val = readChar();
+
+
+                    break;
+
+                case BOOLEAN:
+                    readFieldType();
+
+                    val = readBoolean();
+
+                    break;
+
+                case OTHER:
+                    val = readObject();
+
+                    break;
+
+                default:
+                    throw new IgniteException("Unknown field type: " + fieldInfo.type());
+            }
+
+            fieldsValues.put(fieldInfo.id(), val);
+        }
+
+        return fieldsValues;
+    }
+
     /**
      * Reads {@link Externalizable} object.
      *
@@ -512,11 +607,12 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
      *
      * @param constructor Constructor.
      * @param readResolveMtd {@code readResolve} method.
+     * @param typeId Object type ID.
      * @return Object.
      * @throws ClassNotFoundException If class not found.
      * @throws IOException In case of error.
      */
-    Object readMarshalAware(Constructor<?> constructor, Method readResolveMtd)
+    Object readMarshalAware(Constructor<?> constructor, Method readResolveMtd, int typeId)
         throws ClassNotFoundException, IOException {
         Object obj;
 
@@ -529,6 +625,17 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
 
         int handle = handles.assign(obj);
 
+        OptimizedObjectMetadata meta = metaHandler.metadata(typeId);
+
+        assert meta != null;
+
+        HashMap<Integer, Object> fieldsValues = readFields(meta);
+
+        if (marshalAwareValues == null)
+            marshalAwareValues = new Stack<>();
+
+        marshalAwareValues.push(fieldsValues);
+
         OptimizedMarshalAware extObj = ((OptimizedMarshalAware)obj);
 
         extObj.readFields(this);
@@ -544,6 +651,13 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
             }
         }
 
+        marshalAwareValues.pop();
+
+        if (marshalAwareValues.empty())
+            marshalAwareValues = null;
+
+        skipFooter(obj.getClass());
+
         return obj;
     }
 
@@ -1004,122 +1118,133 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
 
     /** {@inheritDoc} */
     @Override public byte readByte(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public short readShort(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public int readInt(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public long readLong(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public float readFloat(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public double readDouble(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public char readChar(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Override public boolean readBoolean(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public String readString(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <T> T readObject(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public byte[] readByteArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public short[] readShortArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public int[] readIntArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public long[] readLongArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public float[] readFloatArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public double[] readDoubleArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public char[] readCharArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public boolean[] readBooleanArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public String[] readStringArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public Object[] readObjectArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <T> Collection<T> readCollection(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <K, V> Map<K, V> readMap(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <T extends Enum<?>> T readEnum(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public <T extends Enum<?>> T[] readEnumArray(String fieldName) throws IOException {
-        return doReadField(fieldName);
+        return getField(fieldName);
+    }
+
+    /**
+     * Gets field of {@link OptimizedMarshalAware} object.
+     *
+     * @param fieldName Field name.
+     * @param <F> Field type.
+     * @return Field.
+     */
+    private <F> F getField(String fieldName) {
+        return (F)marshalAwareValues.peek().get(OptimizedMarshallerUtils.resolveFieldId(fieldName));
     }
 
     /**
@@ -1163,7 +1288,7 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
 
         in.position(pos);
 
-        return range != null && range.start > 0;
+        return range != null && range.start >= 0;
     }
 
     /**
@@ -1177,18 +1302,6 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
      * @throws ClassNotFoundException In case of error.
      */
     public <F> F readField(String fieldName) throws IOException, ClassNotFoundException {
-        return doReadField(fieldName, false);
-    }
-
-    /**
-     * Reads the field using footer.
-     *
-     * @param fieldName Field name.
-     * @param deserialize Deserialize field if it supports footer.
-     * @param <F> Field type.
-     * @return Field.
-     */
-    private <F> F doReadField(String fieldName, boolean deserialize) throws IOException, ClassNotFoundException {
         int pos = in.position();
 
         byte type = in.readByte();
@@ -1205,19 +1318,15 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
         if (range != null && range.start >= 0) {
             in.position(range.start);
 
-            if (deserialize)
-                field = (F)readObject();
+            byte fieldType = in.readByte();
+
+            if ((fieldType == SERIALIZABLE && metaHandler.metadata(in.readInt()) != null) ||
+                fieldType == MARSHAL_AWARE)
+                //Do we need to make a copy of array?
+                field = (F)new CacheIndexedObjectImpl(in.array(), range.start, range.len);
             else {
-                byte fieldType = in.readByte();
-
-                if ((fieldType == SERIALIZABLE && metaHandler.metadata(in.readInt()) != null) ||
-                    fieldType == MARSHAL_AWARE)
-                    //Do we need to make a copy of array?
-                    field = (F)new CacheIndexedObjectImpl(in.array(), range.start, range.len);
-                else {
-                    in.position(range.start);
-                    field = (F)readObject();
-                }
+                in.position(range.start);
+                field = (F)readObject();
             }
         }
 
@@ -1227,24 +1336,6 @@ public class OptimizedObjectInputStream extends ObjectInputStream implements Opt
     }
 
     /**
-     * Reads the field and deserializes it.
-     *
-     * @param fieldName Field name.
-     * @param <F> Field type.
-     * @return Field.
-     * @throws IOException In case of error.
-     */
-    private <F> F doReadField(String fieldName) throws IOException {
-        try {
-            return doReadField(fieldName, true);
-        }
-        catch (ClassNotFoundException e) {
-            throw new IOException("Failed to read the field, class definition has not" +
-                " been found [field=" + fieldName + "]");
-        }
-    }
-
-    /**
      * Returns field offset in the byte stream.
      *
      * @param fieldName Field name.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java
index 9a5463b..97facca 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectMetadata.java
@@ -101,13 +101,13 @@ public class OptimizedObjectMetadata implements Externalizable {
      */
     public static class FieldInfo {
         /** Field ID. */
-        int id;
+        private int id;
 
         /** Field len. */
-        int len;
+        private int len;
 
         /** Field type. */
-        OptimizedFieldType type;
+        private OptimizedFieldType type;
 
         /**
          * Constructor.
@@ -168,5 +168,14 @@ public class OptimizedObjectMetadata implements Externalizable {
         public int length() {
             return len;
         }
+
+        /**
+         * Returns field type.
+         *
+         * @return Field type.
+         */
+        public OptimizedFieldType type() {
+            return type;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java
index 1702b11..c8b24cc 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStream.java
@@ -346,6 +346,8 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
             throw new IOException("Failed to marshal OptimizedMarshalAware object. OptimizedMarshallerExt must be " +
                 "set to IgniteConfiguration [obj=" + obj.getClass().getName() + "]");
 
+        footer.indexingSupported(true);
+
         if (marshalAwareFooters == null)
             marshalAwareFooters = new Stack<>();
 
@@ -377,7 +379,7 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
         Footer footer = createFooter(obj.getClass());
 
         if (footer != null)
-            footer.fields(fields);
+            footer.indexingSupported(fields.fieldsIndexingSupported());
 
         for (int i = 0; i < mtds.size(); i++) {
             Method mtd = mtds.get(i);
@@ -1189,11 +1191,11 @@ public class OptimizedObjectOutputStream extends ObjectOutputStream implements O
      */
     protected interface Footer {
         /**
-         * Sets fields.
+         * Whether indexing supported or not.
          *
-         * @param fields Fields.
+         * @param indexingSupported {@code true} if supported.
          */
-        void fields(OptimizedClassDescriptor.Fields fields);
+        void indexingSupported(boolean indexingSupported);
 
         /**
          * Puts type ID and its value len to the footer.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStreamExt.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStreamExt.java b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStreamExt.java
index fc0daa6..d1e5dd0 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStreamExt.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/optimized/OptimizedObjectOutputStreamExt.java
@@ -71,8 +71,8 @@ public class OptimizedObjectOutputStreamExt extends OptimizedObjectOutputStream
         private boolean hasHandles;
 
         /** {@inheritDoc} */
-        @Override public void fields(OptimizedClassDescriptor.Fields fields) {
-            if (fields.fieldsIndexingSupported()) {
+        @Override public void indexingSupported(boolean indexingSupported) {
+            if (indexingSupported) {
                 data = new ArrayList<>();
                 this.fields = new ArrayList<>();
             }
@@ -81,7 +81,7 @@ public class OptimizedObjectOutputStreamExt extends OptimizedObjectOutputStream
         }
 
         /** {@inheritDoc} */
-        public void put(int fieldId, OptimizedFieldType fieldType, int len) {
+        @Override public void put(int fieldId, OptimizedFieldType fieldType, int len) {
             if (data == null)
                 return;
 
@@ -108,7 +108,7 @@ public class OptimizedObjectOutputStreamExt extends OptimizedObjectOutputStream
         }
 
         /** {@inheritDoc} */
-        public void write() throws IOException {
+        @Override public void write() throws IOException {
             if (data == null)
                 writeInt(EMPTY_FOOTER);
             else {

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
new file mode 100644
index 0000000..0e9fb61
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerExtSelfTest.java
@@ -0,0 +1,418 @@
+/*
+ * 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.marshaller.optimized;
+
+import org.apache.ignite.internal.processors.cache.*;
+import org.apache.ignite.marshaller.*;
+import org.apache.ignite.testframework.junits.common.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * Optimized marshaller self test.
+ */
+@GridCommonTest(group = "Marshaller")
+public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest {
+    /** */
+    private static ConcurrentHashMap<Integer, OptimizedObjectMetadata> META_BUF = new ConcurrentHashMap<>();
+
+    /** */
+    private static final OptimizedMarshallerMetaHandler META_HANDLER = new OptimizedMarshallerMetaHandler() {
+        @Override public void addMeta(int typeId, OptimizedObjectMetadata meta) {
+            META_BUF.putIfAbsent(typeId, meta);
+        }
+
+        @Override public OptimizedObjectMetadata metadata(int typeId) {
+            return META_BUF.get(typeId);
+        }
+    };
+
+    /** {@inheritDoc} */
+    @Override protected Marshaller marshaller() {
+        return new InternalMarshaller(false);
+    }
+
+    /**
+     * @throws Exception In case of error.
+     */
+    public void testHasField() throws Exception {
+        META_BUF.clear();
+
+        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
+
+        assertTrue(marsh.enableFieldsIndexing(TestObject.class));
+
+        assertEquals(1, META_BUF.size());
+
+        TestObject testObj = new TestObject("World", 50);
+
+        byte[] arr = marsh.marshal(testObj);
+
+        assertTrue(marsh.hasField("o2", arr, 0, arr.length));
+        assertTrue(marsh.hasField("str", arr, 0, arr.length));
+
+        assertFalse(marsh.hasField("m", arr, 0, arr.length));
+    }
+
+    /**
+     * @throws Exception In case of error.
+     */
+    public void testReadField() throws Exception {
+        META_BUF.clear();
+
+        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
+
+        assertTrue(marsh.enableFieldsIndexing(TestObject.class));
+        assertEquals(1, META_BUF.size());
+
+        TestObject testObj = new TestObject("World", 50);
+
+        byte[] arr = marsh.marshal(testObj);
+
+        // Simple field extraction.
+
+        String text = marsh.readField("str", arr, 0, arr.length, null);
+
+        assertEquals(testObj.str, text);
+
+        // Serializable extraction (doesn't have meta, thus doesn't have footer)
+        TestObject2 o2 = marsh.readField("o2", arr, 0, arr.length, null);
+
+        assertEquals(testObj.o2, o2);
+
+        // Add metadata for the enclosed object.
+        assertTrue(marsh.enableFieldsIndexing(TestObject2.class));
+        assertEquals(2, META_BUF.size());
+
+        arr = marsh.marshal(testObj);
+
+        // Must be returned in a wrapped form, since metadata was added enabling the footer.
+        CacheIndexedObjectImpl cacheObject = marsh.readField("o2", arr, 0, arr.length, null);
+
+        arr = cacheObject.valueBytes(null);
+
+        // Check enclosed objects fields
+        assertTrue(marsh.hasField("i", arr, 0, arr.length));
+        assertEquals(testObj.o2.i, (int)marsh.readField("i", arr, 0, arr.length, null));
+    }
+
+    /**
+     * @throws Exception In case of error.
+     */
+    public void testHandles() throws Exception {
+        META_BUF.clear();
+
+        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
+
+        assertTrue(marsh.enableFieldsIndexing(SelfLinkObject.class));
+        assertEquals(1, META_BUF.size());
+
+        SelfLinkObject selfLinkObject = new SelfLinkObject();
+        selfLinkObject.str1 = "Hello, world!";
+        selfLinkObject.str2 = selfLinkObject.str1;
+        selfLinkObject.link = selfLinkObject;
+
+        byte[] arr = marsh.marshal(selfLinkObject);
+
+        String str2 = marsh.readField("str2", arr, 0, arr.length, null);
+
+        assertEquals(selfLinkObject.str1, str2);
+
+        CacheIndexedObjectImpl cacheObj = marsh.readField("link", arr, 0, arr.length, null);
+
+        arr = cacheObj.valueBytes(null);
+
+        SelfLinkObject selfLinkObject2 = marsh.unmarshal(arr, null);
+
+        assertEquals(selfLinkObject, selfLinkObject2);
+    }
+
+
+    /**
+     * @throws Exception In case of error.
+     */
+    public void testMarshalAware() throws Exception {
+        META_BUF.clear();
+
+        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
+
+        assertTrue(marsh.enableFieldsIndexing(TestMarshalAware.class));
+        assertTrue(marsh.enableFieldsIndexing(AnotherMarshalAware.class));
+        assertEquals(0, META_BUF.size());
+
+        assertTrue(marsh.enableFieldsIndexing(TestObject2.class));
+        assertEquals(1, META_BUF.size());
+
+        TestMarshalAware test = new TestMarshalAware(100, "MarshalAware");
+
+        byte[] arr = marsh.marshal(test);
+
+        assertEquals(3, META_BUF.size());
+
+        // Working with fields
+        String text = marsh.readField("text", arr, 0, arr.length, null);
+
+        assertEquals(test.text, text);
+
+        CacheIndexedObjectImpl cacheObj = marsh.readField("aware", arr, 0, arr.length, null);
+        byte[] cacheObjArr = cacheObj.valueBytes(null);
+
+        Date date = marsh.readField("date", cacheObjArr, 0, cacheObjArr.length, null);
+
+        assertEquals(test.aware.date, date);
+
+        cacheObj = marsh.readField("testObject2", arr, 0, arr.length, null);
+        cacheObjArr = cacheObj.valueBytes(null);
+
+        int n = marsh.readField("i", cacheObjArr, 0, cacheObjArr.length, null);
+
+        assertEquals(test.testObject2.i, n);
+
+        // Deserializing
+        TestMarshalAware test2 = marsh.unmarshal(arr, null);
+
+        assertEquals(test.number, test2.number);
+        assertEquals(test.text, test2.text);
+        assertEquals(test.testObject2, test2.testObject2);
+        assertEquals(test.aware.date, test2.aware.date);
+        assertNull(test2.aware.someObject);
+
+        for (int i = 0; i < test.aware.arr.length; i++)
+            assertEquals(test.aware.arr[i], test2.aware.arr[i]);
+    }
+
+    private static class InternalMarshaller extends OptimizedMarshallerExt {
+        /**
+         * Constructor.
+         */
+        public InternalMarshaller() {
+        }
+
+        /**
+         * Constructor.
+         * @param requireSer Requires serialiazable.
+         */
+        public InternalMarshaller(boolean requireSer) {
+            super(requireSer);
+
+            super.setMetadataHandler(META_HANDLER);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void setMetadataHandler(OptimizedMarshallerMetaHandler metaHandler) {
+            // No-op
+        }
+    }
+
+    /** */
+    private static class TestObject2 {
+        /** */
+        private final int i;
+
+        /**
+         * Constructor for TestObject2 instances.
+         *
+         * @param i Integer value to hold.
+         */
+        private TestObject2(int i) {
+            this.i = i;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            return i == ((TestObject2)o).i;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return i;
+        }
+    }
+
+    /**
+     * Static nested class.
+     */
+    private static class TestObject {
+        /** */
+        private final TestObject2 o2;
+
+        /** The only meaningful field in the class, used for {@link #equals(Object o)} and {@link #hashCode()}. */
+        private final String str;
+
+        /** */
+        private TestObject t2;
+
+        /**
+         * @param str String to hold.
+         * @param i Integer.
+         */
+        TestObject(String str, int i) {
+            this.str = str;
+
+            o2 = new TestObject2(i);
+        }
+
+        /**
+         * Method for accessing value of the hold string after the object is created.
+         *
+         * @return Wrapped string.
+         */
+        public String string() {
+            return str;
+        }
+
+        /**
+         * @return Object held in this wrapped.
+         */
+        public TestObject2 obj() {
+            return o2;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return 31 * o2.hashCode() + str.hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("RedundantIfStatement")
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            TestObject obj = (TestObject)o;
+
+            if (o2 != null ? !o2.equals(obj.o2) : obj.o2 != null)
+                return false;
+
+            if (str != null ? !str.equals(obj.str) : obj.str != null)
+                return false;
+
+            return true;
+        }
+    }
+
+    /**
+     *
+     */
+    private static class SelfLinkObject {
+        /** */
+        String str1;
+
+        /** */
+        String str2;
+
+        /** */
+        SelfLinkObject link;
+
+        @Override public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            SelfLinkObject that = (SelfLinkObject)o;
+
+            if (str1 != null ? !str1.equals(that.str1) : that.str1 != null) return false;
+            if (str2 != null ? !str2.equals(that.str2) : that.str2 != null) return false;
+
+            return true;
+        }
+    }
+
+    /**
+     *
+     */
+    private static class TestMarshalAware implements OptimizedMarshalAware {
+        /** */
+        private int number;
+
+        /** */
+        private String text;
+
+        /** */
+        private AnotherMarshalAware aware;
+
+        /** */
+        private TestObject2 testObject2;
+
+        public TestMarshalAware() {
+            // No-op
+        }
+
+        public TestMarshalAware(int i, String str) {
+            this.number = i;
+            this.text = str;
+
+            aware = new AnotherMarshalAware(new int[] {10, 11, 23});
+            testObject2 = new TestObject2(i * 10);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeFields(OptimizedFieldsWriter writer) throws IOException {
+            writer.writeInt("number", number);
+            writer.writeString("text", text);
+            writer.writeObject("aware", aware);
+            writer.writeObject("testObject2", testObject2);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readFields(OptimizedFieldsReader reader) throws IOException {
+            number = reader.readInt("number");
+            text = reader.readString("text");
+            aware = reader.readObject("aware");
+            testObject2 = reader.readObject("testObject2");
+        }
+    }
+
+    /**
+     *
+     */
+    private static class AnotherMarshalAware implements OptimizedMarshalAware {
+        /** */
+        private Date date = new Date();
+
+        /** */
+        private Object someObject;
+
+        /** */
+        private int[] arr;
+
+        public AnotherMarshalAware() {
+            // No-op
+        }
+
+        public AnotherMarshalAware(int[] arr) {
+            this.arr = arr;
+            someObject = new Object();
+        }
+
+        @Override public void writeFields(OptimizedFieldsWriter writer) throws IOException {
+            writer.writeIntArray("arr", arr);
+            writer.writeObject("date", date);
+        }
+
+        @Override public void readFields(OptimizedFieldsReader reader) throws IOException {
+            // Deliberately reading in reverse order.
+            date = reader.readObject("date");
+            arr = reader.readIntArray("arr");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java
deleted file mode 100644
index 7866500..0000000
--- a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/OptimizedMarshallerExtSelfTest.java
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * 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.marshaller.optimized.ext;
-
-import org.apache.ignite.internal.processors.cache.*;
-import org.apache.ignite.marshaller.*;
-import org.apache.ignite.marshaller.optimized.*;
-import org.apache.ignite.testframework.junits.common.*;
-
-import java.io.*;
-import java.util.concurrent.*;
-
-/**
- * Optimized marshaller self test.
- */
-@GridCommonTest(group = "Marshaller")
-public class OptimizedMarshallerExtSelfTest extends OptimizedMarshallerSelfTest {
-    /** */
-    private static ConcurrentHashMap<Integer, OptimizedObjectMetadata> META_BUF = new ConcurrentHashMap<>();
-
-    /** */
-    private static final OptimizedMarshallerMetaHandler META_HANDLER = new OptimizedMarshallerMetaHandler() {
-        @Override public void addMeta(int typeId, OptimizedObjectMetadata meta) {
-            META_BUF.putIfAbsent(typeId, meta);
-        }
-
-        @Override public OptimizedObjectMetadata metadata(int typeId) {
-            return META_BUF.get(typeId);
-        }
-    };
-
-    /** {@inheritDoc} */
-    @Override protected Marshaller marshaller() {
-        return new InternalMarshaller(false);
-    }
-
-    /**
-     * @throws Exception In case of error.
-     */
-    public void testHasField() throws Exception {
-        META_BUF.clear();
-
-        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
-
-        assertTrue(marsh.enableFieldsIndexing(TestObject.class));
-
-        assertEquals(1, META_BUF.size());
-
-        TestObject testObj = new TestObject("World", 50);
-
-        byte[] arr = marsh.marshal(testObj);
-
-        assertTrue(marsh.hasField("o2", arr, 0, arr.length));
-        assertTrue(marsh.hasField("str", arr, 0, arr.length));
-
-        assertFalse(marsh.hasField("m", arr, 0, arr.length));
-    }
-
-    /**
-     * @throws Exception In case of error.
-     */
-    public void testReadField() throws Exception {
-        META_BUF.clear();
-
-        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
-
-        assertTrue(marsh.enableFieldsIndexing(TestObject.class));
-        assertEquals(1, META_BUF.size());
-
-        TestObject testObj = new TestObject("World", 50);
-
-        byte[] arr = marsh.marshal(testObj);
-
-        // Simple field extraction.
-
-        String text = marsh.readField("str", arr, 0, arr.length, null);
-
-        assertEquals(testObj.str, text);
-
-        // Serializable extraction (doesn't have meta, thus doesn't have footer)
-        TestObject2 o2 = marsh.readField("o2", arr, 0, arr.length, null);
-
-        assertEquals(testObj.o2, o2);
-
-        // Add metadata for the enclosed object.
-        assertTrue(marsh.enableFieldsIndexing(TestObject2.class));
-        assertEquals(2, META_BUF.size());
-
-        arr = marsh.marshal(testObj);
-
-        // Must be returned in a wrapped form, since metadata was added enabling the footer.
-        CacheIndexedObjectImpl cacheObject = marsh.readField("o2", arr, 0, arr.length, null);
-
-        arr = cacheObject.valueBytes(null);
-
-        // Check enclosed objects fields
-        assertTrue(marsh.hasField("i", arr, 0, arr.length));
-        assertEquals(testObj.o2.i, (int)marsh.readField("i", arr, 0, arr.length, null));
-    }
-
-    /**
-     * @throws Exception In case of error.
-     */
-    public void testHandles() throws Exception {
-        META_BUF.clear();
-
-        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
-
-        assertTrue(marsh.enableFieldsIndexing(SelfLinkObject.class));
-        assertEquals(1, META_BUF.size());
-
-        SelfLinkObject selfLinkObject = new SelfLinkObject();
-        selfLinkObject.str1 = "Hello, world!";
-        selfLinkObject.str2 = selfLinkObject.str1;
-        selfLinkObject.link = selfLinkObject;
-
-        byte[] arr = marsh.marshal(selfLinkObject);
-
-        String str2 = marsh.readField("str2", arr, 0, arr.length, null);
-
-        assertEquals(selfLinkObject.str1, str2);
-
-        CacheIndexedObjectImpl cacheObj = marsh.readField("link", arr, 0, arr.length, null);
-
-        arr = cacheObj.valueBytes(null);
-
-        SelfLinkObject selfLinkObject2 = marsh.unmarshal(arr, null);
-
-        assertEquals(selfLinkObject, selfLinkObject2);
-    }
-
-
-    /**
-     * @throws Exception In case of error.
-     */
-    /*public void testMarshalAware() throws Exception {
-        META_BUF.clear();
-
-        OptimizedMarshallerExt marsh = (OptimizedMarshallerExt)OptimizedMarshallerExtSelfTest.marsh;
-
-        assertTrue(marsh.enableFieldsIndexing(TestMarshalAware.class));
-        assertEquals(0, META_BUF.size());
-
-        TestMarshalAware test = new TestMarshalAware(100, "MarshalAware");
-
-        byte[] arr = marsh.marshal(test);
-
-        assertEquals(1, META_BUF.size());
-
-        TestMarshalAware test2 = marsh.unmarshal(arr, null);
-
-        assertEquals(test, test2);
-    }*/
-
-    private static class InternalMarshaller extends OptimizedMarshallerExt {
-        /**
-         * Constructor.
-         */
-        public InternalMarshaller() {
-        }
-
-        /**
-         * Constructor.
-         * @param requireSer Requires serialiazable.
-         */
-        public InternalMarshaller(boolean requireSer) {
-            super(requireSer);
-
-            super.setMetadataHandler(META_HANDLER);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void setMetadataHandler(OptimizedMarshallerMetaHandler metaHandler) {
-            // No-op
-        }
-    }
-
-    /** */
-    private static class TestObject2 {
-        /** */
-        private final int i;
-
-        /**
-         * Constructor for TestObject2 instances.
-         *
-         * @param i Integer value to hold.
-         */
-        private TestObject2(int i) {
-            this.i = i;
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean equals(Object o) {
-            return i == ((TestObject2)o).i;
-        }
-
-        /** {@inheritDoc} */
-        @Override public int hashCode() {
-            return i;
-        }
-    }
-
-    /**
-     * Static nested class.
-     */
-    private static class TestObject {
-        /** */
-        private final TestObject2 o2;
-
-        /** The only meaningful field in the class, used for {@link #equals(Object o)} and {@link #hashCode()}. */
-        private final String str;
-
-        /** */
-        private TestObject t2;
-
-        /**
-         * @param str String to hold.
-         * @param i Integer.
-         */
-        TestObject(String str, int i) {
-            this.str = str;
-
-            o2 = new TestObject2(i);
-        }
-
-        /**
-         * Method for accessing value of the hold string after the object is created.
-         *
-         * @return Wrapped string.
-         */
-        public String string() {
-            return str;
-        }
-
-        /**
-         * @return Object held in this wrapped.
-         */
-        public TestObject2 obj() {
-            return o2;
-        }
-
-        /** {@inheritDoc} */
-        @Override public int hashCode() {
-            return 31 * o2.hashCode() + str.hashCode();
-        }
-
-        /** {@inheritDoc} */
-        @SuppressWarnings("RedundantIfStatement")
-        @Override public boolean equals(Object o) {
-            if (this == o)
-                return true;
-
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            TestObject obj = (TestObject)o;
-
-            if (o2 != null ? !o2.equals(obj.o2) : obj.o2 != null)
-                return false;
-
-            if (str != null ? !str.equals(obj.str) : obj.str != null)
-                return false;
-
-            return true;
-        }
-    }
-
-    /**
-     *
-     */
-    private static class SelfLinkObject {
-        /** */
-        String str1;
-
-        /** */
-        String str2;
-
-        /** */
-        SelfLinkObject link;
-
-        @Override public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-
-            SelfLinkObject that = (SelfLinkObject)o;
-
-            if (str1 != null ? !str1.equals(that.str1) : that.str1 != null) return false;
-            if (str2 != null ? !str2.equals(that.str2) : that.str2 != null) return false;
-
-            return true;
-        }
-    }
-
-    /**
-     *
-     */
-    private static class TestMarshalAware implements OptimizedMarshalAware {
-        /** */
-        private int i;
-
-        /** */
-        private String str;
-
-        public TestMarshalAware() {
-            // No-op
-        }
-
-        public TestMarshalAware(int i, String str) {
-            this.i = i;
-            this.str = str;
-        }
-
-        /** {@inheritDoc} */
-        @Override public void writeFields(OptimizedFieldsWriter writer) throws IOException {
-            writer.writeInt("i", i);
-            writer.writeString("str", str);
-        }
-
-        /** {@inheritDoc} */
-        @Override public void readFields(OptimizedFieldsReader reader) throws IOException {
-            i = reader.readInt("i");
-            str = reader.readString("str");
-        }
-
-        /** {@inheritDoc} */
-        @Override public boolean equals(Object o) {
-            if (this == o)
-                return true;
-            if (o == null || getClass() != o.getClass())
-                return false;
-
-            TestMarshalAware that = (TestMarshalAware)o;
-
-            if (i != that.i)
-                return false;
-
-            return !(str != null ? !str.equals(that.str) : that.str != null);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
deleted file mode 100644
index eabdbce..0000000
--- a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/ext/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 description. -->
- * Extended optimized marshaller test package.
- */
-package org.apache.ignite.marshaller.optimized.ext;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteMarshallerSelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteMarshallerSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteMarshallerSelfTestSuite.java
index f3047f2..1f65008 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteMarshallerSelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteMarshallerSelfTestSuite.java
@@ -21,7 +21,6 @@ import junit.framework.*;
 import org.apache.ignite.internal.util.io.*;
 import org.apache.ignite.marshaller.jdk.*;
 import org.apache.ignite.marshaller.optimized.*;
-import org.apache.ignite.marshaller.optimized.ext.*;
 import org.apache.ignite.testframework.*;
 
 import java.util.*;

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/d8fbf710/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheOptimizedMarshallerExtQuerySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheOptimizedMarshallerExtQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheOptimizedMarshallerExtQuerySelfTest.java
index 77e5bb2..5791b37 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheOptimizedMarshallerExtQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheOptimizedMarshallerExtQuerySelfTest.java
@@ -24,6 +24,7 @@ import org.apache.ignite.configuration.*;
 import org.apache.ignite.marshaller.optimized.*;
 
 import javax.cache.*;
+import java.io.*;
 import java.util.*;
 
 import static org.apache.ignite.cache.CacheMode.*;
@@ -78,7 +79,13 @@ public class IgniteCacheOptimizedMarshallerExtQuerySelfTest extends GridCacheAbs
             p.salary = (i + 1) * 100;
             p.address = addr;
 
+            Customer customer = new Customer();
+            customer.id = i;
+            customer.company = "Company " + addr.street;
+            customer.info = p;
+
             cache.put(i, p);
+            cache.put(i + 200, customer);
         }
     }
 
@@ -133,7 +140,7 @@ public class IgniteCacheOptimizedMarshallerExtQuerySelfTest extends GridCacheAbs
         IgniteCache<Integer, Person> cache = grid(0).cache(null);
 
         QueryCursor<List<?>> cur = cache.query(new SqlFieldsQuery("select name, address, zip" +
-            " from Person where zip IN (1,2)"));
+                                                                      " from Person where zip IN (1,2)"));
 
         List<?> result = cur.getAll();
 
@@ -150,6 +157,76 @@ public class IgniteCacheOptimizedMarshallerExtQuerySelfTest extends GridCacheAbs
     }
 
     /**
+     * @throws Exception In case of error.
+     */
+    public void testSimpleMarshalAwareQuery() throws Exception {
+        IgniteCache<Integer, Customer> cache = grid(0).cache(null);
+
+        Collection<Cache.Entry<Integer, Customer>> entries = cache.query(new SqlQuery<Integer, Customer>(
+            "Customer", "info is not null")).getAll();
+
+        assertEquals(50, entries.size());
+
+        for (Cache.Entry<Integer, Customer> entry : entries) {
+            int id = entry.getKey();
+            Customer c = entry.getValue();
+
+            id -= 200;
+
+            assertEquals("Person " + id, c.info.name);
+            assertEquals((id + 1) * 100, c.info.salary);
+            assertEquals("Company Street " + id, c.company);
+            assertEquals(id, c.id);
+        }
+    }
+
+    /**
+     * @throws Exception In case of error.
+     */
+    public void testNestedFieldsMarshalAwareQuery() throws Exception {
+        IgniteCache<Integer, Customer> cache = grid(0).cache(null);
+
+        Collection<Cache.Entry<Integer, Customer>> entries = cache.query(new SqlQuery<Integer, Customer>(
+            "Customer", "name is not null AND (zip = 1 OR zip = 2)")).getAll();
+
+        assertEquals(2, entries.size());
+
+        for (Cache.Entry<Integer, Customer> entry : entries) {
+            int id = entry.getKey();
+            Customer c = entry.getValue();
+
+            id -= 200;
+
+            assertEquals("Person " + id, c.info.name);
+            assertEquals((id + 1) * 100, c.info.salary);
+            assertEquals("Company Street " + id, c.company);
+            assertEquals(id, c.info.address.zip);
+        }
+    }
+
+    /**
+     * @throws Exception In case of error.
+     */
+    public void testFieldsMarshalAwareQuery() throws Exception {
+        IgniteCache<Integer, Customer> cache = grid(0).cache(null);
+
+        QueryCursor<List<?>> cur = cache.query(new SqlFieldsQuery("select name, company, zip" +
+                                                                      " from Customer where zip IN (1,2)"));
+
+        List<?> result = cur.getAll();
+
+        assertTrue(result.size() == 2);
+
+        for (Object row : result) {
+            ArrayList<Object> list = (ArrayList<Object>)row;
+
+            assertNotNull(list.get(0));
+            assertNotNull(list.get(1));
+            assert (int)list.get(2) > 0;
+        }
+    }
+
+    /**
      * @return Cache type metadata.
      */
     private Collection<CacheTypeMetadata> cacheTypeMetadata() {
@@ -178,7 +255,24 @@ public class IgniteCacheOptimizedMarshallerExtQuerySelfTest extends GridCacheAbs
 
         addrMeta.setQueryFields(addrQryFields);
 
-        return Arrays.asList(personMeta, addrMeta);
+        CacheTypeMetadata customerMeta = new CacheTypeMetadata();
+
+        customerMeta.setValueType(Customer.class);
+
+        Map<String, Class<?>> customerIndexFields = new HashMap<>();
+        customerIndexFields.put("id", Integer.class);
+
+        customerMeta.setAscendingFields(customerIndexFields);
+
+        Map<String, Class<?>> customerQueryFields = new HashMap<>();
+        customerQueryFields.put("info", Person.class);
+        customerQueryFields.put("info.address.zip", Integer.class);
+        customerQueryFields.put("info.name", String.class);
+        customerQueryFields.put("company", String.class);
+
+        customerMeta.setQueryFields(customerQueryFields);
+
+        return Arrays.asList(personMeta, addrMeta, customerMeta);
     }
 
     /**
@@ -205,4 +299,36 @@ public class IgniteCacheOptimizedMarshallerExtQuerySelfTest extends GridCacheAbs
         /** */
         public int zip;
     }
+
+    /**
+     *
+     */
+    private static class Customer implements OptimizedMarshalAware {
+        /** */
+        private int id;
+
+        /** */
+        private Person info;
+
+        /** */
+        private String company;
+
+        public Customer() {
+            // No-op
+        }
+
+        /** {@inheritDoc} */
+        @Override public void writeFields(OptimizedFieldsWriter writer) throws IOException {
+            writer.writeInt("id", id);
+            writer.writeObject("info", info);
+            writer.writeString("company", company);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void readFields(OptimizedFieldsReader reader) throws IOException {
+            info = reader.readObject("info");
+            company = reader.readString("company");
+            id = reader.readInt("id");
+        }
+    }
 }