#ignite-gg-9924: add fix for marshalling from 6.6.4

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

Branch: refs/heads/ignite-443
Commit: 75ea4a3d6f8bd680a3ffd4a8a4d1b2b6489ed1c6
Parents: 448e9c3
Author: ivasilinets <ivasilin...@gridgain.com>
Authored: Thu Mar 19 20:31:49 2015 +0300
Committer: ivasilinets <ivasilin...@gridgain.com>
Committed: Thu Mar 19 20:31:49 2015 +0300

----------------------------------------------------------------------
 .../optimized/OptimizedClassDescriptor.java     | 268 ++++++++++++-------
 .../optimized/OptimizedObjectInputStream.java   |  91 ++++---
 .../optimized/OptimizedObjectOutputStream.java  |  64 ++---
 ...arshallerSerialPersistentFieldsSelfTest.java | 107 ++++++++
 .../IgniteMarshallerSelfTestSuite.java          |   1 +
 5 files changed, 367 insertions(+), 164 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/75ea4a3d/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 9eaf7af..05ef534 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
@@ -18,8 +18,7 @@
 package org.apache.ignite.marshaller.optimized;
 
 import org.apache.ignite.internal.util.*;
-import org.apache.ignite.internal.util.typedef.*;
-import org.apache.ignite.lang.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
 import org.apache.ignite.marshaller.*;
 import sun.misc.*;
 
