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

petrov-mg 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 f86423746a0 IGNITE-28963 Added support for EnumSet collection type 
during message serialization  (#13451)
f86423746a0 is described below

commit f86423746a0ef992657ced28ba8714bb87ba1161
Author: Mikhail Petrov <[email protected]>
AuthorDate: Sun Aug 9 14:23:11 2026 +0300

    IGNITE-28963 Added support for EnumSet collection type during message 
serialization  (#13451)
---
 .../internal/MessageSerializerGenerator.java       |  35 ++++++-
 .../direct/stream/DirectByteBufferStream.java      |  17 +++-
 .../processors/security/SecurityUtils.java         |  32 ++----
 .../security/SecurityBasicPermissionSet.java       | 112 ++++++++++++---------
 .../internal/codegen/MessageProcessorTest.java     |  25 +++++
 .../direct/DirectMarshallingMessagesTest.java      |  46 +++++++++
 .../direct/TestNestedContainersMessage.java        |  15 ++-
 .../managers/AbstractMessageSerializationTest.java |   5 +-
 ...ecurityBasicPermissionSetSerializationTest.java |  12 +--
 .../CustomMapperEnumFieldsMessageSerializer.java   |   3 +-
 .../DefaultMapperEnumFieldsMessageSerializer.java  |   5 +-
 .../codegen/TestCollectionsMessageSerializer.java  |  53 +++++-----
 .../codegen/TestEnumSetMessage.java}               |  26 ++---
 ...izer.java => TestEnumSetMessageSerializer.java} |  51 ++++------
 .../codegen/TestMapMessageSerializer.java          |   5 +-
 .../TestMarshalledArrayMapMessageSerializer.java   |   5 +-
 .../TestMarshalledMapMessageSerializer.java        |   5 +-
 .../TestMarshalledObjectsMessageSerializer.java    |   3 +-
 .../codegen/WrongEnumSetMessage.java}              |  29 ++----
 ...Type.java => CollectionImplementationType.java} |  37 ++-----
 .../communication/MessageCollectionType.java       |  16 +--
 .../extensions/communication/MessageEnumType.java  |  13 ++-
 22 files changed, 312 insertions(+), 238 deletions(-)

