IGNITE-5444: Collections.singletonList is not properly serialized by binary 
marshaller. This closes #2217.


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

Branch: refs/heads/ignite-5578-locJoin
Commit: 038a90a98e3d6dce4514d55710955789ea30d2cb
Parents: c0c6c2f
Author: Andrey V. Mashenkov <andrey.mashen...@gmail.com>
Authored: Fri Jul 14 16:41:41 2017 +0300
Committer: Andrey V. Mashenkov <andrey.mashen...@gmail.com>
Committed: Fri Jul 14 16:41:41 2017 +0300

----------------------------------------------------------------------
 .../ignite/internal/binary/BinaryContext.java   |  1 +
 .../ignite/internal/binary/BinaryUtils.java     | 19 +++++--
 .../internal/binary/GridBinaryMarshaller.java   |  3 ++
 .../processors/cache/CacheObjectUtils.java      |  4 +-
 .../binary/CacheObjectBinaryProcessorImpl.java  |  3 +-
 .../platform/utils/PlatformUtils.java           |  3 +-
 .../ignite/internal/util/IgniteUtils.java       | 11 ++++
 .../internal/util/MutableSingletonList.java     | 53 ++++++++++++++++++++
 .../BinaryObjectBuilderAdditionalSelfTest.java  |  2 +-
 .../GridCacheBinaryObjectsAbstractSelfTest.java | 28 +++++++++++
 10 files changed, 120 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