@@ -337,10 +336,7 @@ class OptimizedClassDescriptor {
 
                     writeObjMtds = new ArrayList<>();
                     readObjMtds = new ArrayList<>();
-                    List<List<Field>> fields = new ArrayList<>();
-                    List<List<T2<OptimizedFieldType, Long>>> fieldOffs = new 
ArrayList<>();
-                    List<Map<String, IgniteBiTuple<Integer, 
OptimizedFieldType>>> fieldInfoMaps = new ArrayList<>();
-                    List<List<IgniteBiTuple<Integer, OptimizedFieldType>>> 
fieldInfoLists = new ArrayList<>();
+                    List<ClassFields> fields = new ArrayList<>();
 
                     for (c = cls; c != null && !c.equals(Object.class); c = 
c.getSuperclass()) {
                         Method mtd;
@@ -381,33 +377,14 @@ class OptimizedClassDescriptor {
 
                         Field[] clsFields0 = c.getDeclaredFields();
 
-                        Arrays.sort(clsFields0, new Comparator<Field>() {
-                            @Override public int compare(Field f1, Field f2) {
-                                return f1.getName().compareTo(f2.getName());
-                            }
-                        });
-
-                        List<Field> clsFields = new 
ArrayList<>(clsFields0.length);
-                        List<T2<OptimizedFieldType, Long>> clsFieldOffs =
-                            new ArrayList<>(clsFields0.length);
-
-                        for (int i = 0; i < clsFields0.length; i++) {
-                            Field f = clsFields0[i];
-
-                            int mod = f.getModifiers();
-
-                            if (!isStatic(mod) && !isTransient(mod)) {
-                                OptimizedFieldType type = 
fieldType(f.getType());
+                        Map<String, Field> fieldNames = new HashMap<>();
 
-                                clsFields.add(f);
-                                clsFieldOffs.add(new T2<>(type, 
UNSAFE.objectFieldOffset(f)));
-                            }
-                        }
+                        for (Field f : clsFields0)
+                            fieldNames.put(f.getName(), f);
 
-                        fields.add(clsFields);
-                        fieldOffs.add(clsFieldOffs);
+                        List<FieldInfo> clsFields = new 
ArrayList<>(clsFields0.length);
 
-                        Map<String, IgniteBiTuple<Integer, 
OptimizedFieldType>> fieldInfoMap = null;
+                        boolean hasSerialPersistentFields  = false;
 
                         try {
                             Field serFieldsDesc = 
c.getDeclaredField("serialPersistentFields");
@@ -416,16 +393,33 @@ class OptimizedClassDescriptor {
 
                             if (serFieldsDesc.getType() == 
ObjectStreamField[].class &&
                                 isPrivate(mod) && isStatic(mod) && 
isFinal(mod)) {
-                                serFieldsDesc.setAccessible(true);
+                                hasSerialPersistentFields = true;
 
-                                ObjectStreamField[] serFields = 
(ObjectStreamField[])serFieldsDesc.get(null);
+                                serFieldsDesc.setAccessible(true);
 
-                                fieldInfoMap = new HashMap<>();
+                                ObjectStreamField[] serFields = 
(ObjectStreamField[]) serFieldsDesc.get(null);
 
                                 for (int i = 0; i < serFields.length; i++) {
                                     ObjectStreamField serField = serFields[i];
 
-                                    fieldInfoMap.put(serField.getName(), 
F.t(i, fieldType(serField.getType())));
+                                    FieldInfo fieldInfo;
+
+                                    if 
(!fieldNames.containsKey(serField.getName())) {
+                                        fieldInfo = new FieldInfo(null,
+                                            serField.getName(),
+                                            -1,
+                                            fieldType(serField.getType()));
+                                    }
+                                    else {
+                                        Field f = 
fieldNames.get(serField.getName());
+
+                                        fieldInfo = new FieldInfo(f,
+                                            serField.getName(),
+                                            UNSAFE.objectFieldOffset(f),
+                                            fieldType(serField.getType()));
+                                    }
+
+                                    clsFields.add(fieldInfo);
                                 }
                             }
                         }
@@ -437,39 +431,35 @@ class OptimizedClassDescriptor {
                                 cls.getName(), e);
                         }
 
-                        if (fieldInfoMap == null) {
-                            fieldInfoMap = new HashMap<>();
+                        if (!hasSerialPersistentFields) {
+                            for (int i = 0; i < clsFields0.length; i++) {
+                                Field f = clsFields0[i];
+
+                                int mod = f.getModifiers();
 
-                            for (int i = 0; i < clsFields.size(); i++) {
-                                Field f = clsFields.get(i);
+                                if (!isStatic(mod) && !isTransient(mod)) {
+                                    FieldInfo fieldInfo = new FieldInfo(f, 
f.getName(),
+                                        UNSAFE.objectFieldOffset(f), 
fieldType(f.getType()));
 
-                                fieldInfoMap.put(f.getName(), F.t(i, 
fieldType(f.getType())));
+                                    clsFields.add(fieldInfo);
+                                }
                             }
                         }
 
-                        fieldInfoMaps.add(fieldInfoMap);
-
-                        List<IgniteBiTuple<Integer, OptimizedFieldType>> 
fieldInfoList =
-                            new ArrayList<>(fieldInfoMap.values());
-
-                        Collections.sort(fieldInfoList, new 
Comparator<IgniteBiTuple<Integer, OptimizedFieldType>>() {
-                            @Override public int 
compare(IgniteBiTuple<Integer, OptimizedFieldType> t1,
-                                IgniteBiTuple<Integer, OptimizedFieldType> t2) 
{
-                                return t1.get1().compareTo(t2.get1());
+                        Collections.sort(clsFields, new 
Comparator<FieldInfo>() {
+                            @Override public int compare(FieldInfo t1, 
FieldInfo t2) {
+                                return t1.name().compareTo(t2.name());
                             }
                         });
 
-                        fieldInfoLists.add(fieldInfoList);
+                        fields.add(new ClassFields(clsFields));
                     }
 
                     Collections.reverse(writeObjMtds);
                     Collections.reverse(readObjMtds);
                     Collections.reverse(fields);
-                    Collections.reverse(fieldOffs);
-                    Collections.reverse(fieldInfoMaps);
-                    Collections.reverse(fieldInfoLists);
 
-                    this.fields = new Fields(fields, fieldOffs, 
fieldInfoLists, fieldInfoMaps);
+                    this.fields = new Fields(fields);
                 }
             }
         }
@@ -810,76 +800,166 @@ class OptimizedClassDescriptor {
     }
 
     /**
-     * Encapsulates data about class fields.
+     * Information about one field.
      */
     @SuppressWarnings("PackageVisibleInnerClass")
-    static class Fields {
-        /** Fields. */
-        private final List<List<Field>> fields;
+    static class FieldInfo {
+        /** Field. */
+        private final Field field;
 
-        /** Fields offsets. */
-        private final List<List<T2<OptimizedFieldType, Long>>> fieldOffs;
+        /** Field offset. */
+        private final long fieldOffs;
 
-        /** Fields details lists. */
-        private final List<List<IgniteBiTuple<Integer, OptimizedFieldType>>> 
fieldInfoLists;
+        /** Field type. */
+        private final OptimizedFieldType fieldType;
 
-        /** Fields details maps. */
-        private final List<Map<String, IgniteBiTuple<Integer, 
OptimizedFieldType>>> fieldInfoMaps;
+        /** Field name. */
+        private final String fieldName;
 
         /**
-         * Creates new instance.
-         *
-         * @param fields Fields.
-         * @param fieldOffs Field offsets.
-         * @param fieldInfoLists List of field details sequences for each type 
in the object's class hierarchy.
-         * @param fieldInfoMaps List of field details maps for each type in 
the object's class hierarchy.
+         * @param field Field.
+         * @param name Field name.
+         * @param offset Field offset.
+         * @param type Grid optimized field type.
+         */
+        FieldInfo(Field field, String name, long offset, OptimizedFieldType 
type) {
+            this.field = field;
+            fieldOffs = offset;
+            fieldType = type;
+            fieldName = name;
+        }
+
+        /**
+         * @return Returns field.
+         */
+        Field field() {
+            return field;
+        }
+
+        /**
+         * @return Offset.
+         */
+        long offset() {
+            return fieldOffs;
+        }
+
+        /**
+         * @return Type.
+         */
+        OptimizedFieldType type() {
+            return fieldType;
+        }
+
+        /**
+         * @return Name.
+         */
+        String name() {
+            return fieldName;
+        }
+    }
+
+    /**
+     * Information about one class.
+     */
+    static class ClassFields {
+        /** Fields. */
+        private final List<FieldInfo> fields;
+
+        private final Map<String, Integer> nameToIndex;
+
+        /**
+         * @param fields Field infos.
          */
-        Fields(List<List<Field>> fields, List<List<T2<OptimizedFieldType, 
Long>>> fieldOffs,
-            List<List<IgniteBiTuple<Integer, OptimizedFieldType>>> 
fieldInfoLists,
-            List<Map<String, IgniteBiTuple<Integer, OptimizedFieldType>>> 
fieldInfoMaps) {
+        ClassFields(List<FieldInfo> fields) {
             this.fields = fields;
-            this.fieldOffs = fieldOffs;
-            this.fieldInfoLists = fieldInfoLists;
-            this.fieldInfoMaps = fieldInfoMaps;
+
+            nameToIndex = U.newHashMap(fields.size());
+
+            for (int i = 0; i < fields.size(); ++i)
+                nameToIndex.put(fields.get(i).name(), i);
         }
 
         /**
-         * Returns class's own fields (excluding inherited).
-         *
-         * @return List of fields or {@code null} if fields list is empty.
+         * @return Class fields.
          */
-        List<Field> ownFields() {
-            return fields.isEmpty() ? null : fields.get(fields.size() - 1);
+        List<FieldInfo> fields() {
+            return fields;
         }
 
         /**
-         * Returns field types and their offsets.
+         * @return Fields count.
+         */
+        int size() {
+            return fields.size();
+        }
+
+        /**
+         * @param i Field's index.
+         * @return FieldInfo.
+         */
+        FieldInfo get(int i) {
+            return fields.get(i);
+        }
+
+        /**
+         * @param name Field's name.
+         * @return Field's index.
+         */
+        int getIndex(String name) {
+            assert nameToIndex.containsKey(name);
+
+            return nameToIndex.get(name);
+        }
+    }
+
+    /**
+     * Encapsulates data about class fields.
+     */
+    @SuppressWarnings("PackageVisibleInnerClass")
+    static class Fields {
+        /** Fields. */
+        private final List<ClassFields> fields;
+
+        /** Own fields (excluding inherited). */
+        private final List<Field> ownFields;
+
+        /**
+         * Creates new instance.
          *
-         * @param i hierarchy level where 0 corresponds to top level.
-         * @return list of pairs where first value is field type and second 
value is its offset.
+         * @param fields Fields.
          */
-        List<T2<OptimizedFieldType, Long>> fieldOffs(int i) {
-            return fieldOffs.get(i);
+        Fields(List<ClassFields> fields) {
+            this.fields = fields;
+
+            if (fields.isEmpty())
+                ownFields = null;
+            else {
+                ownFields = new ArrayList<>(fields.size());
+
+                for (FieldInfo f : fields.get(fields.size() - 1).fields()) {
+                    if (f.field() != null)
+                        ownFields.add(f.field);
+                }
+            }
         }
 
         /**
-         * Returns field sequence numbers and their types as list.
+         * Returns class's own fields (excluding inherited).
          *
-         * @param i hierarchy level where 0 corresponds to top level.
-         * @return list of pairs (field number, field type) for the given 
hierarchy level.
+         * @return List of fields or {@code null} if fields list is empty.
          */
-        List<IgniteBiTuple<Integer, OptimizedFieldType>> fieldInfoList(int i) {
-            return fieldInfoLists.get(i);
+        List<Field> ownFields() {
+            return ownFields;
         }
 
         /**
-         * Returns field sequence numbers and their types as map where key is 
a field name,
+         * Returns field types and their offsets.
          *
          * @param i hierarchy level where 0 corresponds to top level.
-         * @return map of field names and their details.
+         * @return list of pairs where first value is field type and second 
value is its offset.
          */
-        Map<String, IgniteBiTuple<Integer, OptimizedFieldType>> 
fieldInfoMap(int i) {
-            return fieldInfoMaps.get(i);
+        ClassFields fields(int i) {
+            return fields.get(i);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/75ea4a3d/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 f8c6e46..6d02eeb 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
@@ -20,9 +20,7 @@ package org.apache.ignite.marshaller.optimized;
 import org.apache.ignite.*;
 import org.apache.ignite.internal.util.*;
 import org.apache.ignite.internal.util.io.*;
-import org.apache.ignite.internal.util.typedef.*;
 import org.apache.ignite.internal.util.typedef.internal.*;
-import org.apache.ignite.lang.*;
 import org.apache.ignite.marshaller.*;
 import sun.misc.*;
 
@@ -62,13 +60,7 @@ class OptimizedObjectInputStream extends ObjectInputStream {
     private Object curObj;
 
     /** */
-    private List<T2<OptimizedFieldType, Long>> curFields;
-
-    /** */
-    private List<IgniteBiTuple<Integer, OptimizedFieldType>> curFieldInfoList;
-
-    /** */
-    private Map<String, IgniteBiTuple<Integer, OptimizedFieldType>> 
curFieldInfoMap;
+    private OptimizedClassDescriptor.ClassFields curFields;
 
     /** */
     private Class<?> curCls;
@@ -133,16 +125,12 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
 
         curObj = null;
         curFields = null;
-        curFieldInfoList = null;
-        curFieldInfoMap = null;
     }
 
     /** {@inheritDoc} */
     @Override public Object readObjectOverride() throws 
ClassNotFoundException, IOException {
         curObj = null;
         curFields = null;
-        curFieldInfoList = null;
-        curFieldInfoMap = null;
 
         byte ref = in.readByte();
 
@@ -357,54 +345,81 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
      * @throws IOException In case of error.
      */
     @SuppressWarnings("ForLoopReplaceableByForEach")
-    void readFields(Object obj, List<T2<OptimizedFieldType, Long>> fieldOffs) 
throws ClassNotFoundException,
+    void readFields(Object obj, OptimizedClassDescriptor.ClassFields 
fieldOffs) throws ClassNotFoundException,
         IOException {
         for (int i = 0; i < fieldOffs.size(); i++) {
-            T2<OptimizedFieldType, Long> t = fieldOffs.get(i);
+            OptimizedClassDescriptor.FieldInfo t = fieldOffs.get(i);
 
-            switch ((t.get1())) {
+            switch ((t.type())) {
                 case BYTE:
-                    setByte(obj, t.get2(), readByte());
+                    byte resByte = readByte();
+
+                    if (t.field() != null)
+                        setByte(obj, t.offset(), resByte);
 
                     break;
 
                 case SHORT:
-                    setShort(obj, t.get2(), readShort());
+                    short resShort = readShort();
+
+                    if (t.field() != null)
+                        setShort(obj, t.offset(), resShort);
 
                     break;
 
                 case INT:
-                    setInt(obj, t.get2(), readInt());
+                    int resInt = readInt();
+
+                    if (t.field() != null)
+                        setInt(obj, t.offset(), resInt);
 
                     break;
 
                 case LONG:
-                    setLong(obj, t.get2(), readLong());
+                    long resLong = readLong();
+
+                    if (t.field() != null)
+                        setLong(obj, t.offset(), resLong);
 
                     break;
 
                 case FLOAT:
-                    setFloat(obj, t.get2(), readFloat());
+                    float resFloat = readFloat();
+
+                    if (t.field() != null)
+                        setFloat(obj, t.offset(), resFloat);
 
                     break;
 
                 case DOUBLE:
-                    setDouble(obj, t.get2(), readDouble());
+                    double resDouble = readDouble();
+
+                    if (t.field() != null)
+                        setDouble(obj, t.offset(), resDouble);
 
                     break;
 
                 case CHAR:
-                    setChar(obj, t.get2(), readChar());
+                    char resChar = readChar();
+
+                    if (t.field() != null)
+                        setChar(obj, t.offset(), resChar);
 
                     break;
 
                 case BOOLEAN:
-                    setBoolean(obj, t.get2(), readBoolean());
+                    boolean resBoolean = readBoolean();
+
+                    if (t.field() != null)
+                        setBoolean(obj, t.offset(), resBoolean);
 
                     break;
 
                 case OTHER:
-                    setObject(obj, t.get2(), readObject());
+                    Object resObject = readObject();
+
+                    if (t.field() != null)
+                        setObject(obj, t.offset(), resObject);
             }
         }
     }
@@ -479,9 +494,7 @@ class OptimizedObjectInputStream extends ObjectInputStream {
 
             if (mtd != null) {
                 curObj = obj;
-                curFields = fields.fieldOffs(i);
-                curFieldInfoList = fields.fieldInfoList(i);
-                curFieldInfoMap = fields.fieldInfoMap(i);
+                curFields = fields.fields(i);
 
                 try {
                     mtd.invoke(obj, this);
@@ -491,7 +504,7 @@ class OptimizedObjectInputStream extends ObjectInputStream {
                 }
             }
             else
-                readFields(obj, fields.fieldOffs(i));
+                readFields(obj, fields.fields(i));
         }
 
         if (readResolveMtd != null) {
@@ -1008,7 +1021,7 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
      */
     private static class GetFieldImpl extends GetField {
         /** Field info map. */
-        private final Map<String, IgniteBiTuple<Integer, OptimizedFieldType>> 
fieldInfoMap;
+        private final OptimizedClassDescriptor.ClassFields fieldInfo;
 
         /** Values. */
         private final Object[] objs;
@@ -1020,18 +1033,16 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
          */
         @SuppressWarnings("ForLoopReplaceableByForEach")
         private GetFieldImpl(OptimizedObjectInputStream in) throws 
IOException, ClassNotFoundException {
-            fieldInfoMap = in.curFieldInfoMap;
-
-            List<IgniteBiTuple<Integer, OptimizedFieldType>> infos = 
in.curFieldInfoList;
+            fieldInfo = in.curFields;
 
-            objs = new Object[infos.size()];
+            objs = new Object[fieldInfo.size()];
 
-            for (int i = 0; i < infos.size(); i++) {
-                IgniteBiTuple<Integer, OptimizedFieldType> t = infos.get(i);
+            for (int i = 0; i < fieldInfo.size(); i++) {
+                OptimizedClassDescriptor.FieldInfo t = fieldInfo.get(i);
 
                 Object obj = null;
 
-                switch (t.get2()) {
+                switch (t.type()) {
                     case BYTE:
                         obj = in.readByte();
 
@@ -1076,7 +1087,7 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
                         obj = in.readObject();
                 }
 
-                objs[t.get1()] = obj;
+                objs[i] = obj;
             }
         }
 
@@ -1087,7 +1098,7 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
 
         /** {@inheritDoc} */
         @Override public boolean defaulted(String name) throws IOException {
-            return objs[fieldInfoMap.get(name).get1()] == null;
+            return objs[fieldInfo.getIndex(name)] == null;
         }
 
         /** {@inheritDoc} */
@@ -1142,7 +1153,7 @@ class OptimizedObjectInputStream extends 
ObjectInputStream {
          */
         @SuppressWarnings("unchecked")
         private <T> T value(String name, T dflt) {
-            return objs[fieldInfoMap.get(name).get1()] != null ? 
(T)objs[fieldInfoMap.get(name).get1()] : dflt;
+            return objs[fieldInfo.getIndex(name)] != null ? 
(T)objs[fieldInfo.getIndex(name)] : dflt;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/75ea4a3d/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 c5f9f08..82ae129 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
@@ -61,10 +61,7 @@ class OptimizedObjectOutputStream extends ObjectOutputStream 
{
     private Object curObj;
 
     /** */
-    private List<T2<OptimizedFieldType, Long>> curFields;
-
-    /** */
-    private Map<String, IgniteBiTuple<Integer, OptimizedFieldType>> 
curFieldInfoMap;
+    private OptimizedClassDescriptor.ClassFields curFields;
 
     /** */
     private PutFieldImpl curPut;
@@ -158,7 +155,6 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
         curObj = null;
         curFields = null;
         curPut = null;
-        curFieldInfoMap = null;
 
         if (obj == null)
             writeByte(NULL);
@@ -309,8 +305,7 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
 
             if (mtd != null) {
                 curObj = obj;
-                curFields = fields.fieldOffs(i);
-                curFieldInfoMap = fields.fieldInfoMap(i);
+                curFields = fields.fields(i);
 
                 try {
                     mtd.invoke(obj, this);
@@ -323,7 +318,7 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
                 }
             }
             else
-                writeFields(obj, fields.fieldOffs(i));
+                writeFields(obj, fields.fields(i));
         }
     }
 
@@ -452,57 +447,66 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
      * Writes all non-static and non-transient field values to this stream.
      *
      * @param obj Object.
-     * @param fieldOffs Field offsets.
+     * @param fields Fields.
      * @throws IOException In case of error.
      */
     @SuppressWarnings("ForLoopReplaceableByForEach")
-    private void writeFields(Object obj, List<T2<OptimizedFieldType, Long>> 
fieldOffs) throws IOException {
-        for (int i = 0; i < fieldOffs.size(); i++) {
-            T2<OptimizedFieldType, Long> t = fieldOffs.get(i);
+    private void writeFields(Object obj, OptimizedClassDescriptor.ClassFields 
fields) throws IOException {
+        for (int i = 0; i < fields.size(); i++) {
+            OptimizedClassDescriptor.FieldInfo t = fields.get(i);
 
-            switch (t.get1()) {
+            switch (t.type()) {
                 case BYTE:
-                    writeByte(getByte(obj, t.get2()));
+                    if (t.field() != null)
+                        writeByte(getByte(obj, t.offset()));
 
                     break;
 
                 case SHORT:
-                    writeShort(getShort(obj, t.get2()));
+                    if (t.field() != null)
+                        writeShort(getShort(obj, t.offset()));
 
                     break;
 
                 case INT:
-                    writeInt(getInt(obj, t.get2()));
+                    if (t.field() != null)
+                        writeInt(getInt(obj, t.offset()));
 
                     break;
 
                 case LONG:
-                    writeLong(getLong(obj, t.get2()));
+                    if (t.field() != null)
+                        writeLong(getLong(obj, t.offset()));
 
                     break;
 
                 case FLOAT:
-                    writeFloat(getFloat(obj, t.get2()));
+                    if (t.field() != null)
+                        writeFloat(getFloat(obj, t.offset()));
 
                     break;
 
                 case DOUBLE:
-                    writeDouble(getDouble(obj, t.get2()));
+                    if (t.field() != null)
+                        writeDouble(getDouble(obj, t.offset()));
 
                     break;
 
                 case CHAR:
-                    writeChar(getChar(obj, t.get2()));
+                    if (t.field() != null)
+                        writeChar(getChar(obj, t.offset()));
 
                     break;
 
                 case BOOLEAN:
-                    writeBoolean(getBoolean(obj, t.get2()));
+                    if (t.field() != null)
+                        writeBoolean(getBoolean(obj, t.offset()));
 
                     break;
 
                 case OTHER:
-                    writeObject0(getObject(obj, t.get2()));
+                    if (t.field() != null)
+                        writeObject0(getObject(obj, t.offset()));
             }
         }
     }
@@ -750,7 +754,6 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
         curObj = null;
         curFields = null;
         curPut = null;
-        curFieldInfoMap = null;
     }
 
     /** {@inheritDoc} */
@@ -780,9 +783,8 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
         /** Stream. */
         private final OptimizedObjectOutputStream out;
 
-        /** Field info map. */
-        private final Map<String, IgniteBiTuple<Integer, OptimizedFieldType>> 
fieldInfoMap;
-
+        /** Fields info. */
+        private final OptimizedClassDescriptor.ClassFields curFields;
         /** Values. */
         private final IgniteBiTuple<OptimizedFieldType, Object>[] objs;
 
@@ -793,9 +795,9 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
         private PutFieldImpl(OptimizedObjectOutputStream out) {
             this.out = out;
 
-            fieldInfoMap = out.curFieldInfoMap;
+            curFields = out.curFields;
 
-            objs = new IgniteBiTuple[fieldInfoMap.size()];
+            objs = new IgniteBiTuple[curFields.size()];
         }
 
         /** {@inheritDoc} */
@@ -856,9 +858,11 @@ class OptimizedObjectOutputStream extends 
ObjectOutputStream {
          * @param val Value.
          */
         private void value(String name, Object val) {
-            IgniteBiTuple<Integer, OptimizedFieldType> info = 
fieldInfoMap.get(name);
+            int i = curFields.getIndex(name);
+
+            OptimizedClassDescriptor.FieldInfo info = curFields.get(i);
 
-            objs[info.get1()] = F.t(info.get2(), val);
+            objs[i] = F.t(info.type(), val);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/75ea4a3d/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSerialPersistentFieldsSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSerialPersistentFieldsSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSerialPersistentFieldsSelfTest.java
new file mode 100644
index 0000000..3dbbd4c
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/marshaller/optimized/OptimizedMarshallerSerialPersistentFieldsSelfTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.testframework.junits.common.*;
+
+import java.io.*;
+
+/**
+ * Test that Optimized Marshaller works with classes with 
serialPersistentFields.
+ */
+public class OptimizedMarshallerSerialPersistentFieldsSelfTest extends 
GridCommonAbstractTest {
+    /**
+     * @throws Exception If failed.
+     */
+    public void testOptimizedMarshaller() throws Exception {
+        OptimizedMarshaller m = new OptimizedMarshaller();
+
+        m.unmarshal(m.marshal(new TestClass()), 
TestClass.class.getClassLoader());
+
+        TestClass2 val = m.unmarshal(m.marshal(new TestClass2()), 
TestClass2.class.getClassLoader());
+
+        assertNull(val.field3);
+    }
+
+    /**
+     * Test class with serialPersistentFields fields.
+     */
+    private static class TestClass implements Serializable {
+        private static final long serialVersionUID = 0L;
+
+        /** For serialization compatibility. */
+        private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("field1", Integer.TYPE),
+            new ObjectStreamField("field2", Integer.TYPE)
+        };
+
+        /**
+         * @param s Object output stream.
+         */
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            s.putFields().put("field1", 1);
+            s.putFields().put("field2", 2);
+            s.writeFields();
+
+            s.writeObject(null);
+        }
+
+        /**
+         * @param s Object input stream.
+         */
+        private void readObject(ObjectInputStream s) throws IOException, 
ClassNotFoundException {
+            s.defaultReadObject();
+
+            s.readObject();
+        }
+    }
+
+    /**
+     * Test class with serialPersistentFields fields.
+     */
+    private static class TestClass2 implements Serializable {
+        private static final long serialVersionUID = 0L;
+
+        private Integer field3 = 1;
+
+        /** For serialization compatibility. */
+        private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("field1", Integer.TYPE),
+            new ObjectStreamField("field2", Integer.TYPE)
+        };
+
+        /**
+         * @param s Object output stream.
+         */
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            s.putFields().put("field1", 1);
+            s.putFields().put("field2", 2);
+            s.writeFields();
+
+            s.writeObject(null);
+        }
+
+        /**
+         * @param s Object input stream.
+         */
+        private void readObject(ObjectInputStream s) throws IOException, 
ClassNotFoundException {
+            s.defaultReadObject();
+
+            s.readObject();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/75ea4a3d/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 1d7f196..10afe10 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
@@ -40,6 +40,7 @@ public class IgniteMarshallerSelfTestSuite extends TestSuite {
         suite.addTest(new TestSuite(OptimizedObjectStreamSelfTest.class));
         suite.addTest(new 
TestSuite(GridUnsafeDataOutputArraySizingSelfTest.class));
         suite.addTest(new 
TestSuite(OptimizedMarshallerNodeFailoverTest.class));
+        suite.addTest(new 
TestSuite(OptimizedMarshallerSerialPersistentFieldsSelfTest.class));
 
         return suite;
     }

Reply via email to