diff --git 
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
 
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
index 6ae7e029410..81680f1b108 100644
--- 
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
+++ 
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
@@ -23,6 +23,7 @@ import java.io.Writer;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -86,6 +87,9 @@ public class MessageSerializerGenerator extends 
MessageCompanionGenerator {
     /** */
     private static final String MESSAGE_COLLECTION_TYPE_CLS = 
"org.apache.ignite.plugin.extensions.communication.MessageCollectionType";
 
+    /** */
+    private static final String COLLECTION_IMPL_TYPE_CLS = 
"org.apache.ignite.plugin.extensions.communication.CollectionImplementationType";
+
     /** */
     private static final String IGNITE_UUID_CLS = 
"org.apache.ignite.lang.IgniteUuid";
 
@@ -552,9 +556,17 @@ public class MessageSerializerGenerator extends 
MessageCompanionGenerator {
 
             assert typeArgs.size() == 1 : type.toString();
 
-            return "new MessageCollectionType(" +
-                messageCollectionItemTypeDescriptor(typeArgs.get(0), field) + 
", " +
-                assignableFrom(erasedType(type), type(Set.class.getName())) + 
")";
+            TypeMirror itemType = typeArgs.get(0);
+
+            if 
(EnumSet.class.getName().equals(qualifiedClassName(erasedType(type))) && 
!enumType(env, itemType))
+                throw new IllegalArgumentException("Unexpected Enum Set 
element type [itemType=" + itemType + ", colType=" + type + ']');
+
+            imports.add(COLLECTION_IMPL_TYPE_CLS);
+
+            String implType = resolveCollectionImplementationType(type);
+
+            return "new MessageCollectionType(" + 
messageCollectionItemTypeDescriptor(itemType, field) +
+                ", CollectionImplementationType." + implType + ")";
         }
         else if (enumType(env, type)) {
             
imports.add("org.apache.ignite.plugin.extensions.communication.MessageEnumType");
@@ -566,7 +578,7 @@ public class MessageSerializerGenerator extends 
MessageCompanionGenerator {
             String decoder = custMapper ? prefix + "Mapper::decode" :
                 "b -> DefaultEnumMapper.INSTANCE.decode(" + prefix + "Vals, 
b)";
 
-            return String.format("new MessageEnumType<>(%s, %s)", encoder, 
decoder);
+            return String.format("new MessageEnumType<>(%s.class, %s, %s)", 
simpleClassName(type), encoder, decoder);
         }
         else {
             imports.add(MESSAGE_ITEM_TYPE_CLS);
@@ -575,6 +587,21 @@ public class MessageSerializerGenerator extends 
MessageCompanionGenerator {
         }
     }
 
+    /**
+     * @param type Declared collection type.
+     * @return Name of the {@code CollectionImplementationType} that will be 
used to create collection instance.
+     */
+    private String resolveCollectionImplementationType(TypeMirror type) {
+        TypeMirror declType = erasedType(type);
+
+        if (EnumSet.class.getName().equals(qualifiedClassName(declType)))
+            return "ENUM_SET";
+        else if (assignableFrom(declType, type(Set.class.getName())))
+            return "HASH_SET";
+        else
+            return "ARRAY_LIST";
+    }
+
     /**
      * Find MessageCollectionItemType for a given type.
      * <p>
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
index 75440117e23..c0752343b54 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java
@@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -1639,11 +1640,11 @@ public class DirectByteBufferStream {
     }
 
     /**
-     * Reads collection eather as a {@link ArrayList} or a {@link HashSet}.
+     * Reads collection either as an {@link ArrayList}, a {@link HashSet} or 
an {@link EnumSet}.
      *
      * @param type Item type.
      * @param reader Reader.
-     * @return {@link ArrayList} or a {@link HashSet}.
+     * @return {@link ArrayList}, {@link HashSet} or {@link EnumSet}.
      */
     public <C extends Collection<?>> C readCollection(MessageCollectionType 
type, MessageReader reader) {
         if (readSize == -1) {
@@ -1657,7 +1658,7 @@ public class DirectByteBufferStream {
 
         if (readSize >= 0) {
             if (col == null)
-                col = type.set() ? U.newHashSet(readSize) : new 
ArrayList<>(readSize);
+                col = newCollection(type);
 
             for (int i = readItems; i < readSize; i++) {
                 Object item = read(type.valueType(), reader);
@@ -1682,6 +1683,16 @@ public class DirectByteBufferStream {
         return col0;
     }
 
+    /** */
+    @SuppressWarnings("unchecked")
+    private Collection<Object> newCollection(MessageCollectionType type) {
+        return switch (type.collectionImplementationType()) {
+            case ENUM_SET -> 
(Collection<Object>)((MessageEnumType<?>)type.valueType()).newEnumSet();
+            case HASH_SET -> U.newHashSet(readSize);
+            case ARRAY_LIST -> new ArrayList<>(readSize);
+        };
+    }
+
     /**
      * @param type Value type.
      * @param reader Reader.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
index 452a13cdd54..a8aa2f64c82 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecurityUtils.java
@@ -132,7 +132,7 @@ public class SecurityUtils {
     /**
      * @return Allow all service permissions.
      */
-    public static Map<String, Collection<SecurityPermission>> 
compatibleServicePermissions() {
+    public static Map<String, EnumSet<SecurityPermission>> 
compatibleServicePermissions() {
         Map<String, EnumSet<SecurityPermission>> srvcPerms = new HashMap<>();
 
         srvcPerms.put("*", EnumSet.of(
@@ -140,34 +140,22 @@ public class SecurityUtils {
             SecurityPermission.SERVICE_DEPLOY,
             SecurityPermission.SERVICE_INVOKE));
 
-        return upcast(srvcPerms);
+        return srvcPerms;
     }
 
     /** */
-    @SuppressWarnings("rawtypes")
-    public static Map<String, Collection<SecurityPermission>> 
upcast(Map<String, EnumSet<SecurityPermission>> map) {
-        return (Map<String, Collection<SecurityPermission>>)(Map)map;
-    }
-
-    /** */
-    @SuppressWarnings("rawtypes")
-    public static Map<String, EnumSet<SecurityPermission>> 
downcast(Map<String, Collection<SecurityPermission>> map) {
-        return (Map<String, EnumSet<SecurityPermission>>)(Map)map;
-    }
-
-    /**
-     * @param permissionsMap Permissions map.
-     * @return Map with enum sets of security permissions.
-     */
-    public static Map<String, Collection<SecurityPermission>> 
normalizeValueType(
-        Map<String, Collection<SecurityPermission>> permissionsMap
+    public static Map<String, EnumSet<SecurityPermission>> 
normalizeResourcePermissions(
+        Map<String, ? extends Collection<SecurityPermission>> rsrcPerms
     ) {
-        return permissionsMap.entrySet().stream()
-            .collect(Collectors.toMap(Map.Entry::getKey, e -> 
copySafe(e.getValue())));
+        if (rsrcPerms == null)
+            return new HashMap<>();
+
+        return rsrcPerms.entrySet().stream()
+            .collect(Collectors.toMap(Map.Entry::getKey, e -> 
toEnumSet(e.getValue())));
     }
 
     /** */
-    public static EnumSet<SecurityPermission> 
copySafe(Collection<SecurityPermission> col) {
+    public static EnumSet<SecurityPermission> 
toEnumSet(Collection<SecurityPermission> col) {
         if (col instanceof EnumSet<SecurityPermission> enumSet)
             return enumSet;
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
 
b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
index 5256acb83ab..627cd5a2250 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java
@@ -20,6 +20,7 @@ package org.apache.ignite.plugin.security;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -27,7 +28,6 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import org.apache.ignite.internal.Order;
-import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.internal.A;
 import org.apache.ignite.internal.util.typedef.internal.S;
@@ -35,42 +35,48 @@ import org.apache.ignite.internal.util.typedef.internal.U;
 import org.jetbrains.annotations.Nullable;
 
 import static 
org.apache.ignite.internal.processors.security.SecurityUtils.compatibleServicePermissions;
-import static 
org.apache.ignite.internal.processors.security.SecurityUtils.copySafe;
-import static 
org.apache.ignite.internal.processors.security.SecurityUtils.downcast;
 import static 
org.apache.ignite.internal.processors.security.SecurityUtils.isSecurityCompatibilityMode;
-import static 
org.apache.ignite.internal.processors.security.SecurityUtils.normalizeValueType;
+import static 
org.apache.ignite.internal.processors.security.SecurityUtils.normalizeResourcePermissions;
 import static 
org.apache.ignite.internal.processors.security.SecurityUtils.serializeVersion;
-import static 
org.apache.ignite.internal.processors.security.SecurityUtils.upcast;
+import static 
org.apache.ignite.internal.processors.security.SecurityUtils.toEnumSet;
 
 /**
  * Simple implementation of {@link SecurityPermissionSet} interface.
  * Provides convenient way to specify permission set in the XML configuration.
  */
-public class SecurityBasicPermissionSet implements SecurityPermissionSet, 
SelfMarshallingMessage {
+public class SecurityBasicPermissionSet implements SecurityPermissionSet {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
+    /** */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("dfltAllowAll", boolean.class),
+        new ObjectStreamField("cachePermissions", Map.class),
+        new ObjectStreamField("sysPermissions", Collection.class),
+        new ObjectStreamField("taskPermissions", Map.class)
+    };
+
     /** Cache permissions. */
     @GridToStringInclude
     @Order(0)
-    Map<String, Collection<SecurityPermission>> cachePermissions = new 
HashMap<>();
+    Map<String, EnumSet<SecurityPermission>> cachePermissions = new 
HashMap<>();
 
     /** Task permissions. */
     @GridToStringInclude
     @Order(1)
-    Map<String, Collection<SecurityPermission>> taskPermissions = new 
HashMap<>();
+    Map<String, EnumSet<SecurityPermission>> taskPermissions = new HashMap<>();
 
     /** Service permissions. */
     @GridToStringInclude
     @Order(2)
-    transient Map<String, Collection<SecurityPermission>> srvcPermissions = 
isSecurityCompatibilityMode()
-            ? compatibleServicePermissions()
-            : new HashMap<>();
+    transient Map<String, EnumSet<SecurityPermission>> srvcPermissions = 
isSecurityCompatibilityMode()
+        ? compatibleServicePermissions()
+        : new HashMap<>();
 
     /** System permissions. */
     @GridToStringInclude
     @Order(3)
-    @Nullable Collection<SecurityPermission> sysPermissions;
+    @Nullable EnumSet<SecurityPermission> sysPermissions;
 
     /** Default allow all. */
     @Order(4)
@@ -82,9 +88,7 @@ public class SecurityBasicPermissionSet implements 
SecurityPermissionSet, SelfMa
      * @param cachePermissions Cache permissions.
      */
     public void setCachePermissions(Map<String, EnumSet<SecurityPermission>> 
cachePermissions) {
-        A.notNull(cachePermissions, "cachePermissions");
-
-        this.cachePermissions = normalizeValueType(upcast(cachePermissions));
+        this.cachePermissions = checkPermissions(cachePermissions, 
"cachePermissions");
     }
 
     /**
@@ -93,9 +97,7 @@ public class SecurityBasicPermissionSet implements 
SecurityPermissionSet, SelfMa
      * @param taskPermissions Task permissions.
      */
     public void setTaskPermissions(Map<String, EnumSet<SecurityPermission>> 
taskPermissions) {
-        A.notNull(taskPermissions, "taskPermissions");
-
-        this.taskPermissions = normalizeValueType(upcast(taskPermissions));
+        this.taskPermissions = checkPermissions(taskPermissions, 
"taskPermissions");
     }
 
     /**
@@ -104,9 +106,7 @@ public class SecurityBasicPermissionSet implements 
SecurityPermissionSet, SelfMa
      * @param srvcPermissions Service permissions.
      */
     public void setServicePermissions(Map<String, EnumSet<SecurityPermission>> 
srvcPermissions) {
-        A.notNull(srvcPermissions, "servicePermissions");
-
-        this.srvcPermissions = normalizeValueType(upcast(srvcPermissions));
+        this.srvcPermissions = checkPermissions(srvcPermissions, 
"servicePermissions");
     }
 
     /**
@@ -129,22 +129,22 @@ public class SecurityBasicPermissionSet implements 
SecurityPermissionSet, SelfMa
 
     /** {@inheritDoc} */
     @Override public Map<String, EnumSet<SecurityPermission>> 
cachePermissions() {
-        return downcast(cachePermissions);
+        return cachePermissions;
     }
 
     /** {@inheritDoc} */
     @Override public Map<String, EnumSet<SecurityPermission>> 
taskPermissions() {
-        return downcast(taskPermissions);
+        return taskPermissions;
     }
 
     /** {@inheritDoc} */
     @Override public Map<String, EnumSet<SecurityPermission>> 
servicePermissions() {
-        return downcast(srvcPermissions);
+        return srvcPermissions;
     }
 
     /** {@inheritDoc} */
     @Nullable @Override public EnumSet<SecurityPermission> systemPermissions() 
{
-        return (EnumSet<SecurityPermission>)sysPermissions;
+        return sysPermissions;
     }
 
     /** {@inheritDoc} */
@@ -183,28 +183,40 @@ public class SecurityBasicPermissionSet implements 
SecurityPermissionSet, SelfMa
 
     /** */
     private void writeObject(ObjectOutputStream out) throws IOException {
-        out.defaultWriteObject();
+        ObjectOutputStream.PutField fields = out.putFields();
+
+        fields.put("dfltAllowAll", dfltAllowAll);
+        fields.put("cachePermissions", cachePermissions);
+        fields.put("sysPermissions", sysPermissions);
+        fields.put("taskPermissions", taskPermissions);
+
+        out.writeFields();
 
         if (serializeVersion() >= 2)
             U.writeMap(out, srvcPermissions);
     }
 
     /** */
+    @SuppressWarnings("unchecked")
     private void readObject(ObjectInputStream in) throws IOException, 
ClassNotFoundException {
-        in.defaultReadObject();
+        ObjectInputStream.GetField fields = in.readFields();
 
-        if (serializeVersion() >= 2)
-            srvcPermissions = U.readMap(in);
+        dfltAllowAll = fields.get("dfltAllowAll", false);
+        cachePermissions = readPermissions(fields, "cachePermissions");
+        taskPermissions = readPermissions(fields, "taskPermissions");
 
-        if (srvcPermissions == null) {
+        Collection<SecurityPermission> sysPerms = 
(Collection<SecurityPermission>)fields.get("sysPermissions", null);
+
+        sysPermissions = sysPerms == null ? null : toEnumSet(sysPerms);
+
+        Map<String, ? extends Collection<SecurityPermission>> srvcPerms = 
serializeVersion() >= 2 ? U.readMap(in) : null;
+
+        if (srvcPerms == null) {
             // Allow all for compatibility mode
-            if (serializeVersion() < 2)
-                srvcPermissions = compatibleServicePermissions();
-            else
-                srvcPermissions = Collections.emptyMap();
+            srvcPerms = serializeVersion() < 2 ? 
compatibleServicePermissions() : Collections.emptyMap();
         }
 
-        normalize();
+        srvcPermissions = normalizeResourcePermissions(srvcPerms);
     }
 
     /** {@inheritDoc} */
@@ -212,23 +224,23 @@ public class SecurityBasicPermissionSet implements 
SecurityPermissionSet, SelfMa
         return S.toString(SecurityBasicPermissionSet.class, this);
     }
 
-    /** {@inheritDoc} */
-    @Override public void selfMarshal() {
-        // No-op.
-    }
-
-    /** {@inheritDoc} */
-    @Override public void selfUnmarshal() {
-        // Message framework uses ArrayList for ordinary collections,
-        // so we need to convert it to appropriate form explicitly.
-        normalize();
+    /** */
+    @SuppressWarnings("unchecked")
+    private static Map<String, EnumSet<SecurityPermission>> readPermissions(
+        ObjectInputStream.GetField fields,
+        String name
+    ) throws IOException {
+        return normalizeResourcePermissions((Map<String, ? extends 
Collection<SecurityPermission>>)fields.get(name, null));
     }
 
     /** */
-    private void normalize() {
-        cachePermissions = normalizeValueType(cachePermissions);
-        taskPermissions = normalizeValueType(taskPermissions);
-        srvcPermissions = normalizeValueType(srvcPermissions);
-        sysPermissions = sysPermissions == null ? null : 
copySafe(sysPermissions);
+    private static Map<String, EnumSet<SecurityPermission>> checkPermissions(
+        Map<String, EnumSet<SecurityPermission>> perms,
+        String name
+    ) {
+        A.notNull(perms, name);
+        A.ensure(perms.values().stream().noneMatch(Objects::isNull), name + " 
must not contain a null permission set");
+
+        return perms;
     }
 }
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
index fe4dc2e4099..76df5d5548e 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
@@ -109,6 +109,31 @@ public class MessageProcessorTest {
             
.hasSourceEquivalentTo(javaFile("TestCollectionsMessageMarshaller.java"));
     }
 
+    /** */
+    @Test
+    public void testEnumSetMessage() {
+        Compilation compilation = compile("TestEnumSetMessage.java");
+
+        assertThat(compilation).succeeded();
+
+        assertEquals(1, compilation.generatedSourceFiles().size());
+
+        assertThat(compilation)
+            
.generatedSourceFile("org.apache.ignite.internal.TestEnumSetMessageSerializer")
+            
.hasSourceEquivalentTo(javaFile("TestEnumSetMessageSerializer.java"));
+    }
+
+    /** */
+    @Test
+    public void testEnumSetOfTypeVariableFailed() {
+        Compilation compilation = compile("WrongEnumSetMessage.java");
+
+        assertThat(compilation).failed();
+
+        assertThat(compilation).hadErrorContaining(
+            "Unexpected Enum Set element type [itemType=E, 
colType=java.util.EnumSet<E>");
+    }
+
     /** */
     @Test
     public void testMapMessage() {
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java
index 3e46ceae987..84600db1dd0 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java
@@ -19,6 +19,8 @@ package org.apache.ignite.internal.direct;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
 import java.util.Map;
 import org.apache.ignite.internal.CoreMessagesProvider;
 import 
org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl;
@@ -26,9 +28,13 @@ import 
org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageFactory;
 import 
org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider;
 import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.TransactionIsolation;
 import org.junit.Test;
 
 import static org.apache.ignite.marshaller.Marshallers.jdk;
+import static 
org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
+import static 
org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
 import static org.junit.Assert.assertArrayEquals;
 
 /**
@@ -77,6 +83,46 @@ public class DirectMarshallingMessagesTest extends 
GridCommonAbstractTest {
         assertArrayEquals(msg.nestedArr.get(2), resMsg.nestedArr.get(2));
     }
 
+    /** */
+    @Test
+    public void testEnumSets() {
+        TestNestedContainersMessage msg = new TestNestedContainersMessage();
+
+        msg.isolations = EnumSet.of(READ_COMMITTED, SERIALIZABLE);
+
+        msg.isolationsMap = Map.of(
+            "empty", EnumSet.noneOf(TransactionIsolation.class),
+            "one", EnumSet.of(REPEATABLE_READ)
+        );
+
+        msg.isolationsList = Arrays.asList(EnumSet.of(READ_COMMITTED), 
EnumSet.allOf(TransactionIsolation.class));
+
+        TestNestedContainersMessage resMsg = doMarshalUnmarshalChunked(msg);
+
+        assertEquals(msg.isolations, resMsg.isolations);
+        assertEquals(msg.isolationsMap, resMsg.isolationsMap);
+        assertEquals(msg.isolationsList, resMsg.isolationsList);
+
+        for (Collection<TransactionIsolation> col : 
resMsg.isolationsMap.values())
+            assertTrue(col instanceof EnumSet);
+
+        for (Collection<TransactionIsolation> col : resMsg.isolationsList)
+            assertTrue(col instanceof EnumSet);
+    }
+
+    /** */
+    @Test
+    public void testNullContainers() {
+        TestNestedContainersMessage resMsg = doMarshalUnmarshalChunked(new 
TestNestedContainersMessage());
+
+        assertNull(resMsg.nestedMap);
+        assertNull(resMsg.nestedCollection);
+        assertNull(resMsg.nestedArr);
+        assertNull(resMsg.isolations);
+        assertNull(resMsg.isolationsMap);
+        assertNull(resMsg.isolationsList);
+    }
+
     /**
      * @param srcMsg Message to marshal.
      * @param <T> Message type.
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
index 32ef435f320..5fd1a25f936 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
@@ -17,10 +17,12 @@
 
 package org.apache.ignite.internal.direct;
 
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 import org.apache.ignite.internal.Order;
 import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.transactions.TransactionIsolation;
 
 /** */
 class TestNestedContainersMessage implements Message {
@@ -39,9 +41,20 @@ class TestNestedContainersMessage implements Message {
     @Order(2)
     Map<Integer, String[]> nestedArr;
 
+    /** */
+    @Order(3)
+    EnumSet<TransactionIsolation> isolations;
+
+    /** */
+    @Order(4)
+    Map<String, EnumSet<TransactionIsolation>> isolationsMap;
+
+    /** */
+    @Order(5)
+    List<EnumSet<TransactionIsolation>> isolationsList;
+
     /** Default constructor for {@link MessageFactory}. */
     public TestNestedContainersMessage() {
         // No-op.
     }
-
 }
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java
index eaa1081abf1..bfa3c8e3142 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java
@@ -47,6 +47,7 @@ import org.jetbrains.annotations.Nullable;
 import org.junit.Test;
 
 import static java.lang.Integer.MAX_VALUE;
+import static 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType.HASH_SET;
 import static org.junit.Assert.assertEquals;
 
 /** */
@@ -305,7 +306,7 @@ public abstract class AbstractMessageSerializationTest {
 
         /** {@inheritDoc} */
         @Override public <T> boolean writeCollection(Collection<T> col, 
MessageCollectionType type) {
-            return writeField(type.set() ? Set.class : Collection.class);
+            return writeField(type.collectionImplementationType() == HASH_SET 
? Set.class : Collection.class);
         }
 
         /** {@inheritDoc} */
@@ -572,7 +573,7 @@ public abstract class AbstractMessageSerializationTest {
 
         /** {@inheritDoc} */
         @Override public <C extends Collection<?>> C 
readCollection(MessageCollectionType type) {
-            readField(type.set() ? Set.class : Collection.class);
+            readField(type.collectionImplementationType() == HASH_SET ? 
Set.class : Collection.class);
 
             return null;
         }
diff --git 
a/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
 
b/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
index 83d18941fe4..7d3a472cefd 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSetSerializationTest.java
@@ -26,9 +26,7 @@ import org.apache.ignite.internal.CoreMessagesProvider;
 import org.apache.ignite.internal.direct.DirectMessageReader;
 import org.apache.ignite.internal.direct.DirectMessageWriter;
 import 
org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl;
-import org.apache.ignite.internal.managers.communication.MessageMarshalling;
 import org.apache.ignite.internal.util.nio.MessageSerialization;
-import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageFactory;
 import 
org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider;
@@ -74,7 +72,7 @@ public class SecurityBasicPermissionSetSerializationTest 
extends GridCommonAbstr
 
     /** */
     @Test
-    public void testWithNullAndEmptyPermissions() throws Exception {
+    public void testWithEmptyPermissions() throws Exception {
         SecurityBasicPermissionSet src = new SecurityBasicPermissionSet();
         src.setDefaultAllowAll(true);
 
@@ -83,8 +81,8 @@ public class SecurityBasicPermissionSetSerializationTest 
extends GridCommonAbstr
         src.setSystemPermissions(emptyPerms);
 
         HashMap<String, EnumSet<SecurityPermission>> taskPerms = new 
HashMap<>();
-        taskPerms.put("task1", null);
-        taskPerms.put("task2", emptyPerms);
+        taskPerms.put("task1", emptyPerms);
+        taskPerms.put("task2", EnumSet.of(TASK_EXECUTE));
 
         src.setTaskPermissions(taskPerms);
 
@@ -115,8 +113,6 @@ public class SecurityBasicPermissionSetSerializationTest 
extends GridCommonAbstr
 
         GridTestUtils.setFieldValue(kctx.grid(), "msgFactory", msgFactory);
 
-        MessageMarshalling.marshal(msg, kctx, null);
-
         ByteBuffer buf = ByteBuffer.allocate(64 * 1024);
 
         DirectMessageWriter writer = new DirectMessageWriter(msgFactory);
@@ -133,8 +129,6 @@ public class SecurityBasicPermissionSetSerializationTest 
extends GridCommonAbstr
 
         assertTrue(MessageSerialization.readFrom(msgFactory, res, reader));
 
-        MessageMarshalling.unmarshal(res, kctx, null, U.gridClassLoader());
-
         return res;
     }
 }
diff --git 
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
 
b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
index 270f40fc71b..fe0cb67561b 100644
--- 
a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
+++ 
b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.CustomMapperEnumFieldsMessage;
 import org.apache.ignite.internal.TransactionIsolationEnumMapper;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageEnumType;
@@ -37,7 +38,7 @@ public final class CustomMapperEnumFieldsMessageSerializer 
implements MessageSer
     /** */
     private static final EnumMapper<TransactionIsolation> 
transactionIsolationMapper = new TransactionIsolationEnumMapper();
     /** */
-    private static final MessageCollectionType isolationsCollDesc = new 
MessageCollectionType(new MessageCollectionType(new 
MessageEnumType<>(transactionIsolationMapper::encode, 
transactionIsolationMapper::decode), false), false);
+    private static final MessageCollectionType isolationsCollDesc = new 
MessageCollectionType(new MessageCollectionType(new 
MessageEnumType<>(TransactionIsolation.class, 
transactionIsolationMapper::encode, transactionIsolationMapper::decode), 
CollectionImplementationType.ARRAY_LIST), 
CollectionImplementationType.ARRAY_LIST);
 
     /** */
     @Override public final boolean writeTo(CustomMapperEnumFieldsMessage msg, 
MessageWriter writer) {
diff --git 
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
 
b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
index 25324b44875..dba15be2846 100644
--- 
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
+++ 
b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal;
 import org.apache.ignite.internal.DefaultMapperEnumFieldsMessage;
 import org.apache.ignite.internal.processors.cache.GridCacheOperation;
 import 
org.apache.ignite.internal.processors.cache.verify.PartitionHashRecord.PartitionState;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageEnumType;
@@ -44,9 +45,9 @@ public final class DefaultMapperEnumFieldsMessageSerializer 
implements MessageSe
     /** */
     private static final TransactionIsolation[] transactionIsolationVals = 
TransactionIsolation.values();
     /** */
-    private static final MessageCollectionType partStatesCollDesc = new 
MessageCollectionType(new MessageEnumType<>(DefaultEnumMapper.INSTANCE::encode, 
b -> DefaultEnumMapper.INSTANCE.decode(partitionStateVals, b)), false);
+    private static final MessageCollectionType partStatesCollDesc = new 
MessageCollectionType(new MessageEnumType<>(PartitionState.class, 
DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(partitionStateVals, b)), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageMapType isolationStringMapCollDesc = new 
MessageMapType(new MessageCollectionType(new 
MessageEnumType<>(DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), false), new 
MessageItemType(MessageCollectionItemType.STRING), false);
+    private static final MessageMapType isolationStringMapCollDesc = new 
MessageMapType(new MessageCollectionType(new 
MessageEnumType<>(TransactionIsolation.class, 
DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), 
CollectionImplementationType.ARRAY_LIST), new 
MessageItemType(MessageCollectionItemType.STRING), false);
 
     /** */
     @Override public final boolean writeTo(DefaultMapperEnumFieldsMessage msg, 
MessageWriter writer) {
diff --git 
a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java 
b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java
index 080c8cfaaa0..bd79c20a48c 100644
--- 
a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java
+++ 
b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.TestCollectionsMessage;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageItemType;
@@ -32,57 +33,57 @@ import 
org.apache.ignite.plugin.extensions.communication.MessageWriter;
  */
 public final class TestCollectionsMessageSerializer implements 
MessageSerializer<TestCollectionsMessage> {
     /** */
-    private static final MessageCollectionType affTopVersionListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), false);
+    private static final MessageCollectionType affTopVersionListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType bitSetListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), 
false);
+    private static final MessageCollectionType bitSetListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType bitSetSetCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), 
true);
+    private static final MessageCollectionType bitSetSetCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), 
CollectionImplementationType.HASH_SET);
     /** */
-    private static final MessageCollectionType booleanArrayListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), false);
+    private static final MessageCollectionType booleanArrayListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedBooleanListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BOOLEAN), 
false);
+    private static final MessageCollectionType boxedBooleanListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BOOLEAN), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedByteListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE), 
false);
+    private static final MessageCollectionType boxedByteListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedCharListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR), 
false);
+    private static final MessageCollectionType boxedCharListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedDoubleListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), 
false);
+    private static final MessageCollectionType boxedDoubleListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedFloatListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT), 
false);
+    private static final MessageCollectionType boxedFloatListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedIntListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), 
false);
+    private static final MessageCollectionType boxedIntListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedIntegerSetCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), true);
+    private static final MessageCollectionType boxedIntegerSetCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), 
CollectionImplementationType.HASH_SET);
     /** */