index fa051f5..eaac7b8 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryContext.java
@@ -275,6 +275,7 @@ public class BinaryContext {
 
         colTypes.put(ArrayList.class, GridBinaryMarshaller.ARR_LIST);
         colTypes.put(LinkedList.class, GridBinaryMarshaller.LINKED_LIST);
+        colTypes.put(BinaryUtils.SINGLETON_LIST_CLS, 
GridBinaryMarshaller.SINGLETON_LIST);
         colTypes.put(HashSet.class, GridBinaryMarshaller.HASH_SET);
         colTypes.put(LinkedHashSet.class, 
GridBinaryMarshaller.LINKED_HASH_SET);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
index 969f3e1..74d1730 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/BinaryUtils.java
@@ -32,6 +32,7 @@ import java.sql.Time;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -59,6 +60,7 @@ import org.apache.ignite.binary.BinaryType;
 import org.apache.ignite.binary.Binarylizable;
 import org.apache.ignite.internal.binary.builder.BinaryLazyValue;
 import org.apache.ignite.internal.binary.streams.BinaryInputStream;
+import org.apache.ignite.internal.util.MutableSingletonList;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiTuple;
@@ -92,6 +94,9 @@ public class BinaryUtils {
     /** Binary classes. */
     private static final Collection<Class<?>> BINARY_CLS = new HashSet<>();
 
+    /** Class for SingletonList obtained at runtime. */
+    public static final Class<? extends Collection> SINGLETON_LIST_CLS = 
Collections.singletonList(null).getClass();
+
     /** Flag: user type. */
     public static final short FLAG_USR_TYP = 0x0001;
 
@@ -697,7 +702,8 @@ public class BinaryUtils {
             (!wrapTrees() && cls == TreeSet.class) ||
             cls == ConcurrentSkipListSet.class ||
             cls == ArrayList.class ||
-            cls == LinkedList.class;
+            cls == LinkedList.class ||
+            cls == SINGLETON_LIST_CLS;
     }
 
     /**
@@ -738,6 +744,8 @@ public class BinaryUtils {
             return new ArrayList<>(((Collection)col).size());
         else if (cls == LinkedList.class)
             return new LinkedList<>();
+        else if (cls == SINGLETON_LIST_CLS)
+            return new MutableSingletonList<>();
 
         return null;
     }
@@ -1132,7 +1140,7 @@ public class BinaryUtils {
      * @return {@code True} if this is a special collection class.
      */
     public static boolean isSpecialCollection(Class cls) {
-        return ArrayList.class.equals(cls) || LinkedList.class.equals(cls) ||
+        return ArrayList.class.equals(cls) || LinkedList.class.equals(cls) || 
SINGLETON_LIST_CLS.equals(cls) ||
             HashSet.class.equals(cls) || LinkedHashSet.class.equals(cls);
     }
 
@@ -2023,6 +2031,11 @@ public class BinaryUtils {
 
                     break;
 
+                case GridBinaryMarshaller.SINGLETON_LIST:
+                    col = new MutableSingletonList<>();
+
+                    break;
+
                 case GridBinaryMarshaller.HASH_SET:
                     col = U.newHashSet(size);
 
@@ -2053,7 +2066,7 @@ public class BinaryUtils {
         for (int i = 0; i < size; i++)
             col.add(deserializeOrUnmarshal(in, ctx, ldr, handles, 
deserialize));
 
-        return col;
+        return colType == GridBinaryMarshaller.SINGLETON_LIST ? 
U.convertToSingletonList(col) : col;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
index 291c638..d6c8abd 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/binary/GridBinaryMarshaller.java
@@ -184,6 +184,9 @@ public class GridBinaryMarshaller {
     public static final byte LINKED_HASH_SET = 4;
 
     /** */
+    public static final byte SINGLETON_LIST = 5;
+
+    /** */
     public static final byte HASH_MAP = 1;
 
     /** */

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
index f9c76df..5afa751 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectUtils.java
@@ -18,7 +18,9 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.internal.binary.BinaryUtils;
+import org.apache.ignite.internal.util.MutableSingletonList;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -66,7 +68,7 @@ public class CacheObjectUtils {
         for (Object obj : col)
             col0.add(unwrapBinary(ctx, obj, keepBinary, cpy));
 
-        return col0;
+        return (col0 instanceof MutableSingletonList) ? 
U.convertToSingletonList(col0) : col0;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
index 0065e41..c0f3515 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/CacheObjectBinaryProcessorImpl.java
@@ -66,6 +66,7 @@ import 
org.apache.ignite.internal.processors.cache.KeyCacheObject;
 import 
org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessorImpl;
 import org.apache.ignite.internal.util.GridUnsafe;
 import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.MutableSingletonList;
 import org.apache.ignite.internal.util.future.GridFutureAdapter;
 import org.apache.ignite.internal.util.lang.GridMapEntry;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
@@ -349,7 +350,7 @@ public class CacheObjectBinaryProcessorImpl extends 
IgniteCacheObjectProcessorIm
                 for (Object item : col)
                     pCol.add(marshalToBinary(item));
 
-                return pCol;
+                return (pCol instanceof MutableSingletonList) ? 
U.convertToSingletonList(pCol) : pCol;
             }
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
index 654a2a1..dbd65ed 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformUtils.java
@@ -58,6 +58,7 @@ import 
org.apache.ignite.internal.processors.platform.memory.PlatformInputStream
 import org.apache.ignite.internal.processors.platform.memory.PlatformMemory;
 import 
org.apache.ignite.internal.processors.platform.memory.PlatformMemoryUtils;
 import 
org.apache.ignite.internal.processors.platform.memory.PlatformOutputStream;
+import org.apache.ignite.internal.util.MutableSingletonList;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.U;
@@ -941,7 +942,7 @@ public class PlatformUtils {
         for (Object obj : col)
             col0.add(unwrapBinary(obj));
 
-        return col0;
+        return (col0 instanceof MutableSingletonList) ? 
U.convertToSingletonList(col0) : col0;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java 
b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index 6a3be55..54ffe41 100755
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -9343,6 +9343,17 @@ public abstract class IgniteUtils {
     }
 
     /**
+     * @param col non-null collection with one element
+     * @return a SingletonList containing the element in the original 
collection
+     */
+    public static <T> Collection<T> convertToSingletonList(Collection<T> col) {
+        if (col.size() != 1) {
+            throw new IllegalArgumentException("Unexpected collection size for 
singleton list, expecting 1 but was: " + col.size());
+        }
+        return Collections.singletonList(col.iterator().next());
+    }
+
+    /**
      * Returns comparator that sorts remote node addresses. If remote node 
resides on the same host, then put
      * loopback addresses first, last otherwise.
      *

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/main/java/org/apache/ignite/internal/util/MutableSingletonList.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/util/MutableSingletonList.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/util/MutableSingletonList.java
new file mode 100644
index 0000000..87b96de
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/util/MutableSingletonList.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.util;
+
+
+import java.util.AbstractList;
+
+/**
+ * List that can contain maximum of one element. Does not allow null element 
to be added.
+ */
+public class MutableSingletonList<E> extends AbstractList<E> {
+
+    /** The only element of collection. */
+    private E element;
+
+    /** {@inheritDoc} */
+    @Override public E get(int index) {
+        if (index != 0 || element == null)
+            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " 
+ size());
+
+        return element;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void add(int index, E element) {
+        if (element == null)
+            throw new IllegalArgumentException("Cannot add null element to 
list");
+        else if (index != 0)
+            throw new IllegalStateException("Element already added to 
singleton list");
+        else
+            this.element = element;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int size() {
+        return element == null ? 0 : 1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java
index 145dbb4..82ff383 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinaryObjectBuilderAdditionalSelfTest.java
@@ -1511,7 +1511,7 @@ public class BinaryObjectBuilderAdditionalSelfTest 
extends GridCommonAbstractTes
 
         assert MAP.equals(binaryObj.type().fieldTypeName("singletonMap"));
 
-        assert OBJ.equals(binaryObj.type().fieldTypeName("asList"));
+        assert COL.equals(binaryObj.type().fieldTypeName("asList"));
         assert OBJ.equals(binaryObj.type().fieldTypeName("asSet"));
         assert OBJ.equals(binaryObj.type().fieldTypeName("asMap"));
         assert OBJ.equals(binaryObj.type().fieldTypeName("asListHint"));

http://git-wip-us.apache.org/repos/asf/ignite/blob/038a90a9/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectsAbstractSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectsAbstractSelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectsAbstractSelfTest.java
index 5dace92..b98615c 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectsAbstractSelfTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/binary/GridCacheBinaryObjectsAbstractSelfTest.java
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -424,6 +425,33 @@ public abstract class 
GridCacheBinaryObjectsAbstractSelfTest extends GridCommonA
     /**
      * @throws Exception If failed.
      */
+    public void testSingletonList() throws Exception {
+        IgniteCache<Integer, Collection<TestObject>> c = jcache(0);
+
+        c.put(0, Collections.singletonList(new TestObject(123)));
+
+        Collection<TestObject> cFromCache = c.get(0);
+
+        assertEquals(1, cFromCache.size());
+        assertEquals(123, cFromCache.iterator().next().val);
+
+        IgniteCache<Integer, Collection<BinaryObject>> kpc = keepBinaryCache();
+
+        Collection<?> cBinary = kpc.get(0);
+
+        assertEquals(1, cBinary.size());
+
+        Object bObj = cBinary.iterator().next();
+
+        assertTrue(bObj instanceof BinaryObject);
+        assertEquals(Collections.singletonList(null).getClass(), 
cBinary.getClass());
+
+        assertEquals(Integer.valueOf(123), ((BinaryObject) bObj).field("val"));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
     public void testGetAsync() throws Exception {
         IgniteCache<Integer, TestObject> c = jcache(0);
 

Reply via email to