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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3209af44754 IGNITE-28938 Split MarshallableMessage: a message with a 
custom wire form needs no marshaller (#13427)
3209af44754 is described below

commit 3209af447549c029a9f7eae390187accc80034e9
Author: Anton Vinogradov <[email protected]>
AuthorDate: Wed Aug 5 19:29:54 2026 +0300

    IGNITE-28938 Split MarshallableMessage: a message with a custom wire form 
needs no marshaller (#13427)
---
 .../calcite/message/CalciteMessageFactory.java     |  4 +-
 .../query/calcite/metadata/ColocationGroup.java    | 10 ++--
 .../internal/MessageMarshallerGenerator.java       | 15 +++++
 .../apache/ignite/internal/MessageProcessor.java   | 11 +++-
 .../ignite/internal/CoreMessagesProvider.java      |  4 +-
 .../org/apache/ignite/internal/IgniteKernal.java   |  8 +--
 .../ignite/internal/SelfMarshallingMessage.java    | 38 ++++++++++++
 .../communication/IgniteMessageFactoryImpl.java    |  5 +-
 .../communication/MessageUnmarshalOnceCheck.java   |  7 ++-
 ...er.java => AbstractMessageFactoryProvider.java} | 21 ++++---
 .../processors/cache/GridCacheEntryInfo.java       | 13 ++--
 .../preloader/GridDhtPartitionsFullMessage.java    | 10 ++--
 .../preloader/GridDhtPartitionsSingleMessage.java  | 10 ++--
 .../distributed/near/GridNearTxPrepareRequest.java |  9 ++-
 .../discovery/tcp/internal/TcpDiscoveryNode.java   | 10 ++--
 .../internal/codegen/MessageProcessorTest.java     | 33 +++++++++-
 ...MessageFactoryMarshallerInitializationTest.java |  4 +-
 .../tcp/DiscoveryUnmarshalVulnerabilityTest.java   |  4 +-
 .../codegen/TestSelfMarshallingMessage.java        | 37 ++++++++++++
 .../TestSelfMarshallingMessageMarshaller.java      | 41 +++++++++++++
 .../TestSelfMarshallingMessageSerializer.java      | 70 ++++++++++++++++++++++
 .../codegen/WrongSelfMarshallingMessage.java       | 37 ++++++++++++
 .../discovery/zk/internal/ZkMessageFactory.java    |  4 +-
 23 files changed, 336 insertions(+), 69 deletions(-)

diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java
index dafc92a558b..4978f0717bf 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java
@@ -18,7 +18,7 @@
 package org.apache.ignite.internal.processors.query.calcite.message;
 
 import org.apache.ignite.internal.managers.communication.IgniteMessageFactory;
-import 
org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider;
+import org.apache.ignite.internal.plugin.AbstractMessageFactoryProvider;
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup;
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription;
 import 
org.apache.ignite.internal.processors.query.calcite.metadata.FragmentMapping;
@@ -27,7 +27,7 @@ import 
org.apache.ignite.plugin.extensions.communication.Message;
 /**
  * Message factory.
  */
-public class CalciteMessageFactory extends 
AbstractMarshallableMessageFactoryProvider {
+public class CalciteMessageFactory extends AbstractMessageFactoryProvider {
     /** */
     public static final short MIN_MESSAGE_TYPE = 300;
 
diff --git 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java
 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java
index e0b4738bced..336e2210664 100644
--- 
a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java
+++ 
b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java
@@ -29,19 +29,17 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.LongStream;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
 import org.apache.ignite.internal.processors.query.calcite.util.Commons;
 import org.apache.ignite.internal.util.GridIntIterator;
 import org.apache.ignite.internal.util.GridIntList;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.marshaller.Marshaller;
 
 /** */
-public class ColocationGroup implements MarshallableMessage {
+public class ColocationGroup implements SelfMarshallingMessage {
     /** */
     @Order(0)
     long[] srcIds;
@@ -314,7 +312,7 @@ public class ColocationGroup implements MarshallableMessage 
{
     }
 
     /** {@inheritDoc} */
-    @Override public void marshal(Marshaller marsh) throws 
IgniteCheckedException {
+    @Override public void selfMarshal() {
         if (!F.isEmpty(marshalledAssignments) || assignments == null || 
primaryAssignment)
             return;
 
@@ -343,7 +341,7 @@ public class ColocationGroup implements MarshallableMessage 
{
     }
 
     /** {@inheritDoc} */
-    @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) 
throws IgniteCheckedException {
+    @Override public void selfUnmarshal() {
         if (F.isEmpty(marshalledAssignments))
             return;
 
diff --git 
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java
 
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java
index ab2ebef2280..34e60541417 100644
--- 
a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java
+++ 
b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java
@@ -51,6 +51,7 @@ import static 
org.apache.ignite.internal.MessageProcessor.KEY_CACHE_OBJECT_CLS;
 import static 
org.apache.ignite.internal.MessageProcessor.MARSHALLABLE_MESSAGE_INTERFACE;
 import static org.apache.ignite.internal.MessageProcessor.MESSAGE_INTERFACE;
 import static 
org.apache.ignite.internal.MessageProcessor.NON_MARSHALLABLE_MESSAGE_INTERFACE;
+import static 
org.apache.ignite.internal.MessageProcessor.SELF_MARSHALLING_MESSAGE_INTERFACE;
 
 /**
  * Generates {@code *Marshaller} classes for {@code Message} types that are 
not {@code NonMarshallableMessage}.
@@ -95,6 +96,9 @@ public class MessageMarshallerGenerator extends 
MessageCompanionGenerator {
     /** */
     private final TypeMirror nonMarshallableType;
 
+    /** */
+    private final TypeMirror selfMarshallingMsgType;
+
     /** */
     private final TypeMirror cacheGrpIdMsgType;
 
@@ -107,6 +111,9 @@ public class MessageMarshallerGenerator extends 
MessageCompanionGenerator {
     /** */
     private boolean marshallable;
 
+    /** Whether the message marshals fields of its own, so the generated 
methods call its step. */
+    private boolean selfMarshalling;
+
     /** */
     private boolean hasMarshalled;
 
@@ -133,6 +140,7 @@ public class MessageMarshallerGenerator extends 
MessageCompanionGenerator {
         msgType = type(MESSAGE_INTERFACE);
         cacheObjType = type(CACHE_OBJECT_CLS);
         nonMarshallableType = type(NON_MARSHALLABLE_MESSAGE_INTERFACE);
+        selfMarshallingMsgType = type(SELF_MARSHALLING_MESSAGE_INTERFACE);
         cacheGrpIdMsgType = type(GRID_CACHE_GROUP_ID_MESSAGE_CLS);
         mapType = type(Map.class.getName());
         colType = type(Collection.class.getName());
@@ -160,6 +168,7 @@ public class MessageMarshallerGenerator extends 
MessageCompanionGenerator {
         }
 
         marshallable = marshallableMsgType != null && 
assignableFrom(type.asType(), marshallableMsgType);
+        selfMarshalling = selfMarshallingMsgType != null && 
assignableFrom(type.asType(), selfMarshallingMsgType);
         hasMarshalled = kinds.values().stream().anyMatch(k -> k == 
MarshalledKind.BLOB || k == MarshalledKind.ELEMENT_BLOBS);
 
         generateMarshalMethod(fields);
@@ -233,6 +242,9 @@ public class MessageMarshallerGenerator extends 
MessageCompanionGenerator {
             if (needsCtx(orderedFields))
                 appendBlock(body, List.of(ctxResolutionLine()));
 
+            if (selfMarshalling)
+                appendBlock(body, List.of(indentedLine("msg.selfMarshal();")));
+
             appendMarshalledFieldsPrepare(body);
             appendMarshalledPrepare(body);
 
@@ -305,6 +317,9 @@ public class MessageMarshallerGenerator extends 
MessageCompanionGenerator {
             appendMarshalledMapFinish(body);
             appendMarshalledElementBlobsFinish(body);
 
+            if (selfMarshalling)
+                appendBlock(body, 
List.of(indentedLine("msg.selfUnmarshal();")));
+
             prependMsgFactoryResolution(body);
         });
     }
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 23e110b1eb4..4886bb491e4 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
@@ -84,6 +84,9 @@ public class MessageProcessor extends AbstractProcessor {
     /** Externalizable message. */
     static final String MARSHALLABLE_MESSAGE_INTERFACE = 
"org.apache.ignite.internal.MarshallableMessage";
 
+    /** Message that reshapes its own fields before they go on the wire. */
+    static final String SELF_MARSHALLING_MESSAGE_INTERFACE = 
"org.apache.ignite.internal.SelfMarshallingMessage";
+
     /** Marker of messages with no marshaller. */
     static final String NON_MARSHALLABLE_MESSAGE_INTERFACE = 
"org.apache.ignite.plugin.extensions.communication.NonMarshallableMessage";
 
@@ -141,6 +144,7 @@ public class MessageProcessor extends AbstractProcessor {
 
         TypeElement marshallableEl = 
processingEnv.getElementUtils().getTypeElement(MARSHALLABLE_MESSAGE_INTERFACE);
         TypeElement nonMarshallableEl = 
processingEnv.getElementUtils().getTypeElement(NON_MARSHALLABLE_MESSAGE_INTERFACE);
+        TypeElement selfMarshallingEl = 
processingEnv.getElementUtils().getTypeElement(SELF_MARSHALLING_MESSAGE_INTERFACE);
 
         Map<TypeElement, List<VariableElement>> msgFields = new HashMap<>();
 
@@ -155,9 +159,12 @@ public class MessageProcessor extends AbstractProcessor {
 
             // No marshaller is generated for a NonMarshallableMessage, so 
declared marshalling logic would silently never run.
             if (nonMarshallableEl != null && 
isAssignable(nonMarshallableEl.asType(), clazz)
-                && ((marshallableEl != null && 
isAssignable(marshallableEl.asType(), clazz)) || hasMarshalledFields(clazz))) {
+                && ((marshallableEl != null && 
isAssignable(marshallableEl.asType(), clazz))
+                    || (selfMarshallingEl != null && 
isAssignable(selfMarshallingEl.asType(), clazz))
+                    || hasMarshalledFields(clazz))) {
                 processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
-                    "NonMarshallableMessage must not implement 
MarshallableMessage or declare @Marshalled fields", clazz);
+                    "NonMarshallableMessage must not implement 
MarshallableMessage or SelfMarshallingMessage, " +
+                        "nor declare @Marshalled fields", clazz);
             }
 
             if (clazz.getModifiers().contains(Modifier.ABSTRACT))
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
index d95dbd5c207..9412a9ab9fa 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java
@@ -44,7 +44,7 @@ import 
org.apache.ignite.internal.managers.encryption.NodeEncryptionKeys;
 import org.apache.ignite.internal.managers.eventstorage.EventsDataBagItem;
 import 
org.apache.ignite.internal.managers.eventstorage.GridEventStorageRequest;
 import 
org.apache.ignite.internal.managers.eventstorage.GridEventStorageResponse;
-import 
org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider;
+import org.apache.ignite.internal.plugin.AbstractMessageFactoryProvider;
 import 
org.apache.ignite.internal.processors.authentication.AuthentificationDataBagItem;
 import org.apache.ignite.internal.processors.authentication.User;
 import 
org.apache.ignite.internal.processors.authentication.UserAcceptedMessage;
@@ -323,7 +323,7 @@ import 
org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryStatusCheckMessa
 import org.jetbrains.annotations.Nullable;
 
 /** */
-public class CoreMessagesProvider extends 
AbstractMarshallableMessageFactoryProvider {
+public class CoreMessagesProvider extends AbstractMessageFactoryProvider {
     /** Node ID message type. */
     public static final short NODE_ID_MSG_TYPE = 11500;
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java 
b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 1330973d8c1..db961ddbae9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -110,7 +110,7 @@ import 
org.apache.ignite.internal.managers.indexing.GridIndexingManager;
 import 
org.apache.ignite.internal.managers.loadbalancer.GridLoadBalancerManager;
 import org.apache.ignite.internal.managers.systemview.GridSystemViewManager;
 import 
org.apache.ignite.internal.managers.systemview.IgniteConfigurationIterable;
-import 
org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider;
+import org.apache.ignite.internal.plugin.AbstractMessageFactoryProvider;
 import org.apache.ignite.internal.plugin.IgniteLogInfoProvider;
 import org.apache.ignite.internal.plugin.IgniteLogInfoProviderImpl;
 import org.apache.ignite.internal.processors.GridProcessor;
@@ -1339,13 +1339,13 @@ public class IgniteKernal implements IgniteEx, 
Externalizable {
     }
 
     /**
-     * Re-init {@link AbstractMarshallableMessageFactoryProvider} with a 
proper marshaller.
+     * Re-init {@link AbstractMessageFactoryProvider} with a proper marshaller.
      *
      * @param factoryProvider Message factory provider.
      */
     private void initProvider(MessageFactoryProvider factoryProvider) {
-        if (factoryProvider instanceof 
AbstractMarshallableMessageFactoryProvider) {
-            
((AbstractMarshallableMessageFactoryProvider)factoryProvider).init(ctx.marshallerContext().jdkMarshaller(),
+        if (factoryProvider instanceof AbstractMessageFactoryProvider) {
+            
((AbstractMessageFactoryProvider)factoryProvider).init(ctx.marshallerContext().jdkMarshaller(),
                 ctx.marshaller());
         }
     }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/SelfMarshallingMessage.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/SelfMarshallingMessage.java
new file mode 100644
index 00000000000..3f3eb87844d
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/SelfMarshallingMessage.java
@@ -0,0 +1,38 @@
+/*
+ * 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.plugin.extensions.communication.Message;
+
+/**
+ * A {@link Message} that reshapes its own fields before they go on the wire 
and back after they arrive: copying a
+ * value into the field that is actually sent, packing bits, recalculating a 
TTL. A message needing a
+ * {@code Marshaller} for that implements {@code MarshallableMessage} instead; 
here there is none to use.
+ *
+ * @deprecated A message carries data, it is not a place to compute. Each use 
of this interface is a message doing
+ * work that belongs to the code building or reading it, so treat the current 
ones as debt and add no new ones: do the
+ * conversion where the message is filled in and where it is consumed.
+ */
+@Deprecated
+public interface SelfMarshallingMessage extends Message {
+    /** Called before anything else is marshalled, so a field this step fills 
still goes on the wire. */
+    public void selfMarshal();
+
+    /** Called after everything else is unmarshalled, so this step sees the 
fields already read back. */
+    public void selfUnmarshal();
+}
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java
index a44bbf2706e..26fc5435315 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.managers.communication;
 import java.lang.reflect.Array;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.MarshallableMessage;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.processors.cache.DeployableMessage;
 import org.apache.ignite.internal.processors.cache.GridCacheMessage;
 import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer;
@@ -92,8 +93,8 @@ public class IgniteMessageFactoryImpl<M extends Message, CM 
extends GridCacheMes
         try {
             Message msg = serializer.createMessage();
 
-            if (marshaller == null && msg instanceof MarshallableMessage) {
-                throw new IgniteException("Failed to register a message: it 
implements MarshallableMessage but no" +
+            if (marshaller == null && (msg instanceof MarshallableMessage || 
msg instanceof SelfMarshallingMessage)) {
+                throw new IgniteException("Failed to register a message: it 
marshals fields of its own but no" +
                     " marshaller is provided [directType=" + directType +
                     ", cls=" + msg.getClass().getName() + ']');
             }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java
index aa2e48289a7..f411d2d6ccd 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.internal.MarshallableMessage;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.plugin.extensions.communication.Message;
 
 /**
@@ -53,11 +54,11 @@ public class MessageUnmarshalOnceCheck {
      * @param msg Message about to be finish-unmarshalled.
      * @param cacheMode {@code true} for the cache-aware pass, {@code false} 
for the cache-free pass; the two passes
      * over one message are legitimate and tracked separately, so only a 
repeat of the same pass is reported.
-     * @return {@code true} if {@code msg} is not a {@link 
MarshallableMessage} or is finish-unmarshalled the first
-     * time in this pass.
+     * @return {@code true} if {@code msg} marshals no field of its own, or is 
finish-unmarshalled the first time in
+     * this pass.
      */
     public static boolean firstUnmarshal(Message msg, boolean cacheMode) {
-        if (!(msg instanceof MarshallableMessage))
+        if (!(msg instanceof MarshallableMessage) && !(msg instanceof 
SelfMarshallingMessage))
             return true;
 
         // Static set: evict entries whose message was already collected, so 
it doesn't grow across the suite.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMessageFactoryProvider.java
similarity index 90%
rename from 
modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java
rename to 
modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMessageFactoryProvider.java
index 083be41b16d..44b21069ae0 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMessageFactoryProvider.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.plugin;
 import java.lang.reflect.Constructor;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.MarshallableMessage;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.UseBinaryMarshaller;
 import org.apache.ignite.internal.binary.BinaryMarshaller;
 import org.apache.ignite.internal.managers.communication.IgniteMessageFactory;
@@ -38,7 +39,7 @@ import org.jetbrains.annotations.Nullable;
  * An extension of {@link MessageFactoryProvider} allowing to use provided 
schema-aware marshaller
  * to register {@link MarshallableMessage}.
  */
-public abstract class AbstractMarshallableMessageFactoryProvider implements 
MessageFactoryProvider {
+public abstract class AbstractMessageFactoryProvider implements 
MessageFactoryProvider {
     /** Generated-companion constructors per message class, including cached 
negative lookups. */
     private static final ClassValue<Companions> COMPANIONS = new 
ClassValue<>() {
         @Override protected Companions computeValue(Class<?> cls) {
@@ -74,18 +75,20 @@ public abstract class 
AbstractMarshallableMessageFactoryProvider implements Mess
 
         MessageSerializer<T> serializer = loadGenerated(cls, "Serializer", 
null, true);
 
-        // A MarshallableMessage always gets a generated marshaller (the hook 
call alone is a statement), so its
-        // absence is a build problem. For the rest the generator skips 
statement-free marshallers, so absence
-        // legitimately means "nothing to marshal"; the message and its 
companions ship in the same jar, hence
-        // a missing class cannot be a packaging accident that spares the 
(required) serializer.
+        // A message that marshals a part of its fields itself always gets a 
generated marshaller (its own call alone
+        // is a statement), so its absence is a build problem. For the rest 
the generator skips statement-free
+        // marshallers, so absence legitimately means "nothing to marshal"; 
the message and its companions ship in the
+        // same jar, hence a missing class cannot be a packaging accident that 
spares the (required) serializer.
         MessageMarshaller<T> marshaller;
 
         if (NonMarshallableMessage.class.isAssignableFrom(cls))
             marshaller = null;
-        else if (MarshallableMessage.class.isAssignableFrom(cls))
-            marshaller = loadGenerated(cls, "Marshaller", marsh, true);
-        else
-            marshaller = loadGenerated(cls, "Marshaller", marsh, false);
+        else {
+            boolean required = MarshallableMessage.class.isAssignableFrom(cls)
+                || SelfMarshallingMessage.class.isAssignableFrom(cls);
+
+            marshaller = loadGenerated(cls, "Marshaller", marsh, required);
+        }
 
         // Deployers are generated for GridCacheMessage subclasses only, so 
the class lookup is skipped for the rest;
         // a DeployableMessage left without a deployer is then rejected at 
registration.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
index 3d5c2fe4d5a..90012c72bda 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
@@ -18,21 +18,18 @@
 package org.apache.ignite.internal.processors.cache;
 
 import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Order;
-import org.apache.ignite.internal.UseBinaryMarshaller;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 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.CacheIdAware;
 
 /**
  * Entry information that gets passed over wire.
  */
-@UseBinaryMarshaller
-public class GridCacheEntryInfo implements MarshallableMessage, CacheIdAware {
+public class GridCacheEntryInfo implements SelfMarshallingMessage, 
CacheIdAware {
     /** */
     private static final int SIZE_OVERHEAD = 3 * 8 /* reference */ + 4 /* int 
*/ + 2 * 8 /* long */ + 32 /* version */;
 
@@ -193,9 +190,9 @@ public class GridCacheEntryInfo implements 
MarshallableMessage, CacheIdAware {
         return SIZE_OVERHEAD + size;
     }
 
-    // TODO IGNITE-28920: move the expireTime rebase out of the marshalling 
hooks.
+    // TODO IGNITE-28920: the rebase still runs inside the message; move it to 
the code filling and reading the entry.
     /** {@inheritDoc} */
-    @Override public void marshal(Marshaller marsh) throws 
IgniteCheckedException {
+    @Override public void selfMarshal() {
         if (expireTime == 0)
             expireTime = -1;
         else {
@@ -207,7 +204,7 @@ public class GridCacheEntryInfo implements 
MarshallableMessage, CacheIdAware {
     }
 
     /** {@inheritDoc} */
-    @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) 
throws IgniteCheckedException {
+    @Override public void selfUnmarshal() {
         long remaining = expireTime;
 
         expireTime = remaining < 0 ? 0 : U.currentTimeMillis() + remaining;
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
index 0f80b015b48..b01ab9d81b6 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
@@ -25,11 +25,10 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.Compress;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.managers.communication.ErrorMessage;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
@@ -40,7 +39,6 @@ import 
org.apache.ignite.internal.util.tostring.GridToStringExclude;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.marshaller.Marshaller;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -49,7 +47,7 @@ import org.jetbrains.annotations.Nullable;
  * GridDhtPartitionsSingleMessage}s were received. <br> May be also compacted 
as part of {@link
  * CacheAffinityChangeMessage} for node left or failed case.<br>
  */
-public class GridDhtPartitionsFullMessage extends 
GridDhtPartitionsAbstractMessage implements MarshallableMessage {
+public class GridDhtPartitionsFullMessage extends 
GridDhtPartitionsAbstractMessage implements SelfMarshallingMessage {
     /** */
     private static final byte REBALANCED_FLAG_MASK = 0x01;
 
@@ -388,7 +386,7 @@ public class GridDhtPartitionsFullMessage extends 
GridDhtPartitionsAbstractMessa
     }
 
     /** {@inheritDoc} */
-    @Override public void marshal(Marshaller marsh) throws 
IgniteCheckedException {
+    @Override public void selfMarshal() {
         if (!F.isEmpty(parts) && locParts == null)
             locParts = copyPartitionsMap(parts);
     }
@@ -408,7 +406,7 @@ public class GridDhtPartitionsFullMessage extends 
GridDhtPartitionsAbstractMessa
     }
 
     /** {@inheritDoc} */
-    @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) 
throws IgniteCheckedException {
+    @Override public void selfUnmarshal() {
         if (locParts != null && parts == null) {
             parts = copyPartitionsMap(locParts);
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java
index d2df0a081d0..e003492c58c 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java
@@ -21,17 +21,15 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.Compress;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.managers.communication.ErrorMessage;
 import 
org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.util.tostring.GridToStringInclude;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.S;
-import org.apache.ignite.marshaller.Marshaller;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -39,7 +37,7 @@ import org.jetbrains.annotations.Nullable;
  *
  * Sent in response to {@link GridDhtPartitionsSingleRequest} and during 
processing partitions exchange future.
  */
-public class GridDhtPartitionsSingleMessage extends 
GridDhtPartitionsAbstractMessage implements MarshallableMessage {
+public class GridDhtPartitionsSingleMessage extends 
GridDhtPartitionsAbstractMessage implements SelfMarshallingMessage {
     /** Local partitions. */
     @Order(0)
     @Compress
@@ -292,12 +290,12 @@ public class GridDhtPartitionsSingleMessage extends 
GridDhtPartitionsAbstractMes
     }
 
     /** {@inheritDoc} */
-    @Override public void marshal(Marshaller marsh) throws 
IgniteCheckedException {
+    @Override public void selfMarshal() {
         // No-op.
     }
 
     /** {@inheritDoc} */
-    @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) 
throws IgniteCheckedException {
+    @Override public void selfUnmarshal() {
         if (dupPartsData != null) {
             assert parts != null;
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
index 3860c4cd009..fc5074f8941 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
@@ -22,8 +22,8 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 import java.util.UUID;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import 
org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxPrepareRequest;
@@ -34,13 +34,12 @@ 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.lang.IgniteUuid;
-import org.apache.ignite.marshaller.Marshaller;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Near transaction prepare request to primary node. 'Near' means 'Initiating 
node' here, not 'Near Cache'.
  */
-public class GridNearTxPrepareRequest extends GridDistributedTxPrepareRequest 
implements MarshallableMessage {
+public class GridNearTxPrepareRequest extends GridDistributedTxPrepareRequest 
implements SelfMarshallingMessage {
     /** */
     private static final int NEAR_FLAG_MASK = 0x01;
 
@@ -294,7 +293,7 @@ public class GridNearTxPrepareRequest extends 
GridDistributedTxPrepareRequest im
     }
 
     /** {@inheritDoc} */
-    @Override public void marshal(Marshaller marsh) {
+    @Override public void selfMarshal() {
         // Of all tx messages, only the near prepare request transfers entry 
expiry policies.
         if (writes() != null) {
             for (IgniteTxEntry e : writes())
@@ -308,7 +307,7 @@ public class GridNearTxPrepareRequest extends 
GridDistributedTxPrepareRequest im
     }
 
     /** {@inheritDoc} */
-    @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) {
+    @Override public void selfUnmarshal() {
         // No-op.
     }
 
diff --git 
a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
 
b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
index 46f0fe8684a..7c7f795b918 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
@@ -30,15 +30,14 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cache.CacheMetrics;
 import org.apache.ignite.cluster.ClusterMetrics;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.ClusterMetricsSnapshot;
 import org.apache.ignite.internal.IgniteNodeAttributes;
-import org.apache.ignite.internal.MarshallableMessage;
 import org.apache.ignite.internal.Marshalled;
 import org.apache.ignite.internal.Order;
+import org.apache.ignite.internal.SelfMarshallingMessage;
 import org.apache.ignite.internal.managers.discovery.IgniteClusterNode;
 import org.apache.ignite.internal.processors.cluster.NodeMetricsMessage;
 import org.apache.ignite.internal.util.lang.GridMetadataAwareAdapter;
@@ -49,7 +48,6 @@ import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.lang.IgniteProductVersion;
-import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.spi.discovery.DiscoveryMetricsProvider;
 import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
 import org.jetbrains.annotations.Nullable;
@@ -64,7 +62,7 @@ import static 
org.apache.ignite.internal.util.lang.ClusterNodeFunc.eqNodes;
  * <tt>public</tt> due to certain limitations of Java technology.
  */
 public class TcpDiscoveryNode extends GridMetadataAwareAdapter implements 
IgniteClusterNode,
-    Comparable<TcpDiscoveryNode>, Externalizable, MarshallableMessage {
+    Comparable<TcpDiscoveryNode>, Externalizable, SelfMarshallingMessage {
     /** */
     private static final long serialVersionUID = 0L;
 
@@ -223,12 +221,12 @@ public class TcpDiscoveryNode extends 
GridMetadataAwareAdapter implements Ignite
     }
 
     /** {@inheritDoc} */
-    @Override public void marshal(Marshaller marsh) throws 
IgniteCheckedException {
+    @Override public void selfMarshal() {
         metricsMsg = new NodeMetricsMessage(metrics);
     }
 
     /** {@inheritDoc} */
-    @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) 
throws IgniteCheckedException {
+    @Override public void selfUnmarshal() {
         if (metricsMsg != null)
             metrics = new ClusterMetricsSnapshot(metricsMsg);
 
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 8fa7bc91c6b..43aa5b967ed 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
@@ -372,6 +372,24 @@ public class MessageProcessorTest {
             
.hasSourceEquivalentTo(javaFile("TestMarshallableMessageMarshaller.java"));
     }
 
+    /** The self-marshalling step is called from the generated marshaller, 
statically. */
+    @Test
+    public void testSelfMarshallingMessage() {
+        Compilation compilation = compile("TestSelfMarshallingMessage.java");
+
+        assertThat(compilation).succeeded();
+
+        assertEquals(2, compilation.generatedSourceFiles().size());
+
+        assertThat(compilation)
+            
.generatedSourceFile("org.apache.ignite.internal.TestSelfMarshallingMessageSerializer")
+            
.hasSourceEquivalentTo(javaFile("TestSelfMarshallingMessageSerializer.java"));
+
+        assertThat(compilation)
+            
.generatedSourceFile("org.apache.ignite.internal.TestSelfMarshallingMessageMarshaller")
+            
.hasSourceEquivalentTo(javaFile("TestSelfMarshallingMessageMarshaller.java"));
+    }
+
     /**
      * Negative test for a coflict situation when two enum mappers are used 
for the same enum in different messages.
      */
@@ -611,8 +629,19 @@ public class MessageProcessorTest {
 
         assertThat(compilation).failed();
 
-        assertThat(compilation)
-            .hadErrorContaining("NonMarshallableMessage must not implement 
MarshallableMessage or declare @Marshalled fields");
+        assertThat(compilation).hadErrorContaining("NonMarshallableMessage 
must not implement MarshallableMessage " +
+            "or SelfMarshallingMessage, nor declare @Marshalled fields");
+    }
+
+    /** A self-marshalling step of a {@code NonMarshallableMessage} would 
never run: it gets no marshaller to call it. */
+    @Test
+    public void testNonMarshallableSelfMarshallingFailed() {
+        Compilation compilation = compile("WrongSelfMarshallingMessage.java");
+
+        assertThat(compilation).failed();
+
+        assertThat(compilation).hadErrorContaining("NonMarshallableMessage 
must not implement MarshallableMessage " +
+            "or SelfMarshallingMessage, nor declare @Marshalled fields");
     }
 
     /** */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java
index f6fcc89dad5..b4f8532b9df 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java
@@ -21,7 +21,7 @@ import java.io.Serializable;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.IgniteConfiguration;
-import 
org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider;
+import org.apache.ignite.internal.plugin.AbstractMessageFactoryProvider;
 import org.apache.ignite.marshaller.Marshaller;
 import org.apache.ignite.plugin.AbstractTestPluginProvider;
 import org.apache.ignite.plugin.ExtensionRegistry;
@@ -94,7 +94,7 @@ public class MessageFactoryMarshallerInitializationTest 
extends GridCommonAbstra
     }
 
     /** Message factory provider, which counts initializations. */
-    private static class TestMessageFactoryProvider extends 
AbstractMarshallableMessageFactoryProvider {
+    private static class TestMessageFactoryProvider extends 
AbstractMessageFactoryProvider {
         /** {@inheritDoc} */
         @Override public void registerAll(IgniteMessageFactory factory) {
             // No-op.
diff --git 
a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
 
b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
index f0c4fa25f9f..b5e2c457ffe 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
@@ -38,7 +38,7 @@ import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.direct.DirectMessageWriter;
 import org.apache.ignite.internal.managers.communication.IgniteMessageFactory;
 import org.apache.ignite.internal.managers.communication.MessageMarshalling;
-import 
org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider;
+import org.apache.ignite.internal.plugin.AbstractMessageFactoryProvider;
 import org.apache.ignite.internal.processors.cache.CacheObjectContext;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.marshaller.Marshallers;
@@ -344,7 +344,7 @@ public abstract class DiscoveryUnmarshalVulnerabilityTest 
extends GridCommonAbst
     public static class TestMessageFactoryPlugin extends 
AbstractTestPluginProvider {
         /** {@inheritDoc} */
         @Override public void initExtensions(PluginContext ctx, 
ExtensionRegistry registry) {
-            registry.registerExtension(MessageFactoryProvider.class, new 
AbstractMarshallableMessageFactoryProvider() {
+            registry.registerExtension(MessageFactoryProvider.class, new 
AbstractMessageFactoryProvider() {
                 /** {@inheritDoc} */
                 @Override public void registerAll(IgniteMessageFactory 
factory) {
                     factory.register(
diff --git 
a/modules/core/src/test/resources/codegen/TestSelfMarshallingMessage.java 
b/modules/core/src/test/resources/codegen/TestSelfMarshallingMessage.java
new file mode 100644
index 00000000000..d67250092d4
--- /dev/null
+++ b/modules/core/src/test/resources/codegen/TestSelfMarshallingMessage.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+public class TestSelfMarshallingMessage implements SelfMarshallingMessage {
+    long ttl;
+
+    @Order(0)
+    long ttlOnWire;
+
+    @Override public void selfMarshal() {
+        ttlOnWire = ttl;
+    }
+
+    @Override public void selfUnmarshal() {
+        ttl = ttlOnWire;
+    }
+
+    public short directType() {
+        return 0;
+    }
+}
diff --git 
a/modules/core/src/test/resources/codegen/TestSelfMarshallingMessageMarshaller.java
 
b/modules/core/src/test/resources/codegen/TestSelfMarshallingMessageMarshaller.java
new file mode 100644
index 00000000000..bbecc98571e
--- /dev/null
+++ 
b/modules/core/src/test/resources/codegen/TestSelfMarshallingMessageMarshaller.java
@@ -0,0 +1,41 @@
+/*
+ * 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.IgniteCheckedException;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.TestSelfMarshallingMessage;
+import org.apache.ignite.internal.processors.cache.CacheObjectContext;
+import org.apache.ignite.plugin.extensions.communication.MessageMarshaller;
+
+/**
+ * This class is generated automatically.
+ *
+ * @see org.apache.ignite.internal.MessageProcessor
+ */
+public final class TestSelfMarshallingMessageMarshaller implements 
MessageMarshaller<TestSelfMarshallingMessage> {
+    /** */
+    @Override public void marshal(TestSelfMarshallingMessage msg, 
GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws 
IgniteCheckedException {
+        msg.selfMarshal();
+    }
+
+    /** */
+    @Override public void unmarshal(TestSelfMarshallingMessage msg, 
GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) 
throws IgniteCheckedException {
+        msg.selfUnmarshal();
+    }
+}
diff --git 
a/modules/core/src/test/resources/codegen/TestSelfMarshallingMessageSerializer.java
 
b/modules/core/src/test/resources/codegen/TestSelfMarshallingMessageSerializer.java
new file mode 100644
index 00000000000..ceb51075839
--- /dev/null
+++ 
b/modules/core/src/test/resources/codegen/TestSelfMarshallingMessageSerializer.java
@@ -0,0 +1,70 @@
+/*
+ * 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.TestSelfMarshallingMessage;
+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 final class TestSelfMarshallingMessageSerializer implements 
MessageSerializer<TestSelfMarshallingMessage> {
+    /** */
+    @Override public final boolean writeTo(TestSelfMarshallingMessage msg, 
MessageWriter writer) {
+        if (!writer.isHeaderWritten()) {
+            if (!writer.writeHeader(msg.directType()))
+                return false;
+
+            writer.onHeaderWritten();
+        }
+
+        switch (writer.state()) {
+            case 0:
+                if (!writer.writeLong(msg.ttlOnWire))
+                    return false;
+
+                writer.incrementState();
+        }
+
+        return true;
+    }
+
+    /** */
+    @Override public final boolean readFrom(TestSelfMarshallingMessage msg, 
MessageReader reader) {
+        switch (reader.state()) {
+            case 0:
+                msg.ttlOnWire = reader.readLong();
+
+                if (!reader.isLastRead())
+                    return false;
+
+                reader.incrementState();
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public final TestSelfMarshallingMessage createMessage() {
+        return new TestSelfMarshallingMessage();
+    }
+}
diff --git 
a/modules/core/src/test/resources/codegen/WrongSelfMarshallingMessage.java 
b/modules/core/src/test/resources/codegen/WrongSelfMarshallingMessage.java
new file mode 100644
index 00000000000..b0d5f255a02
--- /dev/null
+++ b/modules/core/src/test/resources/codegen/WrongSelfMarshallingMessage.java
@@ -0,0 +1,37 @@
+/*
+ * 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.plugin.extensions.communication.NonMarshallableMessage;
+
+public class WrongSelfMarshallingMessage implements NonMarshallableMessage, 
SelfMarshallingMessage {
+    @Order(0)
+    int id;
+
+    @Override public void selfMarshal() {
+        // No-op.
+    }
+
+    @Override public void selfUnmarshal() {
+        // No-op.
+    }
+
+    public short directType() {
+        return 0;
+    }
+}
diff --git 
a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java
 
b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java
index c7b32818666..4432f981bd7 100644
--- 
a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java
+++ 
b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java
@@ -18,10 +18,10 @@
 package org.apache.ignite.spi.discovery.zk.internal;
 
 import org.apache.ignite.internal.managers.communication.IgniteMessageFactory;
-import 
org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider;
+import org.apache.ignite.internal.plugin.AbstractMessageFactoryProvider;
 
 /** */
-public class ZkMessageFactory extends 
AbstractMarshallableMessageFactoryProvider {
+public class ZkMessageFactory extends AbstractMessageFactoryProvider {
     /** {@inheritDoc} */
     @Override public void registerAll(IgniteMessageFactory factory) {
         register(factory, ZkCommunicationErrorResolveFinishMessage.class, 
(short)400);

Reply via email to