-    private static final MessageCollectionType boxedLongListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG), 
false);
+    private static final MessageCollectionType boxedLongListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType boxedShortListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT), 
false);
+    private static final MessageCollectionType boxedShortListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType byteArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), 
false);
+    private static final MessageCollectionType byteArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType cacheObjectSetCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.CACHE_OBJECT), true);
+    private static final MessageCollectionType cacheObjectSetCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.CACHE_OBJECT), 
CollectionImplementationType.HASH_SET);
     /** */
-    private static final MessageCollectionType charArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR_ARR), 
false);
+    private static final MessageCollectionType charArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType doubleArrayListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.DOUBLE_ARR), false);
+    private static final MessageCollectionType doubleArrayListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.DOUBLE_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType floatArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), 
false);
+    private static final MessageCollectionType floatArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType gridLongListListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), false);
+    private static final MessageCollectionType gridLongListListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType igniteUuidListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.IGNITE_UUID), false);
+    private static final MessageCollectionType igniteUuidListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.IGNITE_UUID), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType intArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT_ARR), 
false);
+    private static final MessageCollectionType intArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType longArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG_ARR), 
false);
+    private static final MessageCollectionType longArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType messageListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false);
+    private static final MessageCollectionType messageListCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType shortArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT_ARR), 
false);
+    private static final MessageCollectionType shortArrayListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT_ARR), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType stringListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.STRING), 
false);
+    private static final MessageCollectionType stringListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.STRING), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType uuidListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.UUID), 
false);
+    private static final MessageCollectionType uuidListCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.UUID), 
CollectionImplementationType.ARRAY_LIST);
 
     /** */
     @Override public final boolean writeTo(TestCollectionsMessage msg, 
MessageWriter writer) {
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
 b/modules/core/src/test/resources/codegen/TestEnumSetMessage.java
similarity index 65%
copy from 
modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
copy to modules/core/src/test/resources/codegen/TestEnumSetMessage.java
index 32ef435f320..c39f872b2e8 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
+++ b/modules/core/src/test/resources/codegen/TestEnumSetMessage.java
@@ -15,33 +15,25 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.direct;
+package org.apache.ignite.internal;
 
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
-import org.apache.ignite.internal.Order;
 import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.transactions.TransactionIsolation;
 
-/** */
-class TestNestedContainersMessage implements Message {
-    /** */
-    public static final short TYPE = Short.MAX_VALUE;
-
-    /** */
+public class TestEnumSetMessage implements Message {
     @Order(0)
-    Map<Integer, Map<Integer, Long>> nestedMap;
+    EnumSet<TransactionIsolation> isolations;
 
-    /** */
     @Order(1)
-    Map<Integer, List<Integer>> nestedCollection;
+    Map<String, EnumSet<TransactionIsolation>> isolationsMap;
 
-    /** */
     @Order(2)
-    Map<Integer, String[]> nestedArr;
+    List<EnumSet<TransactionIsolation>> isolationsList;
 
-    /** Default constructor for {@link MessageFactory}. */
-    public TestNestedContainersMessage() {
-        // No-op.
+    public short directType() {
+        return 0;
     }
-
 }
diff --git 
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
 b/modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java
similarity index 55%
copy from 
modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
copy to 
modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java
index 25324b44875..fb0afa111fa 100644
--- 
a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/TestEnumSetMessageSerializer.java
@@ -17,9 +17,8 @@
 
 package org.apache.ignite.internal;
 
-import org.apache.ignite.internal.DefaultMapperEnumFieldsMessage;
-import org.apache.ignite.internal.processors.cache.GridCacheOperation;
-import 
org.apache.ignite.internal.processors.cache.verify.PartitionHashRecord.PartitionState;
+import org.apache.ignite.internal.TestEnumSetMessage;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageEnumType;
@@ -36,20 +35,18 @@ import org.apache.ignite.transactions.TransactionIsolation;
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public final class DefaultMapperEnumFieldsMessageSerializer implements 
MessageSerializer<DefaultMapperEnumFieldsMessage> {
-    /** */
-    private static final GridCacheOperation[] gridCacheOperationVals = 
GridCacheOperation.values();
-    /** */
-    private static final PartitionState[] partitionStateVals = 
PartitionState.values();
+public final class TestEnumSetMessageSerializer implements 
MessageSerializer<TestEnumSetMessage> {
     /** */
     private static final TransactionIsolation[] transactionIsolationVals = 
TransactionIsolation.values();
     /** */
-    private static final MessageCollectionType partStatesCollDesc = new 
MessageCollectionType(new MessageEnumType<>(DefaultEnumMapper.INSTANCE::encode, 
b -> DefaultEnumMapper.INSTANCE.decode(partitionStateVals, b)), false);
+    private static final MessageCollectionType isolationsCollDesc = new 
MessageCollectionType(new MessageEnumType<>(TransactionIsolation.class, 
DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), 
CollectionImplementationType.ENUM_SET);
     /** */
-    private static final MessageMapType isolationStringMapCollDesc = new 
MessageMapType(new MessageCollectionType(new 
MessageEnumType<>(DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), false), new 
MessageItemType(MessageCollectionItemType.STRING), false);
+    private static final MessageCollectionType isolationsListCollDesc = new 
MessageCollectionType(new MessageCollectionType(new 
MessageEnumType<>(TransactionIsolation.class, 
DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), 
CollectionImplementationType.ENUM_SET), 
CollectionImplementationType.ARRAY_LIST);
+    /** */
+    private static final MessageMapType isolationsMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.STRING), new 
MessageCollectionType(new MessageEnumType<>(TransactionIsolation.class, 
DefaultEnumMapper.INSTANCE::encode, b -> 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, b)), 
CollectionImplementationType.ENUM_SET), false);
 
     /** */
-    @Override public final boolean writeTo(DefaultMapperEnumFieldsMessage msg, 
MessageWriter writer) {
+    @Override public final boolean writeTo(TestEnumSetMessage msg, 
MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -59,25 +56,19 @@ public final class DefaultMapperEnumFieldsMessageSerializer 
implements MessageSe
 
         switch (writer.state()) {
             case 0:
-                if 
(!writer.writeByte(DefaultEnumMapper.INSTANCE.encode(msg.publicEnum)))
+                if (!writer.writeCollection(msg.isolations, 
isolationsCollDesc))
                     return false;
 
                 writer.incrementState();
 
             case 1:
-                if 
(!writer.writeByte(DefaultEnumMapper.INSTANCE.encode(msg.internalEnum)))
+                if (!writer.writeMap(msg.isolationsMap, isolationsMapCollDesc))
                     return false;
 
                 writer.incrementState();
 
             case 2:
-                if (!writer.writeMap(msg.isolationStringMap, 
isolationStringMapCollDesc))
-                    return false;
-
-                writer.incrementState();
-
-            case 3:
-                if (!writer.writeCollection(msg.partStates, 
partStatesCollDesc))
+                if (!writer.writeCollection(msg.isolationsList, 
isolationsListCollDesc))
                     return false;
 
                 writer.incrementState();
@@ -87,10 +78,10 @@ public final class DefaultMapperEnumFieldsMessageSerializer 
implements MessageSe
     }
 
     /** */
-    @Override public final boolean readFrom(DefaultMapperEnumFieldsMessage 
msg, MessageReader reader) {
+    @Override public final boolean readFrom(TestEnumSetMessage msg, 
MessageReader reader) {
         switch (reader.state()) {
             case 0:
-                msg.publicEnum = 
DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, reader.readByte());
+                msg.isolations = reader.readCollection(isolationsCollDesc);
 
                 if (!reader.isLastRead())
                     return false;
@@ -98,7 +89,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer 
implements MessageSe
                 reader.incrementState();
 
             case 1:
-                msg.internalEnum = 
DefaultEnumMapper.INSTANCE.decode(gridCacheOperationVals, reader.readByte());
+                msg.isolationsMap = reader.readMap(isolationsMapCollDesc);
 
                 if (!reader.isLastRead())
                     return false;
@@ -106,15 +97,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer 
implements MessageSe
                 reader.incrementState();
 
             case 2:
-                msg.isolationStringMap = 
reader.readMap(isolationStringMapCollDesc);
-
-                if (!reader.isLastRead())
-                    return false;
-
-                reader.incrementState();
-
-            case 3:
-                msg.partStates = reader.readCollection(partStatesCollDesc);
+                msg.isolationsList = 
reader.readCollection(isolationsListCollDesc);
 
                 if (!reader.isLastRead())
                     return false;
@@ -126,7 +109,7 @@ public final class DefaultMapperEnumFieldsMessageSerializer 
implements MessageSe
     }
 
     /** {@inheritDoc} */
-    @Override public final DefaultMapperEnumFieldsMessage createMessage() {
-        return new DefaultMapperEnumFieldsMessage();
+    @Override public final TestEnumSetMessage createMessage() {
+        return new TestEnumSetMessage();
     }
 }
diff --git 
a/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java 
b/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java
index 08c7cb117f0..2b6aa6b27ab 100644
--- a/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.TestMapMessage;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageItemType;
@@ -63,11 +64,11 @@ public final class TestMapMessageSerializer implements 
MessageSerializer<TestMap
     /** */
     private static final MessageMapType floatArrayCharArrayMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), new 
MessageItemType(MessageCollectionItemType.CHAR_ARR), false);
     /** */
-    private static final MessageMapType gridCacheObjectMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.KEY_CACHE_OBJECT), 
new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.CACHE_OBJECT), false), false), false);
+    private static final MessageMapType gridCacheObjectMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.KEY_CACHE_OBJECT), 
new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.CACHE_OBJECT), 
CollectionImplementationType.ARRAY_LIST), false), false);
     /** */
     private static final MessageMapType gridLongListIntegerMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), 
