diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MarshalableMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMarshalableMessage.java similarity index 95% rename from modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MarshalableMessage.java rename to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMarshalableMessage.java index b039c0b7512f7..b671639ebd6c4 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MarshalableMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMarshalableMessage.java @@ -23,7 +23,7 @@ /** * */ -public interface MarshalableMessage extends CalciteMessage { +public interface CalciteMarshalableMessage extends CalciteMessage { /** * Prepares the message before sending. * diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java index 1af28d1fe32cb..2cea51aa5cfac 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java @@ -179,8 +179,8 @@ public FailureProcessor failureProcessor() { /** */ protected void prepareMarshal(Message msg) throws IgniteCheckedException { try { - if (msg instanceof MarshalableMessage) - ((MarshalableMessage)msg).prepareMarshal(ctx); + if (msg instanceof CalciteMarshalableMessage) + ((CalciteMarshalableMessage)msg).prepareMarshal(ctx); } catch (Exception e) { failureProcessor().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); @@ -192,8 +192,8 @@ protected void prepareMarshal(Message msg) throws IgniteCheckedException { /** */ protected void prepareUnmarshal(Message msg) throws IgniteCheckedException { try { - if (msg instanceof MarshalableMessage) - ((MarshalableMessage)msg).prepareUnmarshal(ctx); + if (msg instanceof CalciteMarshalableMessage) + ((CalciteMarshalableMessage)msg).prepareUnmarshal(ctx); } catch (Exception e) { failureProcessor().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java index b722b6ccf3758..c21297c3a5c7d 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java @@ -27,7 +27,7 @@ /** * */ -public class QueryBatchMessage implements MarshalableMessage, ExecutionContextAware { +public class QueryBatchMessage implements CalciteMarshalableMessage, ExecutionContextAware { /** */ @Order(0) UUID qryId; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java index 81d843bf3eee0..fe45e12a1c8b1 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java @@ -31,7 +31,7 @@ /** * */ -public class QueryStartRequest implements MarshalableMessage, ExecutionContextAware { +public class QueryStartRequest implements CalciteMarshalableMessage, ExecutionContextAware { /** */ @Order(0) String schema; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/ValueMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/ValueMessage.java index 44c3d8d0fb549..901bcbfafa456 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/ValueMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/ValueMessage.java @@ -21,7 +21,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; /** */ -public interface ValueMessage extends MarshalableMessage { +public interface ValueMessage extends CalciteMarshalableMessage { /** * @return Wrapped value. */ diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/FragmentDescription.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/FragmentDescription.java index 012591fa1e398..dce4f0f5d2f6a 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/FragmentDescription.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/FragmentDescription.java @@ -23,13 +23,13 @@ import java.util.UUID; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; -import org.apache.ignite.internal.processors.query.calcite.message.MarshalableMessage; +import org.apache.ignite.internal.processors.query.calcite.message.CalciteMarshalableMessage; import org.apache.ignite.internal.processors.query.calcite.message.MessageType; import org.apache.ignite.internal.util.UUIDCollectionMessage; import org.apache.ignite.internal.util.typedef.internal.U; /** */ -public class FragmentDescription implements MarshalableMessage { +public class FragmentDescription implements CalciteMarshalableMessage { /** */ @Order(0) long fragmentId; diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java index c4c6ab7207345..f6cf23d4b7190 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java @@ -68,6 +68,12 @@ public class MessageProcessor extends AbstractProcessor { /** Base interface that every message must implement. */ static final String MESSAGE_INTERFACE = "org.apache.ignite.plugin.extensions.communication.Message"; + /** Compressed message. */ + static final String COMPRESSED_MESSAGE_INTERFACE = "org.apache.ignite.internal.managers.communication.CompressedMessage"; + + /** Externalizable message. */ + static final String MARSHALLABLE_MESSAGE_INTERFACE = "org.apache.ignite.plugin.extensions.communication.MarshallableMessage"; + /** This is the only message with zero fields. A serializer must be generated due to restrictions in our communication process. */ static final String HANDSHAKE_WAIT_MESSAGE = "org.apache.ignite.spi.communication.tcp.messages.HandshakeWaitMessage"; 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 51b756c49fbf7..da844353a1024 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 @@ -56,6 +56,8 @@ import org.apache.ignite.internal.util.typedef.internal.SB; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.MessageProcessor.COMPRESSED_MESSAGE_INTERFACE; +import static org.apache.ignite.internal.MessageProcessor.MARSHALLABLE_MESSAGE_INTERFACE; import static org.apache.ignite.internal.MessageProcessor.MESSAGE_INTERFACE; /** @@ -107,23 +109,35 @@ public class MessageSerializerGenerator { /** */ private final ProcessingEnvironment env; + /** Stored type of the message being processed. */ + private TypeElement type; + + /** The marshallable message type. */ + private final TypeMirror marshallableMsgType; + /** */ private int indent; /** */ MessageSerializerGenerator(ProcessingEnvironment env) { this.env = env; + + marshallableMsgType = env.getElementUtils().getTypeElement(MARSHALLABLE_MESSAGE_INTERFACE).asType(); } /** */ void generate(TypeElement type, List fields) throws Exception { - generateMethods(type, fields); + assert this.type == null : "Message serializer generator isn't stateless and is supposed to be single-use."; + + this.type = type; + + generateMethods(fields); SystemViewRowAttributeWalkerProcessor.superclasses(env, type).forEach(el -> imports.add(el.toString())); - String serClsName = type.getSimpleName() + "Serializer"; + String serClsName = type.getSimpleName() + (marshallableMessage() ? "Marshallable" : "") + "Serializer"; String serFqnClsName = env.getElementUtils().getPackageOf(type) + "." + serClsName; - String serCode = generateSerializerCode(type); + String serCode = generateSerializerCode(serClsName); try { JavaFileObject file = env.getFiler().createSourceFile(serFqnClsName); @@ -151,12 +165,21 @@ void generate(TypeElement type, List fields) throws Exception { } /** Generates full code for a serializer class. */ - private String generateSerializerCode(TypeElement type) throws IOException { + private String generateSerializerCode(String serClsName) throws IOException { + if (marshallableMessage()) { + fields.add("private final Marshaller marshaller;"); + fields.add("private final ClassLoader clsLdr;"); + } + try (Writer writer = new StringWriter()) { - writeClassHeader(writer, env.getElementUtils().getPackageOf(type).toString(), type.getSimpleName() + "Serializer"); + writeClassHeader(writer, env.getElementUtils().getPackageOf(type).toString(), serClsName); writeClassFields(writer); + ++indent; + writeConstructor(writer, serClsName); + --indent; + // Write #writeTo method. for (String w: write) writer.write(w + NL); @@ -177,10 +200,33 @@ private String generateSerializerCode(TypeElement type) throws IOException { } } + /** */ + private void writeConstructor(Writer writer, String serClsName) throws IOException { + if (!marshallableMessage()) + return; + + writer.write(identedLine(METHOD_JAVADOC)); + writer.write(NL); + writer.write(identedLine("public " + serClsName + "(Marshaller marshaller, ClassLoader clsLdr) {")); + + writer.write(NL); + ++indent; + + writer.write(identedLine("this.marshaller = marshaller;")); + writer.write(NL); + writer.write(identedLine("this.clsLdr = clsLdr;")); + + --indent; + writer.write(NL); + + writer.write(identedLine("}")); + writer.write(NL); + } + /** Generates code for {@code writeTo} and {@code readFrom}. */ - private void generateMethods(TypeElement type, List fields) throws Exception { - start(type, write, true); - start(type, read, false); + private void generateMethods(List fields) throws Exception { + start(write, true); + start(read, false); indent++; @@ -191,16 +237,14 @@ private void generateMethods(TypeElement type, List fields) thr indent--; - finish(write); - finish(read); + finish(write, false, false); + finish(read, true, marshallableMessage()); } /** * Generates start of write/read methods: *
      *     public boolean writeTo(Message m, MessageWriter writer) {
-     *         TestMessage msg = (TestMessage)m;
-     *
      *         if (!writer.isHeaderWritten()) {
      *             if (!writer.writeHeader(msg.directType()))
      *                 return false;
@@ -212,20 +256,17 @@ private void generateMethods(TypeElement type, List fields) thr
      * @param code Code lines.
      * @param write Whether write code is generated.
      */
-    private void start(TypeElement type, Collection code, boolean write) {
+    private void start(Collection code, boolean write) {
         indent = 1;
 
         code.add(identedLine(METHOD_JAVADOC));
 
-        code.add(identedLine("@Override public boolean %s(Message m, %s) {",
+        code.add(identedLine("@Override public boolean %s(" + type.getSimpleName() + " msg, %s) {",
             write ? "writeTo" : "readFrom",
             write ? "MessageWriter writer" : "MessageReader reader"));
 
         indent++;
 
-        code.add(identedLine("%s msg = (%s)m;", type.getSimpleName().toString(), type.getSimpleName().toString()));
-        code.add(EMPTY);
-
         if (write) {
             code.add(identedLine("if (!writer.isHeaderWritten()) {"));
 
@@ -233,6 +274,12 @@ private void start(TypeElement type, Collection code, boolean write) {
 
             returnFalseIfWriteFailed(code, "writer.writeHeader", "directType()");
 
+            if (write && marshallableMessage()) {
+                code.add(EMPTY);
+
+                code.add(identedLine("msg.prepareMarshal(marshaller);"));
+            }
+
             code.add(EMPTY);
             code.add(identedLine("writer.onHeaderWritten();"));
 
@@ -401,7 +448,7 @@ else if (assignableFrom(type, type("org.apache.ignite.internal.util.GridLongList
                 returnFalseIfWriteFailed(write, field, "writer.writeGridLongList", getExpr);
 
             else if (assignableFrom(type, type(MESSAGE_INTERFACE))) {
-                if (sameType(type, "org.apache.ignite.internal.managers.communication.CompressedMessage"))
+                if (sameType(type, COMPRESSED_MESSAGE_INTERFACE))
                     throw new IllegalArgumentException(COMPRESSED_MSG_ERROR);
 
                 if (compress)
@@ -508,8 +555,14 @@ private void returnFalseIfWriteFailed(Collection code, VariableElement f
 
         String methodName = field.getAnnotation(Order.class).method();
 
-        if (Objects.equals(methodName, ""))
-            code.add(identedLine("if (!%s(((%s)msg).%s))", accessor, field.getEnclosingElement().getSimpleName(), argsStr));
+        if (Objects.equals(methodName, "")) {
+            if (type.equals(field.getEnclosingElement()))
+                code.add(identedLine("if (!%s(msg.%s))", accessor, argsStr));
+            else {
+                // Field has to be requested from a super class object.
+                code.add(identedLine("if (!%s(((%s)msg).%s))", accessor, field.getEnclosingElement().getSimpleName(), argsStr));
+            }
+        }
         else
             code.add(identedLine("if (!%s(msg.%s))", accessor, argsStr));
 
@@ -531,9 +584,15 @@ private void returnFalseIfEnumWriteFailed(
         String fieldGetterCall) {
         String methodName = field.getAnnotation(Order.class).method();
 
-        if (Objects.equals(methodName, ""))
-            code.add(identedLine("if (!%s(%s(((%s)msg).%s)))",
-                writerCall, mapperCall, field.getEnclosingElement().getSimpleName(), fieldGetterCall));
+        if (Objects.equals(methodName, "")) {
+            if (type.equals(field.getEnclosingElement()))
+                code.add(identedLine("if (!%s(%s(msg.%s)))", writerCall, mapperCall, fieldGetterCall));
+            else {
+                // Field has to be requested from a super class object.
+                code.add(identedLine("if (!%s(%s(((%s)msg).%s)))",
+                    writerCall, mapperCall, field.getEnclosingElement().getSimpleName(), fieldGetterCall));
+            }
+        }
         else
             code.add(identedLine("if (!%s(%s(msg.%s)))", writerCall, mapperCall, fieldGetterCall));
 
@@ -650,7 +709,7 @@ else if (assignableFrom(type, type("org.apache.ignite.internal.util.GridLongList
                 returnFalseIfReadFailed(field, "reader.readGridLongList");
 
             else if (assignableFrom(type, type(MESSAGE_INTERFACE))) {
-                if (sameType(type, "org.apache.ignite.internal.managers.communication.CompressedMessage"))
+                if (sameType(type, COMPRESSED_MESSAGE_INTERFACE))
                     throw new IllegalArgumentException(COMPRESSED_MSG_ERROR);
 
                 if (compress)
@@ -744,7 +803,7 @@ private String messageCollectionItemType(TypeMirror type) throws Exception {
             if (primitiveType != null)
                 return primitiveType.getKind().toString();
 
-            if (sameType(type, "org.apache.ignite.internal.managers.communication.CompressedMessage"))
+            if (sameType(type, COMPRESSED_MESSAGE_INTERFACE))
                 throw new IllegalArgumentException(COMPRESSED_MSG_ERROR);
         }
 
@@ -781,9 +840,15 @@ private void returnFalseIfReadFailed(VariableElement field, String mtd, String..
 
         String methodName = field.getAnnotation(Order.class).method();
 
-        if (Objects.equals(methodName, ""))
-            read.add(identedLine("((%s)msg).%s = %s(%s);",
-                field.getEnclosingElement().getSimpleName(), field.getSimpleName().toString(), mtd, argsStr));
+        if (Objects.equals(methodName, "")) {
+            if (type.equals(field.getEnclosingElement()))
+                read.add(identedLine("msg.%s = %s(%s);", field.getSimpleName().toString(), mtd, argsStr));
+            else {
+                // Field has to be requested from a super class object.
+                read.add(identedLine("((%s)msg).%s = %s(%s);",
+                    field.getEnclosingElement().getSimpleName(), field.getSimpleName().toString(), mtd, argsStr));
+            }
+        }
         else
             read.add(identedLine("msg.%s(%s(%s));", methodName, mtd, argsStr));
 
@@ -813,9 +878,15 @@ private void returnFalseIfEnumReadFailed(VariableElement field, String mapperDec
 
         String methodName = field.getAnnotation(Order.class).method();
 
-        if (Objects.equals(methodName, ""))
-            read.add(identedLine("((%s)msg).%s = %s;",
-                field.getEnclosingElement().getSimpleName(), field.getSimpleName().toString(), readOp));
+        if (Objects.equals(methodName, "")) {
+            if (type.equals(field.getEnclosingElement()))
+                read.add(identedLine("msg.%s = %s;", field.getSimpleName().toString(), readOp));
+            else {
+                // Field has to be requested from a super class object.
+                read.add(identedLine("((%s)msg).%s = %s;",
+                    field.getEnclosingElement().getSimpleName(), field.getSimpleName().toString(), readOp));
+            }
+        }
         else
             read.add(identedLine("msg.%s(%s);", methodName, readOp));
 
@@ -831,7 +902,7 @@ private void returnFalseIfEnumReadFailed(VariableElement field, String mapperDec
     }
 
     /** */
-    private void finish(List code) {
+    private void finish(List code, boolean read, boolean marshallable) {
         String lastLine = code.get(code.size() - 1);
 
         if (EMPTY.equals(lastLine))
@@ -840,6 +911,12 @@ private void finish(List code) {
         code.add(identedLine("}"));
         code.add(EMPTY);
 
+        if (read && marshallable) {
+            code.add(identedLine("msg.finishUnmarshal(marshaller, clsLdr);"));
+
+            code.add(EMPTY);
+        }
+
         code.add(identedLine("return true;"));
     }
 
@@ -906,18 +983,28 @@ private void writeClassHeader(Writer writer, String pkgName, String serClsName)
         writer.write(NL);
         writer.write("package " + pkgName + ";" + NL + NL);
 
-        imports.add("org.apache.ignite.plugin.extensions.communication.Message");
+        imports.add(type.toString());
+
+        if (marshallableMessage())
+            imports.add("org.apache.ignite.marshaller.Marshaller");
+
         imports.add("org.apache.ignite.plugin.extensions.communication.MessageSerializer");
         imports.add("org.apache.ignite.plugin.extensions.communication.MessageWriter");
         imports.add("org.apache.ignite.plugin.extensions.communication.MessageReader");
 
-        for (String regularImport: imports)
+        for (String regularImport : imports)
             writer.write("import " + regularImport + ";" + NL);
 
         writer.write(NL);
         writer.write(CLS_JAVADOC);
         writer.write(NL);
-        writer.write("public class " + serClsName + " implements MessageSerializer {" + NL);
+
+        writer.write("public class " + serClsName + " implements MessageSerializer<" + type.getSimpleName() + "> {" + NL);
+    }
+
+    /** */
+    private boolean marshallableMessage() {
+        return env.getTypeUtils().isAssignable(type.asType(), marshallableMsgType);
     }
 
     /** */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryMessageFactory.java
index 66189823f4aba..7f6a3c908a7c9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryMessageFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryMessageFactory.java
@@ -47,6 +47,7 @@
 import org.apache.ignite.internal.processors.query.schema.message.SchemaFinishDiscoveryMessageSerializer;
 import org.apache.ignite.internal.processors.query.schema.message.SchemaProposeDiscoveryMessage;
 import org.apache.ignite.internal.processors.query.schema.message.SchemaProposeDiscoveryMessageSerializer;
+import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.plugin.extensions.communication.MessageFactory;
 import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider;
 import org.apache.ignite.spi.communication.tcp.internal.TcpConnectionRequestDiscoveryMessage;
@@ -75,6 +76,8 @@
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryClientPingRequestSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryClientPingResponse;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryClientPingResponseSerializer;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryClientReconnectMessage;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryClientReconnectMessageMarshallableSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryConnectionCheckMessage;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryConnectionCheckMessageSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryCustomEventMessage;
@@ -88,13 +91,13 @@
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryHandshakeResponse;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryHandshakeResponseSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryJoinRequestMessage;
-import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryJoinRequestMessageSerializer;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryJoinRequestMessageMarshallableSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryLoopbackProblemMessage;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryLoopbackProblemMessageSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryMetricsUpdateMessage;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryMetricsUpdateMessageSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeAddFinishedMessage;
-import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeAddFinishedMessageSerializer;
+import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeAddFinishedMessageMarshallableSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeFailedMessage;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeFailedMessageSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryNodeFullMetricsMessage;
@@ -113,9 +116,27 @@
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryServerOnlyCustomEventMessageSerializer;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryStatusCheckMessage;
 import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryStatusCheckMessageSerializer;
+import org.jetbrains.annotations.Nullable;
 
 /** Message factory for discovery messages. */
 public class DiscoveryMessageFactory implements MessageFactoryProvider {
+    /** Custom data marshaller. */
+    private final @Nullable Marshaller cstDataMarshall;
+
+    /** Class loader for the custom data marshalling. */
+    private final @Nullable ClassLoader cstDataMarshallClsLdr;
+
+    /**
+     * @param cstDataMarshall Custom data marshaller.
+     * @param cstDataMarshallClsLdr Class loader for the custom data marshalling.
+     */
+    public DiscoveryMessageFactory(@Nullable Marshaller cstDataMarshall, @Nullable ClassLoader cstDataMarshallClsLdr) {
+        assert cstDataMarshall == null && cstDataMarshallClsLdr == null || cstDataMarshall != null && cstDataMarshallClsLdr != null;
+
+        this.cstDataMarshall = cstDataMarshall;
+        this.cstDataMarshallClsLdr = cstDataMarshallClsLdr;
+    }
+
     /** {@inheritDoc} */
     @Override public void registerAll(MessageFactory factory) {
         factory.register((short)-109, User::new, new UserSerializer());
@@ -151,12 +172,16 @@ public class DiscoveryMessageFactory implements MessageFactoryProvider {
         factory.register((short)16, TcpDiscoveryNodeLeftMessage::new, new TcpDiscoveryNodeLeftMessageSerializer());
         factory.register((short)17, TcpDiscoveryNodeFailedMessage::new, new TcpDiscoveryNodeFailedMessageSerializer());
         factory.register((short)18, TcpDiscoveryStatusCheckMessage::new, new TcpDiscoveryStatusCheckMessageSerializer());
-        factory.register((short)19, TcpDiscoveryNodeAddFinishedMessage::new, new TcpDiscoveryNodeAddFinishedMessageSerializer());
-        factory.register((short)20, TcpDiscoveryJoinRequestMessage::new, new TcpDiscoveryJoinRequestMessageSerializer());
+        factory.register((short)19, TcpDiscoveryNodeAddFinishedMessage::new,
+            new TcpDiscoveryNodeAddFinishedMessageMarshallableSerializer(cstDataMarshall, cstDataMarshallClsLdr));
+        factory.register((short)20, TcpDiscoveryJoinRequestMessage::new,
+            new TcpDiscoveryJoinRequestMessageMarshallableSerializer(cstDataMarshall, cstDataMarshallClsLdr));
         factory.register((short)21, TcpDiscoveryCustomEventMessage::new, new TcpDiscoveryCustomEventMessageSerializer());
         factory.register((short)22, TcpDiscoveryServerOnlyCustomEventMessage::new,
             new TcpDiscoveryServerOnlyCustomEventMessageSerializer());
         factory.register((short)23, TcpConnectionRequestDiscoveryMessage::new, new TcpConnectionRequestDiscoveryMessageSerializer());
+        factory.register((short)24, TcpDiscoveryClientReconnectMessage::new,
+            new TcpDiscoveryClientReconnectMessageMarshallableSerializer(cstDataMarshall, cstDataMarshallClsLdr));
 
         // DiscoveryCustomMessage
         factory.register((short)500, CacheStatisticsModeChangeMessage::new, new CacheStatisticsModeChangeMessageSerializer());
diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MarshallableMessage.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MarshallableMessage.java
new file mode 100644
index 0000000000000..f58e6cb324110
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MarshallableMessage.java
@@ -0,0 +1,36 @@
+/*
+ * 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.plugin.extensions.communication;
+
+import org.apache.ignite.marshaller.Marshaller;
+
+/** A {@link Message} which still requires external custom pre-marshalling and post-unmarshalling. */
+public interface MarshallableMessage extends Message {
+    /** @param marsh External custom marshaller. */
+    public default void prepareMarshal(Marshaller marsh) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @param marsh External custom marshaller.
+     * @param clsLdr External class loader to post-unmarshall.
+     */
+    public default void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java
index 706b1891572be..90df0601693c3 100644
--- a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java
+++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java
@@ -20,7 +20,7 @@
 /**
  * Interface for message serialization logic.
  */
-public interface MessageSerializer {
+public interface MessageSerializer {
     /**
      * Writes this message to provided byte buffer.
      *
@@ -28,7 +28,7 @@ public interface MessageSerializer {
      * @param writer Writer.
      * @return Whether message was fully written.
      */
-    public boolean writeTo(Message msg, MessageWriter writer);
+    public boolean writeTo(M msg, MessageWriter writer);
 
     /**
      * Reads this message from provided byte buffer.
@@ -37,5 +37,5 @@ public interface MessageSerializer {
      * @param reader Reader.
      * @return Whether message was fully read.
      */
-    public boolean readFrom(Message msg, MessageReader reader);
+    public boolean readFrom(M msg, MessageReader reader);
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
index be87617d45b8d..aea469edc80e3 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java
@@ -788,8 +788,6 @@ private static void sleepEx(long millis, Runnable before, Runnable after) throws
 
                     TcpDiscoveryJoinRequestMessage joinReqMsg = new TcpDiscoveryJoinRequestMessage(node, discoveryData);
 
-                    joinReqMsg.prepareMarshal(spi.marshaller());
-
                     TcpDiscoveryNode nodef = node;
 
                     joinReqMsg.spanContainer().span(
@@ -2310,8 +2308,6 @@ private void processNodeAddFinishedMessage(TcpDiscoveryNodeAddFinishedMessage ms
                         delayDiscoData.clear();
                     }
 
-                    msg.finishUnmarshal(spi.marshaller(), U.resolveClassLoader(spi.ignite().configuration()));
-
                     locNode.setAttributes(msg.clientNodeAttributes());
 
                     clearNodeSensitiveData(locNode);
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
index 01a3733da9823..610526714495b 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java
@@ -1124,8 +1124,6 @@ private void joinTopology() throws IgniteSpiException {
 
         TcpDiscoveryJoinRequestMessage joinReqMsg = new TcpDiscoveryJoinRequestMessage(locNode, discoveryData);
 
-        joinReqMsg.prepareMarshal(spi.marshaller());
-
         joinReqMsg.spanContainer().span(
             tracing.create(TraceableMessagesTable.traceName(joinReqMsg.getClass()))
                 .addTag(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID), () -> locNode.id().toString())
@@ -2493,8 +2491,6 @@ else if (msg instanceof TcpDiscoveryNodeAddFinishedMessage) {
                 if (addFinishMsg.clientDiscoData() != null) {
                     addFinishMsg = new TcpDiscoveryNodeAddFinishedMessage(addFinishMsg);
 
-                    addFinishMsg.prepareMarshal(spi.marshaller());
-
                     msg = addFinishMsg;
 
                     DiscoveryDataPacket discoData = addFinishMsg.clientDiscoData();
@@ -3308,9 +3304,6 @@ private void sendMessageAcrossRing(TcpDiscoveryAbstractMessage msg) {
             if (msg instanceof TraceableMessage)
                 tracing.messages().beforeSend((TraceableMessage)msg);
 
-            if (msg instanceof TcpDiscoveryJoinRequestMessage)
-                ((TcpDiscoveryJoinRequestMessage)msg).prepareMarshal(spi.marshaller());
-
             sendMessageToClients(msg);
 
             List failedNodes;
@@ -4869,8 +4862,6 @@ private void processNodeAddedMessage(TcpDiscoveryNodeAddedMessage msg) {
                         addFinishMsg.clientDiscoData(msg.gridDiscoveryData());
 
                         addFinishMsg.clientNodeAttributes(node.attributes());
-
-                        addFinishMsg.prepareMarshal(spi.marshaller());
                     }
 
                     addFinishMsg = tracing.messages().branch(addFinishMsg, msg);
@@ -6966,8 +6957,6 @@ else if (e.hasCause(ObjectStreamException.class) ||
                         else if (msg instanceof TcpDiscoveryJoinRequestMessage) {
                             TcpDiscoveryJoinRequestMessage req = (TcpDiscoveryJoinRequestMessage)msg;
 
-                            req.finishUnmarshal(spi.marshaller(), U.resolveClassLoader(spi.ignite().configuration()));
-
                             // Current node holds connection with the node that is joining the cluster. Therefore, it can
                             // save certificates with which the connection was established to joining node attributes.
                             if (spi.nodeAuth != null && nodeId.equals(req.node().id()))
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java
index 4658abb1456cd..30e9b1b73f810 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java
@@ -79,7 +79,7 @@ public class TcpDiscoveryIoSession {
     private final Socket sock;
 
     /** */
-    final DirectMessageWriter msgWriter;
+    private final DirectMessageWriter msgWriter;
 
     /** */
     private final DirectMessageReader msgReader;
@@ -91,7 +91,7 @@ public class TcpDiscoveryIoSession {
     private final CompositeInputStream in;
 
     /** Intermediate buffer for serializing discovery messages. */
-    final ByteBuffer msgBuf;
+    private final ByteBuffer msgBuf;
 
     /**
      * Creates a new discovery I/O session bound to the given socket.
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
index 0d99d795a195a..c91dffcb5e7ee 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
@@ -2119,7 +2119,7 @@ protected void onExchange(DiscoveryDataPacket dataPacket, ClassLoader clsLdr) {
         registerMBean(igniteInstanceName, new TcpDiscoverySpiMBeanImpl(this), TcpDiscoverySpiMBean.class);
 
         msgFactory = new IgniteMessageFactoryImpl(
-            new MessageFactoryProvider[] { new DiscoveryMessageFactory() });
+            new MessageFactoryProvider[] { new DiscoveryMessageFactory(marshaller(), U.resolveClassLoader(ignite().configuration())) });
 
         impl.spiStart(igniteInstanceName);
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryClientReconnectMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryClientReconnectMessage.java
index 3a826058c06b2..83ac6fbd2c154 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryClientReconnectMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryClientReconnectMessage.java
@@ -20,28 +20,46 @@
 import java.util.Collection;
 import java.util.Objects;
 import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.managers.discovery.DiscoveryMessageFactory;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.plugin.extensions.communication.MarshallableMessage;
 
 /**
  * Message telling that client node is reconnecting to topology.
  */
 @TcpDiscoveryEnsureDelivery
-public class TcpDiscoveryClientReconnectMessage extends TcpDiscoveryAbstractMessage {
+public class TcpDiscoveryClientReconnectMessage extends TcpDiscoveryAbstractMessage implements MarshallableMessage {
     /** */
     private static final long serialVersionUID = 0L;
 
     /** New router nodeID. */
-    private final UUID routerNodeId;
+    @Order(0)
+    UUID routerNodeId;
 
     /** Last message ID. */
-    private final IgniteUuid lastMsgId;
+    @Order(1)
+    IgniteUuid lastMsgId;
 
     /** Pending messages. */
     @GridToStringExclude
     private Collection msgs;
 
+    /** Srialized bytes of {@link #msgs}. */
+    @Order(2)
+    byte[] msgsBytes;
+
+    /** Constructor for {@link DiscoveryMessageFactory}. */
+    public TcpDiscoveryClientReconnectMessage() {
+        // No-op.
+    }
+
     /**
      * @param creatorNodeId Creator node ID.
      * @param routerNodeId New router node ID.
@@ -111,6 +129,37 @@ public boolean success() {
             Objects.equals(lastMsgId, other.lastMsgId);
     }
 
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(Marshaller marsh) {
+        if (msgs != null && msgsBytes == null) {
+            try {
+                msgsBytes = U.marshal(marsh, msgs);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Failed to marshal the pending messages.", e);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
+        if (msgsBytes != null && msgs == null) {
+            try {
+                msgs = U.unmarshal(marsh, msgsBytes, clsLdr);
+
+                msgsBytes = null;
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Failed to unmarshal the pending messages.", e);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public short directType() {
+        return 24;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(TcpDiscoveryClientReconnectMessage.class, this, "super", super.toString());
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryJoinRequestMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryJoinRequestMessage.java
index 6ddbb8f7af2c4..8932c3f7af901 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryJoinRequestMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryJoinRequestMessage.java
@@ -23,7 +23,7 @@
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.Marshaller;
-import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MarshallableMessage;
 import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket;
 import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode;
 
@@ -33,7 +33,7 @@
  * Initial message sent by a node that wants to enter topology.
  * Sent to random node during SPI start. Then forwarded directly to coordinator.
  */
-public class TcpDiscoveryJoinRequestMessage extends TcpDiscoveryAbstractTraceableMessage implements Message {
+public class TcpDiscoveryJoinRequestMessage extends TcpDiscoveryAbstractTraceableMessage implements MarshallableMessage {
     /** */
     private static final long serialVersionUID = 0L;
 
@@ -95,10 +95,8 @@ public void responded(boolean responded) {
         setFlag(RESPONDED_FLAG_POS, responded);
     }
 
-    /**
-     * @param marsh Marshaller.
-     */
-    public void prepareMarshal(Marshaller marsh) {
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(Marshaller marsh) {
         if (node != null && nodeBytes == null) {
             try {
                 nodeBytes = U.marshal(marsh, node);
@@ -109,11 +107,8 @@ public void prepareMarshal(Marshaller marsh) {
         }
     }
 
-    /**
-     * @param marsh Marshaller.
-     * @param clsLdr Class loader.
-     */
-    public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
         if (nodeBytes != null && node == null) {
             try {
                 node = U.unmarshal(marsh, nodeBytes, clsLdr);
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java
index 86fecaed00fa3..820c42156b53e 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java
@@ -23,11 +23,10 @@
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.Order;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
-import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.Marshaller;
-import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.plugin.extensions.communication.MarshallableMessage;
 import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket;
 import org.jetbrains.annotations.Nullable;
 
@@ -36,7 +35,7 @@
  */
 @TcpDiscoveryEnsureDelivery
 @TcpDiscoveryRedirectToClient
-public class TcpDiscoveryNodeAddFinishedMessage extends TcpDiscoveryAbstractTraceableMessage implements Message {
+public class TcpDiscoveryNodeAddFinishedMessage extends TcpDiscoveryAbstractTraceableMessage implements MarshallableMessage {
     /** */
     private static final long serialVersionUID = 0L;
 
@@ -85,6 +84,7 @@ public TcpDiscoveryNodeAddFinishedMessage(TcpDiscoveryNodeAddFinishedMessage msg
         nodeId = msg.nodeId;
         clientDiscoData = msg.clientDiscoData;
         clientNodeAttrs = msg.clientNodeAttrs;
+        clientNodeAttrsBytes = msg.clientNodeAttrsBytes;
     }
 
     /**
@@ -126,35 +126,28 @@ public void clientNodeAttributes(Map clientNodeAttrs) {
         this.clientNodeAttrs = clientNodeAttrs;
     }
 
-    /**
-     * @param marsh Marshaller.
-     */
-    public void prepareMarshal(Marshaller marsh) {
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(Marshaller marsh) {
         if (clientNodeAttrs != null && clientNodeAttrsBytes == null) {
             try {
                 clientNodeAttrsBytes = U.marshal(marsh, clientNodeAttrs);
             }
             catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to marshal client node attributes", e);
+                throw new IgniteException("Failed to marshal client node attributes.", e);
             }
         }
     }
 
-    /**
-     * @param marsh Marshaller.
-     * @param clsLdr Class loader.
-     */
-    public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
-        if (F.isEmpty(clientNodeAttrsBytes))
-            clientNodeAttrs = null;
-        else {
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
+        if (clientNodeAttrsBytes != null && clientNodeAttrs == null) {
             try {
                 clientNodeAttrs = U.unmarshal(marsh, clientNodeAttrsBytes, clsLdr);
 
                 clientNodeAttrsBytes = null;
             }
             catch (IgniteCheckedException e) {
-                throw new IgniteException("Failed to unmarshal client node attributes", e);
+                throw new IgniteException("Failed to unmarshal client node attributes.", e);
             }
         }
     }
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 019364513a200..ee30d719dccc3 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
@@ -228,6 +228,18 @@ public void testCustomMapperEnumFieldsMessage() {
             .hasSourceEquivalentTo(javaFile("CustomMapperEnumFieldsMessageSerializer.java"));
     }
 
+    /** */
+    @Test
+    public void testMarshallableMessage() {
+        Compilation compilation = compile("TestMarshallableMessage.java");
+
+        assertThat(compilation).succeeded();
+
+        assertThat(compilation)
+            .generatedSourceFile("org.apache.ignite.internal.TestMarshallableMessageMarshallableSerializer")
+            .hasSourceEquivalentTo(javaFile("TestMarshallableMessageMarshallableSerializer.java"));
+    }
+
     /**
      * Negative test for a coflict situation when two enum mappers are used for the same enum in different messages.
      */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java
index cb6c40576fe0a..44f44be77f700 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java
@@ -101,7 +101,7 @@ private static DirectByteBufferStream createStream(ByteBuffer buff) {
             @Override public MessageSerializer serializer(short type) {
                 return null;
             }
-        }, null);
+        });
 
         stream.setBuffer(buff);
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/AbstractMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/AbstractMessageSerializationTest.java
index 317ff20a961ec..2f28cfc4146b0 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/AbstractMessageSerializationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/AbstractMessageSerializationTest.java
@@ -435,7 +435,8 @@ private void readField(Class type) {
         @Override public byte[] readByteArray() {
             readField(byte[].class);
 
-            return new byte[0];
+            // Messages may try to post-marshall non-null byte data.
+            return null;
         }
 
         /** {@inheritDoc} */
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteDiscoveryMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteDiscoveryMessageSerializationTest.java
index 6adada121f281..f6eaab9c754ce 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteDiscoveryMessageSerializationTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/discovery/IgniteDiscoveryMessageSerializationTest.java
@@ -24,6 +24,6 @@
 public class IgniteDiscoveryMessageSerializationTest extends AbstractMessageSerializationTest {
     /** {@inheritDoc} */
     @Override protected MessageFactoryProvider messageFactory() {
-        return new DiscoveryMessageFactory();
+        return new DiscoveryMessageFactory(null, null);
     }
 }
diff --git a/modules/core/src/test/resources/codegen/AbstractMessage.java b/modules/core/src/test/resources/codegen/AbstractMessage.java
index a309841ba5c4a..d63c3cc5f2ffb 100644
--- a/modules/core/src/test/resources/codegen/AbstractMessage.java
+++ b/modules/core/src/test/resources/codegen/AbstractMessage.java
@@ -26,6 +26,9 @@ public abstract class AbstractMessage implements Message {
     @Order(0)
     int id;
 
+    @Order(1)
+    byte flags;
+
     public short directType() {
         return 0;
     }
diff --git a/modules/core/src/test/resources/codegen/ChildMessage.java b/modules/core/src/test/resources/codegen/ChildMessage.java
index fa97a6cbc4441..b89460948a889 100644
--- a/modules/core/src/test/resources/codegen/ChildMessage.java
+++ b/modules/core/src/test/resources/codegen/ChildMessage.java
@@ -23,4 +23,7 @@
 public class ChildMessage extends AbstractMessage {
     @Order(0)
     String str;
+
+    @Order(1)
+    byte flags;
 }
diff --git a/modules/core/src/test/resources/codegen/ChildMessageSerializer.java b/modules/core/src/test/resources/codegen/ChildMessageSerializer.java
index f7989a079c7ef..9ca035db40488 100644
--- a/modules/core/src/test/resources/codegen/ChildMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/ChildMessageSerializer.java
@@ -19,7 +19,6 @@
 
 import org.apache.ignite.internal.AbstractMessage;
 import org.apache.ignite.internal.ChildMessage;
-import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
 import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -29,11 +28,9 @@
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public class ChildMessageSerializer implements MessageSerializer {
+public class ChildMessageSerializer implements MessageSerializer {
     /** */
-    @Override public boolean writeTo(Message m, MessageWriter writer) {
-        ChildMessage msg = (ChildMessage)m;
-
+    @Override public boolean writeTo(ChildMessage msg, MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -49,7 +46,19 @@ public class ChildMessageSerializer implements MessageSerializer {
                 writer.incrementState();
 
             case 1:
-                if (!writer.writeString(((ChildMessage)msg).str))
+                if (!writer.writeByte(((AbstractMessage)msg).flags))
+                    return false;
+
+                writer.incrementState();
+
+            case 2:
+                if (!writer.writeString(msg.str))
+                    return false;
+
+                writer.incrementState();
+
+            case 3:
+                if (!writer.writeByte(msg.flags))
                     return false;
 
                 writer.incrementState();
@@ -59,9 +68,7 @@ public class ChildMessageSerializer implements MessageSerializer {
     }
 
     /** */
-    @Override public boolean readFrom(Message m, MessageReader reader) {
-        ChildMessage msg = (ChildMessage)m;
-
+    @Override public boolean readFrom(ChildMessage msg, MessageReader reader) {
         switch (reader.state()) {
             case 0:
                 ((AbstractMessage)msg).id = reader.readInt();
@@ -72,7 +79,23 @@ public class ChildMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 1:
-                ((ChildMessage)msg).str = reader.readString();
+                ((AbstractMessage)msg).flags = reader.readByte();
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 2:
+                msg.str = reader.readString();
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 3:
+                msg.flags = reader.readByte();
 
                 if (!reader.isLastRead())
                     return false;
diff --git a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
index 180f067c2f185..db939d0825792 100644
--- a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java
@@ -19,7 +19,6 @@
 
 import org.apache.ignite.internal.CustomMapperEnumFieldsMessage;
 import org.apache.ignite.internal.TransactionIsolationEnumMapper;
-import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
 import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -31,14 +30,12 @@
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public class CustomMapperEnumFieldsMessageSerializer implements MessageSerializer {
+public class CustomMapperEnumFieldsMessageSerializer implements MessageSerializer {
     /** */
     private final EnumMapper transactionIsolationMapper = new TransactionIsolationEnumMapper();
 
     /** */
-    @Override public boolean writeTo(Message m, MessageWriter writer) {
-        CustomMapperEnumFieldsMessage msg = (CustomMapperEnumFieldsMessage)m;
-
+    @Override public boolean writeTo(CustomMapperEnumFieldsMessage msg, MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -48,7 +45,7 @@ public class CustomMapperEnumFieldsMessageSerializer implements MessageSerialize
 
         switch (writer.state()) {
             case 0:
-                if (!writer.writeByte(transactionIsolationMapper.encode(((CustomMapperEnumFieldsMessage)msg).txMode)))
+                if (!writer.writeByte(transactionIsolationMapper.encode(msg.txMode)))
                     return false;
 
                 writer.incrementState();
@@ -58,12 +55,10 @@ public class CustomMapperEnumFieldsMessageSerializer implements MessageSerialize
     }
 
     /** */
-    @Override public boolean readFrom(Message m, MessageReader reader) {
-        CustomMapperEnumFieldsMessage msg = (CustomMapperEnumFieldsMessage)m;
-
+    @Override public boolean readFrom(CustomMapperEnumFieldsMessage msg, MessageReader reader) {
         switch (reader.state()) {
             case 0:
-                ((CustomMapperEnumFieldsMessage)msg).txMode = transactionIsolationMapper.decode(reader.readByte());
+                msg.txMode = transactionIsolationMapper.decode(reader.readByte());
 
                 if (!reader.isLastRead())
                     return false;
diff --git a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
index ce0dfcfab17ad..245f1f29ae8e5 100644
--- a/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/DefaultMapperEnumFieldsMessageSerializer.java
@@ -19,7 +19,6 @@
 
 import org.apache.ignite.internal.DefaultMapperEnumFieldsMessage;
 import org.apache.ignite.internal.processors.cache.GridCacheOperation;
-import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
 import org.apache.ignite.plugin.extensions.communication.MessageWriter;
@@ -31,16 +30,14 @@
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public class DefaultMapperEnumFieldsMessageSerializer implements MessageSerializer {
+public class DefaultMapperEnumFieldsMessageSerializer implements MessageSerializer {
     /** */
     private final GridCacheOperation[] gridCacheOperationVals = GridCacheOperation.values();
     /** */
     private final TransactionIsolation[] transactionIsolationVals = TransactionIsolation.values();
 
     /** */
-    @Override public boolean writeTo(Message m, MessageWriter writer) {
-        DefaultMapperEnumFieldsMessage msg = (DefaultMapperEnumFieldsMessage)m;
-
+    @Override public boolean writeTo(DefaultMapperEnumFieldsMessage msg, MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -50,13 +47,13 @@ public class DefaultMapperEnumFieldsMessageSerializer implements MessageSerializ
 
         switch (writer.state()) {
             case 0:
-                if (!writer.writeByte(DefaultEnumMapper.INSTANCE.encode(((DefaultMapperEnumFieldsMessage)msg).publicEnum)))
+                if (!writer.writeByte(DefaultEnumMapper.INSTANCE.encode(msg.publicEnum)))
                     return false;
 
                 writer.incrementState();
 
             case 1:
-                if (!writer.writeByte(DefaultEnumMapper.INSTANCE.encode(((DefaultMapperEnumFieldsMessage)msg).internalEnum)))
+                if (!writer.writeByte(DefaultEnumMapper.INSTANCE.encode(msg.internalEnum)))
                     return false;
 
                 writer.incrementState();
@@ -66,12 +63,10 @@ public class DefaultMapperEnumFieldsMessageSerializer implements MessageSerializ
     }
 
     /** */
-    @Override public boolean readFrom(Message m, MessageReader reader) {
-        DefaultMapperEnumFieldsMessage msg = (DefaultMapperEnumFieldsMessage)m;
-
+    @Override public boolean readFrom(DefaultMapperEnumFieldsMessage msg, MessageReader reader) {
         switch (reader.state()) {
             case 0:
-                ((DefaultMapperEnumFieldsMessage)msg).publicEnum = DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, reader.readByte());
+                msg.publicEnum = DefaultEnumMapper.INSTANCE.decode(transactionIsolationVals, reader.readByte());
 
                 if (!reader.isLastRead())
                     return false;
@@ -79,7 +74,7 @@ public class DefaultMapperEnumFieldsMessageSerializer implements MessageSerializ
                 reader.incrementState();
 
             case 1:
-                ((DefaultMapperEnumFieldsMessage)msg).internalEnum = DefaultEnumMapper.INSTANCE.decode(gridCacheOperationVals, reader.readByte());
+                msg.internalEnum = DefaultEnumMapper.INSTANCE.decode(gridCacheOperationVals, reader.readByte());
 
                 if (!reader.isLastRead())
                     return false;
diff --git a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java
index 00335f38db649..2f4f365cc830a 100644
--- a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.TestCollectionsMessage;
-import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
@@ -29,11 +28,9 @@
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public class TestCollectionsMessageSerializer implements MessageSerializer {
+public class TestCollectionsMessageSerializer implements MessageSerializer {
     /** */
-    @Override public boolean writeTo(Message m, MessageWriter writer) {
-        TestCollectionsMessage msg = (TestCollectionsMessage)m;
-
+    @Override public boolean writeTo(TestCollectionsMessage msg, MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -43,151 +40,151 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
 
         switch (writer.state()) {
             case 0:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).booleanArrayList, MessageCollectionItemType.BOOLEAN_ARR))
+                if (!writer.writeCollection(msg.booleanArrayList, MessageCollectionItemType.BOOLEAN_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 1:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).byteArrayList, MessageCollectionItemType.BYTE_ARR))
+                if (!writer.writeCollection(msg.byteArrayList, MessageCollectionItemType.BYTE_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 2:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).shortArrayList, MessageCollectionItemType.SHORT_ARR))
+                if (!writer.writeCollection(msg.shortArrayList, MessageCollectionItemType.SHORT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 3:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).intArrayList, MessageCollectionItemType.INT_ARR))
+                if (!writer.writeCollection(msg.intArrayList, MessageCollectionItemType.INT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 4:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).longArrayList, MessageCollectionItemType.LONG_ARR))
+                if (!writer.writeCollection(msg.longArrayList, MessageCollectionItemType.LONG_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).charArrayList, MessageCollectionItemType.CHAR_ARR))
+                if (!writer.writeCollection(msg.charArrayList, MessageCollectionItemType.CHAR_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 6:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).floatArrayList, MessageCollectionItemType.FLOAT_ARR))
+                if (!writer.writeCollection(msg.floatArrayList, MessageCollectionItemType.FLOAT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 7:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).doubleArrayList, MessageCollectionItemType.DOUBLE_ARR))
+                if (!writer.writeCollection(msg.doubleArrayList, MessageCollectionItemType.DOUBLE_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 8:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).stringList, MessageCollectionItemType.STRING))
+                if (!writer.writeCollection(msg.stringList, MessageCollectionItemType.STRING))
                     return false;
 
                 writer.incrementState();
 
             case 9:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).uuidList, MessageCollectionItemType.UUID))
+                if (!writer.writeCollection(msg.uuidList, MessageCollectionItemType.UUID))
                     return false;
 
                 writer.incrementState();
 
             case 10:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).bitSetList, MessageCollectionItemType.BIT_SET))
+                if (!writer.writeCollection(msg.bitSetList, MessageCollectionItemType.BIT_SET))
                     return false;
 
                 writer.incrementState();
 
             case 11:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).igniteUuidList, MessageCollectionItemType.IGNITE_UUID))
+                if (!writer.writeCollection(msg.igniteUuidList, MessageCollectionItemType.IGNITE_UUID))
                     return false;
 
                 writer.incrementState();
 
             case 12:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).affTopVersionList, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION))
+                if (!writer.writeCollection(msg.affTopVersionList, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION))
                     return false;
 
                 writer.incrementState();
 
             case 13:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedBooleanList, MessageCollectionItemType.BOOLEAN))
+                if (!writer.writeCollection(msg.boxedBooleanList, MessageCollectionItemType.BOOLEAN))
                     return false;
 
                 writer.incrementState();
 
             case 14:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedByteList, MessageCollectionItemType.BYTE))
+                if (!writer.writeCollection(msg.boxedByteList, MessageCollectionItemType.BYTE))
                     return false;
 
                 writer.incrementState();
 
             case 15:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedShortList, MessageCollectionItemType.SHORT))
+                if (!writer.writeCollection(msg.boxedShortList, MessageCollectionItemType.SHORT))
                     return false;
 
                 writer.incrementState();
 
             case 16:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedIntList, MessageCollectionItemType.INT))
+                if (!writer.writeCollection(msg.boxedIntList, MessageCollectionItemType.INT))
                     return false;
 
                 writer.incrementState();
 
             case 17:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedLongList, MessageCollectionItemType.LONG))
+                if (!writer.writeCollection(msg.boxedLongList, MessageCollectionItemType.LONG))
                     return false;
 
                 writer.incrementState();
 
             case 18:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedCharList, MessageCollectionItemType.CHAR))
+                if (!writer.writeCollection(msg.boxedCharList, MessageCollectionItemType.CHAR))
                     return false;
 
                 writer.incrementState();
 
             case 19:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedFloatList, MessageCollectionItemType.FLOAT))
+                if (!writer.writeCollection(msg.boxedFloatList, MessageCollectionItemType.FLOAT))
                     return false;
 
                 writer.incrementState();
 
             case 20:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).boxedDoubleList, MessageCollectionItemType.DOUBLE))
+                if (!writer.writeCollection(msg.boxedDoubleList, MessageCollectionItemType.DOUBLE))
                     return false;
 
                 writer.incrementState();
 
             case 21:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).messageList, MessageCollectionItemType.MSG))
+                if (!writer.writeCollection(msg.messageList, MessageCollectionItemType.MSG))
                     return false;
 
                 writer.incrementState();
 
             case 22:
-                if (!writer.writeCollection(((TestCollectionsMessage)msg).gridLongListList, MessageCollectionItemType.GRID_LONG_LIST))
+                if (!writer.writeCollection(msg.gridLongListList, MessageCollectionItemType.GRID_LONG_LIST))
                     return false;
 
                 writer.incrementState();
 
             case 23:
-                if (!writer.writeSet(((TestCollectionsMessage)msg).boxedIntegerSet, MessageCollectionItemType.INT))
+                if (!writer.writeSet(msg.boxedIntegerSet, MessageCollectionItemType.INT))
                     return false;
 
                 writer.incrementState();
 
             case 24:
-                if (!writer.writeSet(((TestCollectionsMessage)msg).bitSetSet, MessageCollectionItemType.BIT_SET))
+                if (!writer.writeSet(msg.bitSetSet, MessageCollectionItemType.BIT_SET))
                     return false;
 
                 writer.incrementState();
@@ -197,12 +194,10 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
     }
 
     /** */
-    @Override public boolean readFrom(Message m, MessageReader reader) {
-        TestCollectionsMessage msg = (TestCollectionsMessage)m;
-
+    @Override public boolean readFrom(TestCollectionsMessage msg, MessageReader reader) {
         switch (reader.state()) {
             case 0:
-                ((TestCollectionsMessage)msg).booleanArrayList = reader.readCollection(MessageCollectionItemType.BOOLEAN_ARR);
+                msg.booleanArrayList = reader.readCollection(MessageCollectionItemType.BOOLEAN_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -210,7 +205,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 1:
-                ((TestCollectionsMessage)msg).byteArrayList = reader.readCollection(MessageCollectionItemType.BYTE_ARR);
+                msg.byteArrayList = reader.readCollection(MessageCollectionItemType.BYTE_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -218,7 +213,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 2:
-                ((TestCollectionsMessage)msg).shortArrayList = reader.readCollection(MessageCollectionItemType.SHORT_ARR);
+                msg.shortArrayList = reader.readCollection(MessageCollectionItemType.SHORT_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -226,7 +221,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 3:
-                ((TestCollectionsMessage)msg).intArrayList = reader.readCollection(MessageCollectionItemType.INT_ARR);
+                msg.intArrayList = reader.readCollection(MessageCollectionItemType.INT_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -234,7 +229,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 4:
-                ((TestCollectionsMessage)msg).longArrayList = reader.readCollection(MessageCollectionItemType.LONG_ARR);
+                msg.longArrayList = reader.readCollection(MessageCollectionItemType.LONG_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -242,7 +237,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 5:
-                ((TestCollectionsMessage)msg).charArrayList = reader.readCollection(MessageCollectionItemType.CHAR_ARR);
+                msg.charArrayList = reader.readCollection(MessageCollectionItemType.CHAR_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -250,7 +245,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 6:
-                ((TestCollectionsMessage)msg).floatArrayList = reader.readCollection(MessageCollectionItemType.FLOAT_ARR);
+                msg.floatArrayList = reader.readCollection(MessageCollectionItemType.FLOAT_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -258,7 +253,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 7:
-                ((TestCollectionsMessage)msg).doubleArrayList = reader.readCollection(MessageCollectionItemType.DOUBLE_ARR);
+                msg.doubleArrayList = reader.readCollection(MessageCollectionItemType.DOUBLE_ARR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -266,7 +261,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 8:
-                ((TestCollectionsMessage)msg).stringList = reader.readCollection(MessageCollectionItemType.STRING);
+                msg.stringList = reader.readCollection(MessageCollectionItemType.STRING);
 
                 if (!reader.isLastRead())
                     return false;
@@ -274,7 +269,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 9:
-                ((TestCollectionsMessage)msg).uuidList = reader.readCollection(MessageCollectionItemType.UUID);
+                msg.uuidList = reader.readCollection(MessageCollectionItemType.UUID);
 
                 if (!reader.isLastRead())
                     return false;
@@ -282,7 +277,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 10:
-                ((TestCollectionsMessage)msg).bitSetList = reader.readCollection(MessageCollectionItemType.BIT_SET);
+                msg.bitSetList = reader.readCollection(MessageCollectionItemType.BIT_SET);
 
                 if (!reader.isLastRead())
                     return false;
@@ -290,7 +285,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 11:
-                ((TestCollectionsMessage)msg).igniteUuidList = reader.readCollection(MessageCollectionItemType.IGNITE_UUID);
+                msg.igniteUuidList = reader.readCollection(MessageCollectionItemType.IGNITE_UUID);
 
                 if (!reader.isLastRead())
                     return false;
@@ -298,7 +293,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 12:
-                ((TestCollectionsMessage)msg).affTopVersionList = reader.readCollection(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION);
+                msg.affTopVersionList = reader.readCollection(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION);
 
                 if (!reader.isLastRead())
                     return false;
@@ -306,7 +301,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 13:
-                ((TestCollectionsMessage)msg).boxedBooleanList = reader.readCollection(MessageCollectionItemType.BOOLEAN);
+                msg.boxedBooleanList = reader.readCollection(MessageCollectionItemType.BOOLEAN);
 
                 if (!reader.isLastRead())
                     return false;
@@ -314,7 +309,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 14:
-                ((TestCollectionsMessage)msg).boxedByteList = reader.readCollection(MessageCollectionItemType.BYTE);
+                msg.boxedByteList = reader.readCollection(MessageCollectionItemType.BYTE);
 
                 if (!reader.isLastRead())
                     return false;
@@ -322,7 +317,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 15:
-                ((TestCollectionsMessage)msg).boxedShortList = reader.readCollection(MessageCollectionItemType.SHORT);
+                msg.boxedShortList = reader.readCollection(MessageCollectionItemType.SHORT);
 
                 if (!reader.isLastRead())
                     return false;
@@ -330,7 +325,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 16:
-                ((TestCollectionsMessage)msg).boxedIntList = reader.readCollection(MessageCollectionItemType.INT);
+                msg.boxedIntList = reader.readCollection(MessageCollectionItemType.INT);
 
                 if (!reader.isLastRead())
                     return false;
@@ -338,7 +333,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 17:
-                ((TestCollectionsMessage)msg).boxedLongList = reader.readCollection(MessageCollectionItemType.LONG);
+                msg.boxedLongList = reader.readCollection(MessageCollectionItemType.LONG);
 
                 if (!reader.isLastRead())
                     return false;
@@ -346,7 +341,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 18:
-                ((TestCollectionsMessage)msg).boxedCharList = reader.readCollection(MessageCollectionItemType.CHAR);
+                msg.boxedCharList = reader.readCollection(MessageCollectionItemType.CHAR);
 
                 if (!reader.isLastRead())
                     return false;
@@ -354,7 +349,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 19:
-                ((TestCollectionsMessage)msg).boxedFloatList = reader.readCollection(MessageCollectionItemType.FLOAT);
+                msg.boxedFloatList = reader.readCollection(MessageCollectionItemType.FLOAT);
 
                 if (!reader.isLastRead())
                     return false;
@@ -362,7 +357,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 20:
-                ((TestCollectionsMessage)msg).boxedDoubleList = reader.readCollection(MessageCollectionItemType.DOUBLE);
+                msg.boxedDoubleList = reader.readCollection(MessageCollectionItemType.DOUBLE);
 
                 if (!reader.isLastRead())
                     return false;
@@ -370,7 +365,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 21:
-                ((TestCollectionsMessage)msg).messageList = reader.readCollection(MessageCollectionItemType.MSG);
+                msg.messageList = reader.readCollection(MessageCollectionItemType.MSG);
 
                 if (!reader.isLastRead())
                     return false;
@@ -378,7 +373,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 22:
-                ((TestCollectionsMessage)msg).gridLongListList = reader.readCollection(MessageCollectionItemType.GRID_LONG_LIST);
+                msg.gridLongListList = reader.readCollection(MessageCollectionItemType.GRID_LONG_LIST);
 
                 if (!reader.isLastRead())
                     return false;
@@ -386,7 +381,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 23:
-                ((TestCollectionsMessage)msg).boxedIntegerSet = reader.readSet(MessageCollectionItemType.INT);
+                msg.boxedIntegerSet = reader.readSet(MessageCollectionItemType.INT);
 
                 if (!reader.isLastRead())
                     return false;
@@ -394,7 +389,7 @@ public class TestCollectionsMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 24:
-                ((TestCollectionsMessage)msg).bitSetSet = reader.readSet(MessageCollectionItemType.BIT_SET);
+                msg.bitSetSet = reader.readSet(MessageCollectionItemType.BIT_SET);
 
                 if (!reader.isLastRead())
                     return false;
diff --git a/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java
index 9753dd90e53e0..42d0773b7e224 100644
--- a/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java
@@ -18,7 +18,6 @@
 package org.apache.ignite.internal;
 
 import org.apache.ignite.internal.TestMapMessage;
-import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
@@ -29,11 +28,9 @@
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public class TestMapMessageSerializer implements MessageSerializer {
+public class TestMapMessageSerializer implements MessageSerializer {
     /** */
-    @Override public boolean writeTo(Message m, MessageWriter writer) {
-        TestMapMessage msg = (TestMapMessage)m;
-
+    @Override public boolean writeTo(TestMapMessage msg, MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -43,145 +40,145 @@ public class TestMapMessageSerializer implements MessageSerializer {
 
         switch (writer.state()) {
             case 0:
-                if (!writer.writeMap(((TestMapMessage)msg).booleanArrayBoxedLongMap, MessageCollectionItemType.BOOLEAN_ARR, MessageCollectionItemType.LONG))
+                if (!writer.writeMap(msg.booleanArrayBoxedLongMap, MessageCollectionItemType.BOOLEAN_ARR, MessageCollectionItemType.LONG))
                     return false;
 
                 writer.incrementState();
 
             case 1:
-                if (!writer.writeMap(((TestMapMessage)msg).byteArrayBooleanArrayMap, MessageCollectionItemType.BYTE_ARR, MessageCollectionItemType.BOOLEAN_ARR))
+                if (!writer.writeMap(msg.byteArrayBooleanArrayMap, MessageCollectionItemType.BYTE_ARR, MessageCollectionItemType.BOOLEAN_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 2:
-                if (!writer.writeMap(((TestMapMessage)msg).shortArrayByteArrayMap, MessageCollectionItemType.SHORT_ARR, MessageCollectionItemType.BYTE_ARR))
+                if (!writer.writeMap(msg.shortArrayByteArrayMap, MessageCollectionItemType.SHORT_ARR, MessageCollectionItemType.BYTE_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 3:
-                if (!writer.writeMap(((TestMapMessage)msg).intArrayShortArrayMap, MessageCollectionItemType.INT_ARR, MessageCollectionItemType.SHORT_ARR))
+                if (!writer.writeMap(msg.intArrayShortArrayMap, MessageCollectionItemType.INT_ARR, MessageCollectionItemType.SHORT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 4:
-                if (!writer.writeMap(((TestMapMessage)msg).longArrayIntArrayMap, MessageCollectionItemType.LONG_ARR, MessageCollectionItemType.INT_ARR))
+                if (!writer.writeMap(msg.longArrayIntArrayMap, MessageCollectionItemType.LONG_ARR, MessageCollectionItemType.INT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeMap(((TestMapMessage)msg).charArrayLongArrayMap, MessageCollectionItemType.CHAR_ARR, MessageCollectionItemType.LONG_ARR))
+                if (!writer.writeMap(msg.charArrayLongArrayMap, MessageCollectionItemType.CHAR_ARR, MessageCollectionItemType.LONG_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 6:
-                if (!writer.writeMap(((TestMapMessage)msg).floatArrayCharArrayMap, MessageCollectionItemType.FLOAT_ARR, MessageCollectionItemType.CHAR_ARR))
+                if (!writer.writeMap(msg.floatArrayCharArrayMap, MessageCollectionItemType.FLOAT_ARR, MessageCollectionItemType.CHAR_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 7:
-                if (!writer.writeMap(((TestMapMessage)msg).doubleArrayFloatArrayMap, MessageCollectionItemType.DOUBLE_ARR, MessageCollectionItemType.FLOAT_ARR))
+                if (!writer.writeMap(msg.doubleArrayFloatArrayMap, MessageCollectionItemType.DOUBLE_ARR, MessageCollectionItemType.FLOAT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 8:
-                if (!writer.writeMap(((TestMapMessage)msg).stringDoubleArrayMap, MessageCollectionItemType.STRING, MessageCollectionItemType.DOUBLE_ARR))
+                if (!writer.writeMap(msg.stringDoubleArrayMap, MessageCollectionItemType.STRING, MessageCollectionItemType.DOUBLE_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 9:
-                if (!writer.writeMap(((TestMapMessage)msg).uuidStringMap, MessageCollectionItemType.UUID, MessageCollectionItemType.STRING))
+                if (!writer.writeMap(msg.uuidStringMap, MessageCollectionItemType.UUID, MessageCollectionItemType.STRING))
                     return false;
 
                 writer.incrementState();
 
             case 10:
-                if (!writer.writeMap(((TestMapMessage)msg).bitSetUuidMap, MessageCollectionItemType.BIT_SET, MessageCollectionItemType.UUID))
+                if (!writer.writeMap(msg.bitSetUuidMap, MessageCollectionItemType.BIT_SET, MessageCollectionItemType.UUID))
                     return false;
 
                 writer.incrementState();
 
             case 11:
-                if (!writer.writeMap(((TestMapMessage)msg).igniteUuidBitSetMap, MessageCollectionItemType.IGNITE_UUID, MessageCollectionItemType.BIT_SET))
+                if (!writer.writeMap(msg.igniteUuidBitSetMap, MessageCollectionItemType.IGNITE_UUID, MessageCollectionItemType.BIT_SET))
                     return false;
 
                 writer.incrementState();
 
             case 12:
-                if (!writer.writeMap(((TestMapMessage)msg).affTopVersionIgniteUuidMap, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION, MessageCollectionItemType.IGNITE_UUID))
+                if (!writer.writeMap(msg.affTopVersionIgniteUuidMap, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION, MessageCollectionItemType.IGNITE_UUID))
                     return false;
 
                 writer.incrementState();
 
             case 13:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedBooleanAffTopVersionMap, MessageCollectionItemType.BOOLEAN, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION))
+                if (!writer.writeMap(msg.boxedBooleanAffTopVersionMap, MessageCollectionItemType.BOOLEAN, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION))
                     return false;
 
                 writer.incrementState();
 
             case 14:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedByteBoxedBooleanMap, MessageCollectionItemType.BYTE, MessageCollectionItemType.BOOLEAN))
+                if (!writer.writeMap(msg.boxedByteBoxedBooleanMap, MessageCollectionItemType.BYTE, MessageCollectionItemType.BOOLEAN))
                     return false;
 
                 writer.incrementState();
 
             case 15:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedShortBoxedByteMap, MessageCollectionItemType.SHORT, MessageCollectionItemType.BYTE))
+                if (!writer.writeMap(msg.boxedShortBoxedByteMap, MessageCollectionItemType.SHORT, MessageCollectionItemType.BYTE))
                     return false;
 
                 writer.incrementState();
 
             case 16:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedIntBoxedShortMap, MessageCollectionItemType.INT, MessageCollectionItemType.SHORT))
+                if (!writer.writeMap(msg.boxedIntBoxedShortMap, MessageCollectionItemType.INT, MessageCollectionItemType.SHORT))
                     return false;
 
                 writer.incrementState();
 
             case 17:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedLongBoxedIntMap, MessageCollectionItemType.LONG, MessageCollectionItemType.INT))
+                if (!writer.writeMap(msg.boxedLongBoxedIntMap, MessageCollectionItemType.LONG, MessageCollectionItemType.INT))
                     return false;
 
                 writer.incrementState();
 
             case 18:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedCharBoxedLongMap, MessageCollectionItemType.CHAR, MessageCollectionItemType.LONG))
+                if (!writer.writeMap(msg.boxedCharBoxedLongMap, MessageCollectionItemType.CHAR, MessageCollectionItemType.LONG))
                     return false;
 
                 writer.incrementState();
 
             case 19:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedFloatBoxedCharMap, MessageCollectionItemType.FLOAT, MessageCollectionItemType.CHAR))
+                if (!writer.writeMap(msg.boxedFloatBoxedCharMap, MessageCollectionItemType.FLOAT, MessageCollectionItemType.CHAR))
                     return false;
 
                 writer.incrementState();
 
             case 20:
-                if (!writer.writeMap(((TestMapMessage)msg).boxedDoubleBoxedFloatMap, MessageCollectionItemType.DOUBLE, MessageCollectionItemType.FLOAT))
+                if (!writer.writeMap(msg.boxedDoubleBoxedFloatMap, MessageCollectionItemType.DOUBLE, MessageCollectionItemType.FLOAT))
                     return false;
 
                 writer.incrementState();
 
             case 21:
-                if (!writer.writeMap(((TestMapMessage)msg).messageBoxedDoubleMap, MessageCollectionItemType.MSG, MessageCollectionItemType.DOUBLE))
+                if (!writer.writeMap(msg.messageBoxedDoubleMap, MessageCollectionItemType.MSG, MessageCollectionItemType.DOUBLE))
                     return false;
 
                 writer.incrementState();
 
             case 22:
-                if (!writer.writeMap(((TestMapMessage)msg).integerGridLongListMap, MessageCollectionItemType.INT, MessageCollectionItemType.GRID_LONG_LIST))
+                if (!writer.writeMap(msg.integerGridLongListMap, MessageCollectionItemType.INT, MessageCollectionItemType.GRID_LONG_LIST))
                     return false;
 
                 writer.incrementState();
 
             case 23:
-                if (!writer.writeMap(((TestMapMessage)msg).gridLongListIntegerMap, MessageCollectionItemType.GRID_LONG_LIST, MessageCollectionItemType.INT))
+                if (!writer.writeMap(msg.gridLongListIntegerMap, MessageCollectionItemType.GRID_LONG_LIST, MessageCollectionItemType.INT))
                     return false;
 
                 writer.incrementState();
@@ -191,12 +188,10 @@ public class TestMapMessageSerializer implements MessageSerializer {
     }
 
     /** */
-    @Override public boolean readFrom(Message m, MessageReader reader) {
-        TestMapMessage msg = (TestMapMessage)m;
-
+    @Override public boolean readFrom(TestMapMessage msg, MessageReader reader) {
         switch (reader.state()) {
             case 0:
-                ((TestMapMessage)msg).booleanArrayBoxedLongMap = reader.readMap(MessageCollectionItemType.BOOLEAN_ARR, MessageCollectionItemType.LONG, false);
+                msg.booleanArrayBoxedLongMap = reader.readMap(MessageCollectionItemType.BOOLEAN_ARR, MessageCollectionItemType.LONG, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -204,7 +199,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 1:
-                ((TestMapMessage)msg).byteArrayBooleanArrayMap = reader.readMap(MessageCollectionItemType.BYTE_ARR, MessageCollectionItemType.BOOLEAN_ARR, false);
+                msg.byteArrayBooleanArrayMap = reader.readMap(MessageCollectionItemType.BYTE_ARR, MessageCollectionItemType.BOOLEAN_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -212,7 +207,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 2:
-                ((TestMapMessage)msg).shortArrayByteArrayMap = reader.readMap(MessageCollectionItemType.SHORT_ARR, MessageCollectionItemType.BYTE_ARR, false);
+                msg.shortArrayByteArrayMap = reader.readMap(MessageCollectionItemType.SHORT_ARR, MessageCollectionItemType.BYTE_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -220,7 +215,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 3:
-                ((TestMapMessage)msg).intArrayShortArrayMap = reader.readMap(MessageCollectionItemType.INT_ARR, MessageCollectionItemType.SHORT_ARR, false);
+                msg.intArrayShortArrayMap = reader.readMap(MessageCollectionItemType.INT_ARR, MessageCollectionItemType.SHORT_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -228,7 +223,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 4:
-                ((TestMapMessage)msg).longArrayIntArrayMap = reader.readMap(MessageCollectionItemType.LONG_ARR, MessageCollectionItemType.INT_ARR, false);
+                msg.longArrayIntArrayMap = reader.readMap(MessageCollectionItemType.LONG_ARR, MessageCollectionItemType.INT_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -236,7 +231,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 5:
-                ((TestMapMessage)msg).charArrayLongArrayMap = reader.readMap(MessageCollectionItemType.CHAR_ARR, MessageCollectionItemType.LONG_ARR, false);
+                msg.charArrayLongArrayMap = reader.readMap(MessageCollectionItemType.CHAR_ARR, MessageCollectionItemType.LONG_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -244,7 +239,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 6:
-                ((TestMapMessage)msg).floatArrayCharArrayMap = reader.readMap(MessageCollectionItemType.FLOAT_ARR, MessageCollectionItemType.CHAR_ARR, false);
+                msg.floatArrayCharArrayMap = reader.readMap(MessageCollectionItemType.FLOAT_ARR, MessageCollectionItemType.CHAR_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -252,7 +247,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 7:
-                ((TestMapMessage)msg).doubleArrayFloatArrayMap = reader.readMap(MessageCollectionItemType.DOUBLE_ARR, MessageCollectionItemType.FLOAT_ARR, false);
+                msg.doubleArrayFloatArrayMap = reader.readMap(MessageCollectionItemType.DOUBLE_ARR, MessageCollectionItemType.FLOAT_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -260,7 +255,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 8:
-                ((TestMapMessage)msg).stringDoubleArrayMap = reader.readMap(MessageCollectionItemType.STRING, MessageCollectionItemType.DOUBLE_ARR, false);
+                msg.stringDoubleArrayMap = reader.readMap(MessageCollectionItemType.STRING, MessageCollectionItemType.DOUBLE_ARR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -268,7 +263,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 9:
-                ((TestMapMessage)msg).uuidStringMap = reader.readMap(MessageCollectionItemType.UUID, MessageCollectionItemType.STRING, false);
+                msg.uuidStringMap = reader.readMap(MessageCollectionItemType.UUID, MessageCollectionItemType.STRING, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -276,7 +271,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 10:
-                ((TestMapMessage)msg).bitSetUuidMap = reader.readMap(MessageCollectionItemType.BIT_SET, MessageCollectionItemType.UUID, false);
+                msg.bitSetUuidMap = reader.readMap(MessageCollectionItemType.BIT_SET, MessageCollectionItemType.UUID, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -284,7 +279,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 11:
-                ((TestMapMessage)msg).igniteUuidBitSetMap = reader.readMap(MessageCollectionItemType.IGNITE_UUID, MessageCollectionItemType.BIT_SET, false);
+                msg.igniteUuidBitSetMap = reader.readMap(MessageCollectionItemType.IGNITE_UUID, MessageCollectionItemType.BIT_SET, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -292,7 +287,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 12:
-                ((TestMapMessage)msg).affTopVersionIgniteUuidMap = reader.readMap(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION, MessageCollectionItemType.IGNITE_UUID, false);
+                msg.affTopVersionIgniteUuidMap = reader.readMap(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION, MessageCollectionItemType.IGNITE_UUID, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -300,7 +295,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 13:
-                ((TestMapMessage)msg).boxedBooleanAffTopVersionMap = reader.readMap(MessageCollectionItemType.BOOLEAN, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION, false);
+                msg.boxedBooleanAffTopVersionMap = reader.readMap(MessageCollectionItemType.BOOLEAN, MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -308,7 +303,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 14:
-                ((TestMapMessage)msg).boxedByteBoxedBooleanMap = reader.readMap(MessageCollectionItemType.BYTE, MessageCollectionItemType.BOOLEAN, false);
+                msg.boxedByteBoxedBooleanMap = reader.readMap(MessageCollectionItemType.BYTE, MessageCollectionItemType.BOOLEAN, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -316,7 +311,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 15:
-                ((TestMapMessage)msg).boxedShortBoxedByteMap = reader.readMap(MessageCollectionItemType.SHORT, MessageCollectionItemType.BYTE, false);
+                msg.boxedShortBoxedByteMap = reader.readMap(MessageCollectionItemType.SHORT, MessageCollectionItemType.BYTE, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -324,7 +319,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 16:
-                ((TestMapMessage)msg).boxedIntBoxedShortMap = reader.readMap(MessageCollectionItemType.INT, MessageCollectionItemType.SHORT, false);
+                msg.boxedIntBoxedShortMap = reader.readMap(MessageCollectionItemType.INT, MessageCollectionItemType.SHORT, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -332,7 +327,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 17:
-                ((TestMapMessage)msg).boxedLongBoxedIntMap = reader.readMap(MessageCollectionItemType.LONG, MessageCollectionItemType.INT, false);
+                msg.boxedLongBoxedIntMap = reader.readMap(MessageCollectionItemType.LONG, MessageCollectionItemType.INT, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -340,7 +335,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 18:
-                ((TestMapMessage)msg).boxedCharBoxedLongMap = reader.readMap(MessageCollectionItemType.CHAR, MessageCollectionItemType.LONG, false);
+                msg.boxedCharBoxedLongMap = reader.readMap(MessageCollectionItemType.CHAR, MessageCollectionItemType.LONG, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -348,7 +343,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 19:
-                ((TestMapMessage)msg).boxedFloatBoxedCharMap = reader.readMap(MessageCollectionItemType.FLOAT, MessageCollectionItemType.CHAR, false);
+                msg.boxedFloatBoxedCharMap = reader.readMap(MessageCollectionItemType.FLOAT, MessageCollectionItemType.CHAR, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -356,7 +351,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 20:
-                ((TestMapMessage)msg).boxedDoubleBoxedFloatMap = reader.readMap(MessageCollectionItemType.DOUBLE, MessageCollectionItemType.FLOAT, false);
+                msg.boxedDoubleBoxedFloatMap = reader.readMap(MessageCollectionItemType.DOUBLE, MessageCollectionItemType.FLOAT, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -364,7 +359,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 21:
-                ((TestMapMessage)msg).messageBoxedDoubleMap = reader.readMap(MessageCollectionItemType.MSG, MessageCollectionItemType.DOUBLE, false);
+                msg.messageBoxedDoubleMap = reader.readMap(MessageCollectionItemType.MSG, MessageCollectionItemType.DOUBLE, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -372,7 +367,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 22:
-                ((TestMapMessage)msg).integerGridLongListMap = reader.readMap(MessageCollectionItemType.INT, MessageCollectionItemType.GRID_LONG_LIST, false);
+                msg.integerGridLongListMap = reader.readMap(MessageCollectionItemType.INT, MessageCollectionItemType.GRID_LONG_LIST, false);
 
                 if (!reader.isLastRead())
                     return false;
@@ -380,7 +375,7 @@ public class TestMapMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 23:
-                ((TestMapMessage)msg).gridLongListIntegerMap = reader.readMap(MessageCollectionItemType.GRID_LONG_LIST, MessageCollectionItemType.INT, false);
+                msg.gridLongListIntegerMap = reader.readMap(MessageCollectionItemType.GRID_LONG_LIST, MessageCollectionItemType.INT, false);
 
                 if (!reader.isLastRead())
                     return false;
diff --git a/modules/core/src/test/resources/codegen/TestMarshallableMessage.java b/modules/core/src/test/resources/codegen/TestMarshallableMessage.java
new file mode 100644
index 0000000000000..58a871692d3ac
--- /dev/null
+++ b/modules/core/src/test/resources/codegen/TestMarshallableMessage.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import java.util.BitSet;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.internal.util.GridLongList;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.plugin.extensions.communication.MarshallableMessage;
+
+public class TestMarshallableMessage implements MarshallableMessage {
+    @Order(0)
+    int iv;
+
+    @Order(1)
+    String sv;
+
+    Object cstData;
+
+    @Order(2)
+    byte[] cstDataBytes;
+
+    /** {@inheritDoc} */
+    @Override public void prepareMarshal(Marshaller marsh) {
+        if (cstData != null && cstDataBytes == null) {
+            try {
+                cstDataBytes = U.marshal(marsh, cstData);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Failed to marshal custom data.", e);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) {
+        if (cstDataBytes != null && cstData == null) {
+            try {
+                cstData = U.unmarshal(marsh, cstDataBytes, clsLdr);
+
+                cstDataBytes = null;
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException("Failed to unmarshal custom data.", e);
+            }
+        }
+    }
+
+    public short directType() {
+        return 0;
+    }
+}
diff --git a/modules/core/src/test/resources/codegen/TestMarshallableMessageMarshallableSerializer.java b/modules/core/src/test/resources/codegen/TestMarshallableMessageMarshallableSerializer.java
new file mode 100644
index 0000000000000..365ec8b80bf7e
--- /dev/null
+++ b/modules/core/src/test/resources/codegen/TestMarshallableMessageMarshallableSerializer.java
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+import org.apache.ignite.internal.TestMarshallableMessage;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.plugin.extensions.communication.MessageReader;
+import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
+import org.apache.ignite.plugin.extensions.communication.MessageWriter;
+
+/**
+ * This class is generated automatically.
+ *
+ * @see org.apache.ignite.internal.MessageProcessor
+ */
+public class TestMarshallableMessageMarshallableSerializer implements MessageSerializer {
+    /** */
+    private final ClassLoader clsLdr;
+    /** */
+    private final Marshaller marshaller;
+
+    /** */
+    public TestMarshallableMessageMarshallableSerializer(Marshaller marshaller, ClassLoader clsLdr) {
+        this.marshaller = marshaller;
+        this.clsLdr = clsLdr;
+    }
+    /** */
+    @Override public boolean writeTo(TestMarshallableMessage msg, MessageWriter writer) {
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(msg.directType()))
+                return false;
+
+            msg.prepareMarshal(marshaller);
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 0:
+                if (!writer.writeInt(msg.iv))
+                    return false;
+
+                writer.incrementState();
+
+            case 1:
+                if (!writer.writeString(msg.sv))
+                    return false;
+
+                writer.incrementState();
+
+            case 2:
+                if (!writer.writeByteArray(msg.cstDataBytes))
+                    return false;
+
+                writer.incrementState();
+        }
+
+        return true;
+    }
+
+    /** */
+    @Override public boolean readFrom(TestMarshallableMessage msg, MessageReader reader) {
+        switch (reader.state()) {
+            case 0:
+                msg.iv = reader.readInt();
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 1:
+                msg.sv = reader.readString();
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+
+            case 2:
+                msg.cstDataBytes = reader.readByteArray();
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+        }
+
+        msg.finishUnmarshal(marshaller, clsLdr);
+
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/modules/core/src/test/resources/codegen/TestMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMessageSerializer.java
index 10a7eb4a8a884..f14de0fc03b25 100644
--- a/modules/core/src/test/resources/codegen/TestMessageSerializer.java
+++ b/modules/core/src/test/resources/codegen/TestMessageSerializer.java
@@ -19,7 +19,6 @@
 
 import org.apache.ignite.internal.TestMessage;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
-import org.apache.ignite.plugin.extensions.communication.Message;
 import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType;
 import org.apache.ignite.plugin.extensions.communication.MessageReader;
 import org.apache.ignite.plugin.extensions.communication.MessageSerializer;
@@ -30,11 +29,9 @@
  *
  * @see org.apache.ignite.internal.MessageProcessor
  */
-public class TestMessageSerializer implements MessageSerializer {
+public class TestMessageSerializer implements MessageSerializer {
     /** */
-    @Override public boolean writeTo(Message m, MessageWriter writer) {
-        TestMessage msg = (TestMessage)m;
-
+    @Override public boolean writeTo(TestMessage msg, MessageWriter writer) {
         if (!writer.isHeaderWritten()) {
             if (!writer.writeHeader(msg.directType()))
                 return false;
@@ -44,67 +41,67 @@ public class TestMessageSerializer implements MessageSerializer {
 
         switch (writer.state()) {
             case 0:
-                if (!writer.writeInt(((TestMessage)msg).id))
+                if (!writer.writeInt(msg.id))
                     return false;
 
                 writer.incrementState();
 
             case 1:
-                if (!writer.writeByteArray(((TestMessage)msg).byteArr))
+                if (!writer.writeByteArray(msg.byteArr))
                     return false;
 
                 writer.incrementState();
 
             case 2:
-                if (!writer.writeString(((TestMessage)msg).str))
+                if (!writer.writeString(msg.str))
                     return false;
 
                 writer.incrementState();
 
             case 3:
-                if (!writer.writeObjectArray(((TestMessage)msg).strArr, MessageCollectionItemType.STRING))
+                if (!writer.writeObjectArray(msg.strArr, MessageCollectionItemType.STRING))
                     return false;
 
                 writer.incrementState();
 
             case 4:
-                if (!writer.writeObjectArray(((TestMessage)msg).intMatrix, MessageCollectionItemType.INT_ARR))
+                if (!writer.writeObjectArray(msg.intMatrix, MessageCollectionItemType.INT_ARR))
                     return false;
 
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeMessage(((TestMessage)msg).ver))
+                if (!writer.writeMessage(msg.ver))
                     return false;
 
                 writer.incrementState();
 
             case 6:
-                if (!writer.writeObjectArray(((TestMessage)msg).verArr, MessageCollectionItemType.MSG))
+                if (!writer.writeObjectArray(msg.verArr, MessageCollectionItemType.MSG))
                     return false;
 
                 writer.incrementState();
 
             case 7:
-                if (!writer.writeUuid(((TestMessage)msg).uuid))
+                if (!writer.writeUuid(msg.uuid))
                     return false;
 
                 writer.incrementState();
 
             case 8:
-                if (!writer.writeIgniteUuid(((TestMessage)msg).ignUuid))
+                if (!writer.writeIgniteUuid(msg.ignUuid))
                     return false;
 
                 writer.incrementState();
 
             case 9:
-                if (!writer.writeAffinityTopologyVersion(((TestMessage)msg).topVer))
+                if (!writer.writeAffinityTopologyVersion(msg.topVer))
                     return false;
 
                 writer.incrementState();
 
             case 10:
-                if (!writer.writeBitSet(((TestMessage)msg).bitSet))
+                if (!writer.writeBitSet(msg.bitSet))
                     return false;
 
                 writer.incrementState();
@@ -116,19 +113,19 @@ public class TestMessageSerializer implements MessageSerializer {
                 writer.incrementState();
 
             case 12:
-                if (!writer.writeKeyCacheObject(((TestMessage)msg).keyCacheObject))
+                if (!writer.writeKeyCacheObject(msg.keyCacheObject))
                     return false;
 
                 writer.incrementState();
 
             case 13:
-                if (!writer.writeCacheObject(((TestMessage)msg).cacheObject))
+                if (!writer.writeCacheObject(msg.cacheObject))
                     return false;
 
                 writer.incrementState();
 
             case 14:
-                if (!writer.writeGridLongList(((TestMessage)msg).gridLongList))
+                if (!writer.writeGridLongList(msg.gridLongList))
                     return false;
 
                 writer.incrementState();
@@ -138,12 +135,10 @@ public class TestMessageSerializer implements MessageSerializer {
     }
 
     /** */
-    @Override public boolean readFrom(Message m, MessageReader reader) {
-        TestMessage msg = (TestMessage)m;
-
+    @Override public boolean readFrom(TestMessage msg, MessageReader reader) {
         switch (reader.state()) {
             case 0:
-                ((TestMessage)msg).id = reader.readInt();
+                msg.id = reader.readInt();
 
                 if (!reader.isLastRead())
                     return false;
@@ -151,7 +146,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 1:
-                ((TestMessage)msg).byteArr = reader.readByteArray();
+                msg.byteArr = reader.readByteArray();
 
                 if (!reader.isLastRead())
                     return false;
@@ -159,7 +154,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 2:
-                ((TestMessage)msg).str = reader.readString();
+                msg.str = reader.readString();
 
                 if (!reader.isLastRead())
                     return false;
@@ -167,7 +162,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 3:
-                ((TestMessage)msg).strArr = reader.readObjectArray(MessageCollectionItemType.STRING, String.class);
+                msg.strArr = reader.readObjectArray(MessageCollectionItemType.STRING, String.class);
 
                 if (!reader.isLastRead())
                     return false;
@@ -175,7 +170,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 4:
-                ((TestMessage)msg).intMatrix = reader.readObjectArray(MessageCollectionItemType.INT, int[].class);
+                msg.intMatrix = reader.readObjectArray(MessageCollectionItemType.INT, int[].class);
 
                 if (!reader.isLastRead())
                     return false;
@@ -183,7 +178,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 5:
-                ((TestMessage)msg).ver = reader.readMessage();
+                msg.ver = reader.readMessage();
 
                 if (!reader.isLastRead())
                     return false;
@@ -191,7 +186,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 6:
-                ((TestMessage)msg).verArr = reader.readObjectArray(MessageCollectionItemType.MSG, GridCacheVersion.class);
+                msg.verArr = reader.readObjectArray(MessageCollectionItemType.MSG, GridCacheVersion.class);
 
                 if (!reader.isLastRead())
                     return false;
@@ -199,7 +194,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 7:
-                ((TestMessage)msg).uuid = reader.readUuid();
+                msg.uuid = reader.readUuid();
 
                 if (!reader.isLastRead())
                     return false;
@@ -207,7 +202,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 8:
-                ((TestMessage)msg).ignUuid = reader.readIgniteUuid();
+                msg.ignUuid = reader.readIgniteUuid();
 
                 if (!reader.isLastRead())
                     return false;
@@ -215,7 +210,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 9:
-                ((TestMessage)msg).topVer = reader.readAffinityTopologyVersion();
+                msg.topVer = reader.readAffinityTopologyVersion();
 
                 if (!reader.isLastRead())
                     return false;
@@ -223,7 +218,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 10:
-                ((TestMessage)msg).bitSet = reader.readBitSet();
+                msg.bitSet = reader.readBitSet();
 
                 if (!reader.isLastRead())
                     return false;
@@ -239,7 +234,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 12:
-                ((TestMessage)msg).keyCacheObject = reader.readKeyCacheObject();
+                msg.keyCacheObject = reader.readKeyCacheObject();
 
                 if (!reader.isLastRead())
                     return false;
@@ -247,7 +242,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 13:
-                ((TestMessage)msg).cacheObject = reader.readCacheObject();
+                msg.cacheObject = reader.readCacheObject();
 
                 if (!reader.isLastRead())
                     return false;
@@ -255,7 +250,7 @@ public class TestMessageSerializer implements MessageSerializer {
                 reader.incrementState();
 
             case 14:
-                ((TestMessage)msg).gridLongList = reader.readGridLongList();
+                msg.gridLongList = reader.readGridLongList();
 
                 if (!reader.isLastRead())
                     return false;