You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ip...@apache.org on 2020/01/23 11:43:24 UTC

[ignite] branch master updated: IGNITE-12569 Can't set serialized enum to a BinaryObject's field - Fixes #7292.

This is an automated email from the ASF dual-hosted git repository.

ipavlukhin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new e89c71d  IGNITE-12569 Can't set serialized enum to a BinaryObject's field - Fixes #7292.
e89c71d is described below

commit e89c71d3cb769ebe25c09e241cfc6cd511b150b3
Author: korlov42 <ko...@gridgain.com>
AuthorDate: Thu Jan 23 14:42:57 2020 +0300

    IGNITE-12569 Can't set serialized enum to a BinaryObject's field - Fixes #7292.
    
    Signed-off-by: ipavlukhin <vo...@gmail.com>
---
 .../apache/ignite/internal/binary/BinaryUtils.java |   2 +-
 .../binary/builder/BinaryBuilderSerializer.java    |  35 +++---
 .../binary/builder/BinaryObjectBuilderImpl.java    |  11 +-
 .../BinaryObjectBuilderAdditionalSelfTest.java     | 139 ++++++++++++++++++---
 .../BinarySimpleNameTestPropertySelfTest.java      |   3 +-
 5 files changed, 152 insertions(+), 38 deletions(-)

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 9568c4b..84e4e97 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
@@ -1715,7 +1715,7 @@ public class BinaryUtils {
     private static Object[] doReadBinaryEnumArray(BinaryInputStream in, BinaryContext ctx) {
         int len = in.readInt();
 
-        Object[] arr = (Object[])Array.newInstance(BinaryObject.class, len);
+        Object[] arr = (Object[])Array.newInstance(BinaryEnumObjectImpl.class, len);
 
         for (int i = 0; i < len; i++) {
             byte flag = in.readByte();
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
index 9e6411f..439e65c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryBuilderSerializer.java
@@ -19,10 +19,9 @@ package org.apache.ignite.internal.binary.builder;
 
 import java.util.Collection;
 import java.util.IdentityHashMap;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import org.apache.ignite.binary.BinaryObject;
-import org.apache.ignite.internal.binary.BinaryMetadata;
+import org.apache.ignite.internal.binary.BinaryEnumObjectImpl;
 import org.apache.ignite.internal.binary.BinaryObjectExImpl;
 import org.apache.ignite.internal.binary.BinaryUtils;
 import org.apache.ignite.internal.binary.BinaryWriterExImpl;
@@ -111,22 +110,24 @@ class BinaryBuilderSerializer {
             return;
         }
 
-        if (IgniteUtils.isEnum(val.getClass())) {
-            String clsName = ((Enum)val).getDeclaringClass().getName();
+        if (val instanceof BinaryEnumObjectImpl) {
+            BinaryEnumObjectImpl obj = (BinaryEnumObjectImpl)val;
 
-            int typeId = writer.context().typeId(clsName);
-            String typeName = writer.context().userTypeName(clsName);
+            writer.writeByte(GridBinaryMarshaller.ENUM);
+            writer.writeInt(obj.typeId());
 
-            Object[] enumVals = val.getClass().getEnumConstants();
+            if (obj.typeId() == GridBinaryMarshaller.UNREGISTERED_TYPE_ID)
+                writer.doWriteString(obj.className());
 
-            Map<String, Integer> enumMap = new LinkedHashMap<>(enumVals.length);
+            writer.writeInt(obj.enumOrdinal());
 
-            for (Object enumVal : enumVals)
-                enumMap.put(((Enum)enumVal).name(), ((Enum)enumVal).ordinal());
+            return;
+        }
 
-            BinaryMetadata meta = new BinaryMetadata(typeId, typeName, null, null, null, true, enumMap);
+        if (IgniteUtils.isEnum(val.getClass())) {
+            String clsName = ((Enum)val).getDeclaringClass().getName();
 
-            writer.context().updateMetadata(typeId, meta, writer.failIfUnregistered());
+            int typeId = writer.context().typeId(clsName);
 
             // Need register class for marshaller to be able to deserialize enum value.
             writer.context().registerClass(((Enum)val).getDeclaringClass(), true, false);
@@ -179,17 +180,21 @@ class BinaryBuilderSerializer {
         }
 
         if (val instanceof Object[]) {
-            int compTypeId = writer.context().typeId(((Object[])val).getClass().getComponentType().getName());
+            Class<?> compCls = ((Object[])val).getClass().getComponentType();
 
-            if (val instanceof BinaryBuilderEnum[]) {
+            int compTypeId = writer.context().typeId(compCls.getName());
+
+            if (BinaryEnumObjectImpl.class.isAssignableFrom(compCls) || val instanceof BinaryBuilderEnum[]) {
                 writeArray(writer, GridBinaryMarshaller.ENUM_ARR, (Object[])val, compTypeId);
 
                 return;
             }
 
-            if (((Object[])val).getClass().getComponentType().isEnum()) {
+            if (compCls.isEnum()) {
                 Enum[] enumArr = (Enum[])val;
 
+                writer.context().registerClass(compCls, true, false);
+
                 writer.writeByte(GridBinaryMarshaller.ENUM_ARR);
                 writer.writeInt(compTypeId);
                 writer.writeInt(enumArr.length);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
index 45a13c0..48c3fce 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/binary/builder/BinaryObjectBuilderImpl.java
@@ -402,12 +402,13 @@ public class BinaryObjectBuilderImpl implements BinaryObjectBuilder {
         // Detect Enum and Enum array type.
         else if (newVal instanceof BinaryEnumObjectImpl)
             newFldTypeId = GridBinaryMarshaller.ENUM;
-        else if (newVal.getClass().isArray() && newVal.getClass().getComponentType() == BinaryObject.class) {
-            BinaryObject[] arr = (BinaryObject[])newVal;
 
-            newFldTypeId = arr.length > 0 && arr[0] instanceof BinaryEnumObjectImpl ?
-                GridBinaryMarshaller.ENUM_ARR : GridBinaryMarshaller.OBJ_ARR;
-        }
+        else if (newVal.getClass().isArray() && BinaryEnumObjectImpl.class.isAssignableFrom(newVal.getClass().getComponentType()))
+            newFldTypeId = GridBinaryMarshaller.ENUM_ARR;
+
+        else if (newVal.getClass().isArray() && BinaryObject.class.isAssignableFrom(newVal.getClass().getComponentType()))
+            newFldTypeId = GridBinaryMarshaller.OBJ_ARR;
+
         else
             newFldTypeId = BinaryUtils.typeByClass(newVal.getClass());
 
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 b24d9d6..2877a64 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
@@ -1500,6 +1500,14 @@ public class BinaryObjectBuilderAdditionalSelfTest extends GridCommonAbstractTes
             processor.binaryContext().userTypeName(typeName));
     }
 
+    /** */
+    private void clearBinaryMeta() {
+        BinaryContext binCtx = ((CacheObjectBinaryProcessorImpl)((IgniteBinaryImpl)binaries()).processor()).binaryContext();
+
+        binCtx.unregisterBinarySchemas();
+        binCtx.unregisterUserTypeDescriptors();
+    }
+
     /**
      * Check that correct type is stored in binary object.
      */
@@ -1618,28 +1626,102 @@ public class BinaryObjectBuilderAdditionalSelfTest extends GridCommonAbstractTes
 
     /**
      * Checks correct serialization/deserialization of enums in builder.
-     *
-     * @throws Exception If failed.
      */
     @Test
-    public void testEnum() throws Exception {
-        BinaryObjectBuilder builder = newWrapper("TestType");
+    public void testEnum() {
+        try {
+            BinaryObjectBuilder builder = newWrapper(TestClsWithEnum.class.getName());
+
+            TestEnum[] expArr = {TestEnum.A, TestEnum.B};
+
+            BinaryObject enumObj = builder
+                .setField("testEnumA", TestEnum.A)
+                .setField("testEnumB", TestEnum.B)
+                .setField("testEnumArr", expArr)
+                .build();
+
+            Assert.assertSame(TestEnum.A, ((BinaryObject)enumObj.field("testEnumA")).deserialize());
+            Assert.assertSame(TestEnum.B, ((BinaryObject)enumObj.field("testEnumB")).deserialize());
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+
+            Assert.assertSame(TestEnum.A, ((TestClsWithEnum)enumObj.deserialize()).testEnumA);
+            Assert.assertSame(TestEnum.B, ((TestClsWithEnum)enumObj.deserialize()).testEnumB);
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+
+            builder = newWrapper(enumObj.type().typeName());
+
+            enumObj = builder
+                .setField("testEnumA", (Object)enumObj.field("testEnumA"))
+                .setField("testEnumB", (Object)enumObj.field("testEnumB"))
+                .setField("testEnumArr", (Object)enumObj.field("testEnumArr"))
+                .build();
+
+            Assert.assertSame(TestEnum.A, ((BinaryObject)enumObj.field("testEnumA")).deserialize());
+            Assert.assertSame(TestEnum.B, ((BinaryObject)enumObj.field("testEnumB")).deserialize());
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+
+            Assert.assertSame(TestEnum.A, ((TestClsWithEnum)enumObj.deserialize()).testEnumA);
+            Assert.assertSame(TestEnum.B, ((TestClsWithEnum)enumObj.deserialize()).testEnumB);
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+
+            builder = newWrapper(enumObj.type().typeName());
+
+            expArr = new TestEnum[0];
+
+            enumObj = builder.setField("testEnumArr", expArr).build();
+
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+
+            enumObj = builder.setField("testEnumArr", (Object)enumObj.field("testEnumArr")).build();
+
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+        }
+        finally {
+            clearBinaryMeta();
+        }
+    }
 
-        final TestEnum exp = TestEnum.A;
-        final TestEnum[] expArr = {TestEnum.A, TestEnum.B};
+    /** */
+    @Test
+    public void testEnum2() {
+        try {
+            BinaryObjectBuilder builder = newWrapper(TestClsWithEnum.class.getName());
+
+            Object[] expArr = new TestEnum[0];
+
+            BinaryObject enumObj = builder.setField("testEnumArr", expArr).build();
+
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+
+            builder = newWrapper(enumObj.type().typeName());
 
-        BinaryObject enumObj = builder.setField("testEnum", exp).setField("testEnumArr", expArr).build();
+            enumObj = builder.setField("testEnumArr", (Object)enumObj.field("testEnumArr")).build();
 
-        assertEquals(exp, ((BinaryObject)enumObj.field("testEnum")).deserialize());
-        Assert.assertArrayEquals(expArr, (Object[])deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
 
-        builder = newWrapper(enumObj.type().typeName());
+            expArr = new TestEnum[] {TestEnum.A, TestEnum.B};
 
-        enumObj = builder.setField("testEnum", (Object)enumObj.field("testEnum"))
-            .setField("testEnumArr", (Object)enumObj.field("testEnumArr")).build();
+            builder = newWrapper(enumObj.type().typeName());
 
-        assertEquals(exp, ((BinaryObject)enumObj.field("testEnum")).deserialize());
-        Assert.assertArrayEquals(expArr, (Object[])deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            enumObj = builder.setField("testEnumArr", expArr).build();
+
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+
+            builder = newWrapper(enumObj.type().typeName());
+
+            enumObj = builder.setField("testEnumArr", (Object)enumObj.field("testEnumArr")).build();
+
+            Assert.assertArrayEquals(expArr, deserializeEnumBinaryArray(enumObj.field("testEnumArr")));
+            Assert.assertArrayEquals(expArr, ((TestClsWithEnum)enumObj.deserialize()).testEnumArr);
+        }
+        finally {
+            clearBinaryMeta();
+        }
     }
 
     /**
@@ -1759,12 +1841,39 @@ public class BinaryObjectBuilderAdditionalSelfTest extends GridCommonAbstractTes
         }
     }
 
+    /** Test class with enum and array of enums. */
+    public static class TestClsWithEnum {
+        /** */
+        private final TestEnum testEnumA;
+
+        /** */
+        private final TestEnum testEnumB;
+
+        /** */
+        private final TestEnum[] testEnumArr;
+
+        /** */
+        public TestClsWithEnum(TestEnum testEnumA, TestEnum testEnumB, TestEnum[] testEnumArr) {
+            this.testEnumA = testEnumA;
+            this.testEnumB = testEnumB;
+            this.testEnumArr = testEnumArr;
+        }
+    }
+
     /**
      *
      */
     private enum TestEnum {
         /** */
-        A,
+        A {
+            /**
+             * An empty function is needed so that {@link TestEnum#A}
+             * becomes a subclass.
+             */
+            public void foo() {
+
+            }
+        },
 
         /** */
         B
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java
index 7e1709e..22a5d24 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/binary/BinarySimpleNameTestPropertySelfTest.java
@@ -65,8 +65,7 @@ public class BinarySimpleNameTestPropertySelfTest extends GridCommonAbstractTest
             checkProperty("TestClass");
         }
         finally {
-            if (useSimpleNameBackup != null)
-                GridTestProperties.setProperty(BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER, "true");
+            GridTestProperties.setProperty(BINARY_MARSHALLER_USE_SIMPLE_NAME_MAPPER, useSimpleNameBackup);
         }
     }