new MessageItemType(MessageCollectionItemType.INT), false);
     /** */
-    private static final MessageMapType gridlistDoubleMapUuidMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), 
new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), 
false), false), false);
+    private static final MessageMapType gridlistDoubleMapUuidMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), 
new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), 
CollectionImplementationType.ARRAY_LIST), false), false);
     /** */
     private static final MessageMapType igniteUuidBitSetMapCollDesc = new 
MessageMapType(new MessageItemType(MessageCollectionItemType.IGNITE_UUID), new 
MessageItemType(MessageCollectionItemType.BIT_SET), false);
     /** */
diff --git 
a/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java
 
b/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java
index bc59bc7d808..4f3a7c0e51f 100644
--- 
a/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java
+++ 
b/modules/core/src/test/resources/codegen/TestMarshalledArrayMapMessageSerializer.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal;
 import java.util.List;
 import org.apache.ignite.internal.GridTopicMessage;
 import org.apache.ignite.internal.TestMarshalledArrayMapMessage;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import org.apache.ignite.plugin.extensions.communication.MessageArrayType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
@@ -37,11 +38,11 @@ public final class TestMarshalledArrayMapMessageSerializer 
implements MessageSer
     /** */
     private static final MessageArrayType fixedMapKeysCollDesc = new 
MessageArrayType(new MessageItemType(MessageCollectionItemType.MSG), 
GridTopicMessage.class);
     /** */
-    private static final MessageArrayType fixedMapValsCollDesc = new 
MessageArrayType(new MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.MSG), false), List.class);
+    private static final MessageArrayType fixedMapValsCollDesc = new 
MessageArrayType(new MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.MSG), 
CollectionImplementationType.ARRAY_LIST), List.class);
     /** */
     private static final MessageArrayType mapKeysCollDesc = new 
MessageArrayType(new MessageItemType(MessageCollectionItemType.MSG), 
GridTopicMessage.class);
     /** */
-    private static final MessageArrayType mapValsCollDesc = new 
MessageArrayType(new MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.MSG), false), List.class);
+    private static final MessageArrayType mapValsCollDesc = new 
MessageArrayType(new MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.MSG), 
CollectionImplementationType.ARRAY_LIST), List.class);
 
     /** */
     @Override public final boolean writeTo(TestMarshalledArrayMapMessage msg, 
MessageWriter writer) {
diff --git 
a/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java
 
b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java
index add9975d57b..dd0fcb22533 100644
--- 
a/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java
+++ 
b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.TestMarshalledMapMessage;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageItemType;
@@ -32,9 +33,9 @@ import 
org.apache.ignite.plugin.extensions.communication.MessageWriter;
  */
 public final class TestMarshalledMapMessageSerializer implements 
MessageSerializer<TestMarshalledMapMessage> {
     /** */
-    private static final MessageCollectionType mapKeysCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false);
+    private static final MessageCollectionType mapKeysCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), 
CollectionImplementationType.ARRAY_LIST);
     /** */
-    private static final MessageCollectionType mapValsCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false);
+    private static final MessageCollectionType mapValsCollDesc = new 
MessageCollectionType(new 
MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), 
CollectionImplementationType.ARRAY_LIST);
 
     /** */
     @Override public final boolean writeTo(TestMarshalledMapMessage msg, 
MessageWriter writer) {
diff --git 
a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java
 
b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java
index a07b7011929..b68578b06a6 100644
--- 
a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java
+++ 
b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.TestMarshalledObjectsMessage;
+import 
org.apache.ignite.plugin.extensions.communication.CollectionImplementationType;
 import 
org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionType;
 import org.apache.ignite.plugin.extensions.communication.MessageItemType;
@@ -32,7 +33,7 @@ import 
org.apache.ignite.plugin.extensions.communication.MessageWriter;
  */
 public final class TestMarshalledObjectsMessageSerializer implements 
MessageSerializer<TestMarshalledObjectsMessage> {
     /** */
-    private static final MessageCollectionType dataBytesCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), 
false);
+    private static final MessageCollectionType dataBytesCollDesc = new 
MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), 
CollectionImplementationType.ARRAY_LIST);
 
     /** */
     @Override public final boolean writeTo(TestMarshalledObjectsMessage msg, 
MessageWriter writer) {
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
 b/modules/core/src/test/resources/codegen/WrongEnumSetMessage.java
similarity index 60%
copy from 
modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
copy to modules/core/src/test/resources/codegen/WrongEnumSetMessage.java
index 32ef435f320..c062278aa38 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/direct/TestNestedContainersMessage.java
+++ b/modules/core/src/test/resources/codegen/WrongEnumSetMessage.java
@@ -15,33 +15,16 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.direct;
+package org.apache.ignite.internal;
 
-import java.util.List;
-import java.util.Map;
-import org.apache.ignite.internal.Order;
+import java.util.EnumSet;
 import org.apache.ignite.plugin.extensions.communication.Message;
 
-/** */
-class TestNestedContainersMessage implements Message {
-    /** */
-    public static final short TYPE = Short.MAX_VALUE;
-
-    /** */
+public class WrongEnumSetMessage<E extends Enum<E>> implements Message {
     @Order(0)
-    Map<Integer, Map<Integer, Long>> nestedMap;
-
-    /** */
-    @Order(1)
-    Map<Integer, List<Integer>> nestedCollection;
+    EnumSet<E> enums;
 
-    /** */
-    @Order(2)
-    Map<Integer, String[]> nestedArr;
-
-    /** Default constructor for {@link MessageFactory}. */
-    public TestNestedContainersMessage() {
-        // No-op.
+    public short directType() {
+        return 0;
     }
-
 }
diff --git 
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
 
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/CollectionImplementationType.java
similarity index 55%
copy from 
modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
copy to 
modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/CollectionImplementationType.java
index f6d982de72a..1cf71ca1d81 100644
--- 
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
+++ 
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/CollectionImplementationType.java
@@ -17,35 +17,14 @@
 
 package org.apache.ignite.plugin.extensions.communication;
 
-/** */
-public class MessageCollectionType implements MessageType {
-    /** */
-    private final MessageType valType;
+/** Collection implementation a {@link MessageCollectionType} is read back 
into. */
+public enum CollectionImplementationType {
+    /** {@link java.util.ArrayList} (the default implementation type). */
+    ARRAY_LIST,
 
-    /** */
-    private final boolean set;
+    /** {@link java.util.HashSet}. */
+    HASH_SET,
 
-    /**
-     * @param valType Value type.
-     * @param set Is set.
-     */
-    public MessageCollectionType(MessageType valType, boolean set) {
-        this.valType = valType;
-        this.set = set;
-    }
-
-    /** @return Value type. */
-    public MessageType valueType() {
-        return valType;
-    }
-
-    /** {@inheritDoc} */
-    @Override public MessageCollectionItemType type() {
-        return MessageCollectionItemType.COLLECTION;
-    }
-
-    /** @return Is set. */
-    public boolean set() {
-        return set;
-    }
+    /** {@link java.util.EnumSet}. */
+    ENUM_SET
 }
diff --git 
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
 
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
index f6d982de72a..73e82b0246e 100644
--- 
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
+++ 
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageCollectionType.java
@@ -23,15 +23,17 @@ public class MessageCollectionType implements MessageType {
     private final MessageType valType;
 
     /** */
-    private final boolean set;
+    private final CollectionImplementationType implType;
 
     /**
      * @param valType Value type.
-     * @param set Is set.
+     * @param colImplType Type of the collection the elements are read back 
into.
      */
-    public MessageCollectionType(MessageType valType, boolean set) {
+    public MessageCollectionType(MessageType valType, 
CollectionImplementationType colImplType) {
+        assert colImplType != CollectionImplementationType.ENUM_SET || valType 
instanceof MessageEnumType<?>;
+
         this.valType = valType;
-        this.set = set;
+        this.implType = colImplType;
     }
 
     /** @return Value type. */
@@ -44,8 +46,8 @@ public class MessageCollectionType implements MessageType {
         return MessageCollectionItemType.COLLECTION;
     }
 
-    /** @return Is set. */
-    public boolean set() {
-        return set;
+    /** @return Collection the elements are read back into. */
+    public CollectionImplementationType collectionImplementationType() {
+        return implType;
     }
 }
diff --git 
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
 
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
index cdf67ea5649..46dace8e12b 100644
--- 
a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
+++ 
b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageEnumType.java
@@ -17,10 +17,14 @@
 
 package org.apache.ignite.plugin.extensions.communication;
 
+import java.util.EnumSet;
 import java.util.function.Function;
 
 /** */
 public class MessageEnumType<T extends Enum<T>> implements MessageType {
+    /** */
+    private final Class<T> cls;
+
     /** */
     private final Function<T, Byte> encoder;
 
@@ -28,14 +32,21 @@ public class MessageEnumType<T extends Enum<T>> implements 
MessageType {
     private final Function<Byte, T> decoder;
 
     /**
+     * @param cls Enum class.
      * @param encoder Encoder.
      * @param decoder Decoder.
      */
-    public MessageEnumType(Function<T, Byte> encoder, Function<Byte, T> 
decoder) {
+    public MessageEnumType(Class<T> cls, Function<T, Byte> encoder, 
Function<Byte, T> decoder) {
+        this.cls = cls;
         this.encoder = encoder;
         this.decoder = decoder;
     }
 
+    /** @return Empty {@link EnumSet} of the enum type. */
+    public EnumSet<T> newEnumSet() {
+        return EnumSet.noneOf(cls);
+    }
+
     /**
      * @param val Value.
      * @return Encoded value.

Reply via email to