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

sdanilov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new e0a48c4c5e IGNITE-19437 Add nullability checks for generated messages 
(#2040)
e0a48c4c5e is described below

commit e0a48c4c5e86b58de32fdb9bc582445feb4abf03
Author: Semyon Danilov <[email protected]>
AuthorDate: Thu May 11 17:09:10 2023 +0400

    IGNITE-19437 Add nullability checks for generated messages (#2040)
---
 .../internal/cluster/management/ClusterState.java  |   2 +
 .../network/messages/CancelInitMessage.java        |   2 +
 .../network/messages/CmgInitMessage.java           |   2 +
 .../raft/commands/ClusterNodeMessage.java          |   2 +
 .../internal/compute/message/ExecuteRequest.java   |   3 +-
 .../internal/compute/message/ExecuteResponse.java  |   3 +
 .../metastorage/impl/MetaStorageServiceImpl.java   |   2 +-
 .../processor/messages/MessageImplGenerator.java   | 120 +++++++++++++++----
 .../MessageDeserializerGenerator.java              |  24 +++-
 .../processor/tests/NotNullFieldMessages.java      |  52 +++++++++
 .../processor/tests/NullabilityFieldsTest.java     | 128 +++++++++++++++++++++
 .../processor/tests/NullableFieldMessages.java     |  55 +++++++++
 modules/network/build.gradle                       |   1 +
 .../scalecube/ItScaleCubeNetworkMessagingTest.java |   6 +-
 .../internal/network/message/ScaleCubeMessage.java |   3 +
 .../internal/network/messages/AllTypesMessage.java |  29 +++--
 .../network/messages/NestedMessageMessage.java     |   2 +
 .../messages/SerializationOrderMessage.java        |   3 +
 .../internal/network/messages/TestMessage.java     |   3 +
 modules/placement-driver-api/build.gradle          |   1 +
 .../message/LeaseGrantedMessageResponse.java       |   2 +
 .../message/PlacementDriverMessage.java            |   3 +
 .../message/StopLeaseProlongationMessage.java      |   2 +
 .../raft/jraft/entity/LocalFileMetaOutter.java     |   3 +
 .../raft/jraft/entity/LocalStorageOutter.java      |   2 +
 .../ignite/raft/jraft/entity/RaftOutter.java       |   9 ++
 .../ignite/raft/jraft/rpc/ActionResponse.java      |   2 +
 .../apache/ignite/raft/jraft/rpc/CliRequests.java  |   8 ++
 .../apache/ignite/raft/jraft/rpc/RpcRequests.java  |  13 ++-
 .../org/apache/ignite/raft/TestWriteCommand.java   |   2 +
 modules/replicator/build.gradle                    |   1 +
 .../replicator/message/ReplicaRequest.java         |   3 +
 .../replicator/message/ReplicaResponse.java        |   2 +
 .../sql/engine/message/QueryStartResponse.java     |   2 +
 .../table/distributed/command/UpdateCommand.java   |   2 +
 .../snapshot/message/SnapshotRequestMessage.java   |   3 +
 .../request/ReadWriteMultiRowReplicaRequest.java   |   3 +
 .../request/ReadWriteReplicaRequest.java           |   4 +
 .../request/ReadWriteSingleRowReplicaRequest.java  |   3 +
 .../request/ScanRetrieveBatchReplicaRequest.java   |   6 +
 40 files changed, 472 insertions(+), 46 deletions(-)

diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterState.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterState.java
index a6384da48b..9ab0a43e8d 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterState.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/ClusterState.java
@@ -23,6 +23,7 @@ import 
org.apache.ignite.internal.cluster.management.network.messages.CmgMessage
 import org.apache.ignite.internal.properties.IgniteProductVersion;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Represents the state of the CMG. It contains:
@@ -65,5 +66,6 @@ public interface ClusterState extends NetworkMessage, 
Serializable {
     /**
      * Returns a cluster configuration that should be applied.
      */
+    @Nullable
     String clusterConfigurationToApply();
 }
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CancelInitMessage.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CancelInitMessage.java
index 0e257736ed..2039798bc6 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CancelInitMessage.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CancelInitMessage.java
@@ -19,6 +19,7 @@ package 
org.apache.ignite.internal.cluster.management.network.messages;
 
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Message signaling that the init process has failed and needs to be aborted.
@@ -28,5 +29,6 @@ public interface CancelInitMessage extends NetworkMessage {
     /**
      * Textual representation of the cause of init failure.
      */
+    @Nullable
     String reason();
 }
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgInitMessage.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgInitMessage.java
index 189a50f845..6041581313 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgInitMessage.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/network/messages/CmgInitMessage.java
@@ -20,6 +20,7 @@ package 
org.apache.ignite.internal.cluster.management.network.messages;
 import java.util.Set;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Message for initializing the Cluster Management Group.
@@ -44,5 +45,6 @@ public interface CmgInitMessage extends NetworkMessage {
     /**
      * Cluster configuration that should be applied after init.
      */
+    @Nullable
     String clusterConfigurationToApply();
 }
diff --git 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ClusterNodeMessage.java
 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ClusterNodeMessage.java
index 18a3e6baa2..90cba09914 100644
--- 
a/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ClusterNodeMessage.java
+++ 
b/modules/cluster-management/src/main/java/org/apache/ignite/internal/cluster/management/raft/commands/ClusterNodeMessage.java
@@ -24,6 +24,7 @@ import org.apache.ignite.network.ClusterNode;
 import org.apache.ignite.network.NetworkAddress;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * {@link ClusterNode} as a network message class.
@@ -42,5 +43,6 @@ public interface ClusterNodeMessage extends NetworkMessage, 
Serializable {
         return new ClusterNode(id(), name(), new NetworkAddress(host(), 
port()));
     }
 
+    @Nullable
     Map<String, String> nodeAttributes();
 }
diff --git 
a/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteRequest.java
 
b/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteRequest.java
index 6d4aefd1b9..e2930e10fd 100644
--- 
a/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteRequest.java
+++ 
b/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteRequest.java
@@ -22,6 +22,7 @@ import org.apache.ignite.internal.compute.ComputeMessageTypes;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Used to implement remote job execution in {@link 
org.apache.ignite.compute.IgniteCompute#execute(Set, Class, Object...)}.
@@ -41,5 +42,5 @@ public interface ExecuteRequest extends NetworkMessage {
      * @return arguments
      */
     @Marshallable
-    Object[] args();
+    Object @Nullable [] args();
 }
diff --git 
a/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteResponse.java
 
b/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteResponse.java
index fa95e2056f..17ef2cec68 100644
--- 
a/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteResponse.java
+++ 
b/modules/compute/src/main/java/org/apache/ignite/internal/compute/message/ExecuteResponse.java
@@ -22,6 +22,7 @@ import org.apache.ignite.internal.compute.ComputeMessageTypes;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Used to implement remote job execution in {@link 
org.apache.ignite.compute.IgniteCompute#execute(Set, Class, Object...)}.
@@ -33,6 +34,7 @@ public interface ExecuteResponse extends NetworkMessage {
      *
      * @return result ({@code null} if the execution has failed)
      */
+    @Nullable
     @Marshallable
     Object result();
 
@@ -41,6 +43,7 @@ public interface ExecuteResponse extends NetworkMessage {
      *
      * @return {@link Throwable} that was thrown during job execution ({@code 
null} if the execution was successful)
      */
+    @Nullable
     @Marshallable
     Throwable throwable();
 }
diff --git 
a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
 
b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
index 85c9e94048..d0fc3ff04f 100644
--- 
a/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
+++ 
b/modules/metastorage/src/main/java/org/apache/ignite/internal/metastorage/impl/MetaStorageServiceImpl.java
@@ -285,7 +285,7 @@ public class MetaStorageServiceImpl implements 
MetaStorageService {
         return context.raftService().run(syncTimeCommand);
     }
 
-    // TODO: IGNITE-14734 Implement.
+    // TODO: IGNITE-19417 Implement.
     @Override
     public CompletableFuture<Void> compact() {
         throw new UnsupportedOperationException();
diff --git 
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageImplGenerator.java
 
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageImplGenerator.java
index 0d95f5afaa..826d9883cc 100644
--- 
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageImplGenerator.java
+++ 
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageImplGenerator.java
@@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.IntSet;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -39,6 +40,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.type.ArrayType;
@@ -55,6 +57,7 @@ import org.apache.ignite.internal.tostring.S;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.WithSetter;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Class for generating implementations of the {@link NetworkMessage} 
interfaces and their builders, generated by a {@link
@@ -102,6 +105,9 @@ public class MessageImplGenerator {
         var fields = new ArrayList<FieldSpec>(getters.size());
         var methodImpls = new ArrayList<MethodSpec>(getters.size());
 
+        Set<String> notNullFieldNames = new HashSet<>();
+        Set<String> marshallableFieldNames = new HashSet<>();
+
         // create a field and a getter implementation for every getter in the 
message interface
         for (ExecutableElement getter : getters) {
             TypeMirror getterType = getter.getReturnType();
@@ -114,6 +120,7 @@ public class MessageImplGenerator {
                     .addModifiers(Modifier.PRIVATE);
 
             boolean isMarshallable = getter.getAnnotation(Marshallable.class) 
!= null;
+            boolean isNotNull = shouldRequireNotNull(getter);
             boolean isNetworkMessage = typeUtils.isSubType(getterType, 
NetworkMessage.class);
 
             if (isMarshallable && isNetworkMessage) {
@@ -129,6 +136,14 @@ public class MessageImplGenerator {
                 fieldBuilder.addModifiers(Modifier.FINAL);
             }
 
+            if (isNotNull) {
+                notNullFieldNames.add(getterName);
+            }
+
+            if (isMarshallable) {
+                marshallableFieldNames.add(getterName);
+            }
+
             FieldSpec field = fieldBuilder.build();
             fields.add(field);
 
@@ -172,7 +187,7 @@ public class MessageImplGenerator {
                 .addSuperinterface(message.className())
                 .addFields(fields)
                 .addMethods(methodImpls)
-                .addMethod(constructor(fields));
+                .addMethod(constructor(fields, notNullFieldNames, 
marshallableFieldNames));
 
         // group type constant and getter
         FieldSpec groupTypeField = FieldSpec.builder(short.class, "GROUP_TYPE")
@@ -224,7 +239,7 @@ public class MessageImplGenerator {
         var builderName = ClassName.get(message.packageName(), 
builderInterface.name);
 
         // nested builder interface and static factory method
-        TypeSpec builder = generateBuilderImpl(message, messageImplClassName, 
builderName);
+        TypeSpec builder = generateBuilderImpl(message, messageImplClassName, 
builderName, notNullFieldNames, marshallableFieldNames);
 
         messageImpl.addType(builder);
 
@@ -596,15 +611,27 @@ public class MessageImplGenerator {
     /**
      * Creates a constructor for the current Network Message implementation.
      */
-    private static MethodSpec constructor(List<FieldSpec> fields) {
+    private static MethodSpec constructor(List<FieldSpec> fields, Set<String> 
notNullFieldNames, Set<String> marshallableFieldNames) {
         MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
                 .addModifiers(Modifier.PRIVATE);
 
-        fields.forEach(field ->
-                constructor
-                        .addParameter(field.type, field.name)
-                        .addStatement("this.$N = $N", field, field)
-        );
+        fields.forEach(field -> {
+            String fieldName = field.name;
+
+            if (notNullFieldNames.contains(fieldName) && 
marshallableFieldNames.contains(fieldName)) {
+                CodeBlock nullCheck = CodeBlock.builder()
+                        .beginControlFlow("if ($L == null && $L == null)", 
fieldName, getByteArrayFieldName(fieldName))
+                        .addStatement("throw new $T($S)", 
NullPointerException.class, fieldName + " is not marked @Nullable")
+                        .endControlFlow()
+                        .build();
+
+                constructor.addCode(nullCheck);
+            }
+
+            constructor
+                    .addParameter(field.type, fieldName)
+                    .addStatement("this.$N = $N", field, field);
+        });
 
         return constructor.build();
     }
@@ -613,8 +640,8 @@ public class MessageImplGenerator {
      * Generates a nested static class that implements the Builder interface, 
generated during previous steps.
      */
     private static TypeSpec generateBuilderImpl(
-            MessageClass message, ClassName messageImplClass, ClassName 
builderName
-    ) {
+            MessageClass message, ClassName messageImplClass, ClassName 
builderName, Set<String> notNullFieldNames,
+            Set<String> marshallableFieldNames) {
         List<ExecutableElement> messageGetters = message.getters();
 
         var fields = new ArrayList<FieldSpec>(messageGetters.size());
@@ -622,24 +649,31 @@ public class MessageImplGenerator {
         var getters = new ArrayList<MethodSpec>(messageGetters.size());
 
         for (ExecutableElement messageGetter : messageGetters) {
+            boolean isMarshallable = 
messageGetter.getAnnotation(Marshallable.class) != null;
+
             var getterReturnType = TypeName.get(messageGetter.getReturnType());
 
             String getterName = messageGetter.getSimpleName().toString();
 
             FieldSpec field = FieldSpec.builder(getterReturnType, getterName)
-                    .addModifiers(Modifier.PRIVATE)
-                    .build();
+                    .addModifiers(Modifier.PRIVATE).build();
 
             fields.add(field);
 
-            MethodSpec setter = MethodSpec.methodBuilder(getterName)
+            Builder setterBuilder = MethodSpec.methodBuilder(getterName)
                     .addAnnotation(Override.class)
                     .addModifiers(Modifier.PUBLIC)
                     .returns(builderName)
-                    .addParameter(getterReturnType, getterName)
-                    .addStatement("this.$N = $L", field, getterName)
-                    .addStatement("return this")
-                    .build();
+                    .addParameter(getterReturnType, getterName);
+
+            if (notNullFieldNames.contains(getterName)) {
+                setterBuilder.addStatement("$T.requireNonNull($L, $S)", 
Objects.class, getterName, getterName + " is not marked @Nullable");
+            }
+
+            setterBuilder.addStatement("this.$N = $L", field, getterName)
+                    .addStatement("return this");
+
+            MethodSpec setter = setterBuilder.build();
 
             setters.add(setter);
 
@@ -652,7 +686,7 @@ public class MessageImplGenerator {
 
             getters.add(getter);
 
-            if (messageGetter.getAnnotation(Marshallable.class) != null) {
+            if (isMarshallable) {
                 String name = getByteArrayFieldName(getterName);
                 FieldSpec baField = FieldSpec.builder(BYTE_ARRAY_TYPE, name)
                         .addModifiers(Modifier.PRIVATE)
@@ -688,26 +722,64 @@ public class MessageImplGenerator {
                 .addFields(fields)
                 .addMethods(setters)
                 .addMethods(getters)
-                .addMethod(buildMethod(message, messageImplClass, fields))
+                .addMethod(buildMethod(message, messageImplClass, fields, 
notNullFieldNames, marshallableFieldNames))
                 .build();
     }
 
     /**
      * Generates the {@code build()} method for the Builder interface 
implementation.
      */
-    private static MethodSpec buildMethod(MessageClass message, ClassName 
messageImplClass, List<FieldSpec> fields) {
-        String constructorParameters = fields.stream()
-                .map(field -> field.name)
-                .collect(Collectors.joining(", ", "(", ")"));
+    private static MethodSpec buildMethod(MessageClass message, ClassName 
messageImplClass, List<FieldSpec> fields,
+            Set<String> notNullFieldNames, Set<String> marshallableFieldNames) 
{
+
+        CodeBlock.Builder methodBodyBuilder = CodeBlock.builder();
+
+        methodBodyBuilder.add("return new $T", messageImplClass);
+
+        CodeBlock constructorArgs = fields.stream()
+                .map(field -> {
+                    String fieldName = field.name;
+
+                    if (notNullFieldNames.contains(fieldName) && 
!marshallableFieldNames.contains(fieldName)) {
+                        return CodeBlock.of("$T.requireNonNull($L, $S)", 
Objects.class, fieldName, fieldName + " is not marked @Nullable");
+                    }
+
+                    return CodeBlock.of("$L", fieldName);
+                })
+                .collect(CodeBlock.joining(", ", "(", ")"));
+
+        methodBodyBuilder.add(constructorArgs);
 
         return MethodSpec.methodBuilder("build")
                 .addAnnotation(Override.class)
                 .addModifiers(Modifier.PUBLIC)
                 .returns(message.className())
-                .addStatement("return new $T$L", messageImplClass, 
constructorParameters)
+                .addStatement(methodBodyBuilder.build())
                 .build();
     }
 
+    private static boolean shouldRequireNotNull(ExecutableElement el) {
+        TypeMirror returnType = el.getReturnType();
+
+        TypeKind kind = returnType.getKind();
+
+        if (kind == TypeKind.ARRAY) {
+            List<? extends AnnotationMirror> annotations = 
returnType.getAnnotationMirrors();
+
+            for (AnnotationMirror annotation : annotations) {
+                DeclaredType annotationType = annotation.getAnnotationType();
+
+                if 
(Nullable.class.getName().equals(annotationType.toString())) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        return !kind.isPrimitive() && el.getAnnotation(Nullable.class) == null;
+    }
+
     public static String getByteArrayFieldName(String objectName) {
         return objectName + "ByteArray";
     }
diff --git 
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageDeserializerGenerator.java
 
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageDeserializerGenerator.java
index 11cb176444..e753dfb211 100644
--- 
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageDeserializerGenerator.java
+++ 
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageDeserializerGenerator.java
@@ -19,11 +19,13 @@ package 
org.apache.ignite.internal.network.processor.serialization;
 
 import static 
org.apache.ignite.internal.network.processor.messages.MessageImplGenerator.getByteArrayFieldName;
 
+import com.squareup.javapoet.ArrayTypeName;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
 import com.squareup.javapoet.MethodSpec;
 import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
 import com.squareup.javapoet.TypeSpec;
 import java.util.List;
 import javax.annotation.processing.ProcessingEnvironment;
@@ -128,9 +130,17 @@ public class MessageDeserializerGenerator {
             method.beginControlFlow("switch (reader.state())");
 
             for (int i = 0; i < getters.size(); ++i) {
+                ExecutableElement getter = getters.get(i);
+
+                String name = getter.getSimpleName().toString();
+
+                if (getter.getAnnotation(Marshallable.class) != null) {
+                    name = getByteArrayFieldName(name);
+                }
+
                 method
                         .beginControlFlow("case $L:", i)
-                        .addStatement(readMessageCodeBlock(getters.get(i), 
msgField))
+                        .addStatement(readMessageCodeBlock(getter))
                         .addCode("\n")
                         .addCode(CodeBlock.builder()
                                 .beginControlFlow("if (!reader.isLastRead())")
@@ -139,6 +149,7 @@ public class MessageDeserializerGenerator {
                                 .build()
                         )
                         .addCode("\n")
+                        .addStatement("$N.$N(tmp)", msgField, name)
                         .addStatement("reader.incrementState()")
                         .endControlFlow()
                         .addComment("Falls through");
@@ -155,19 +166,20 @@ public class MessageDeserializerGenerator {
     /**
      * Helper method for resolving a {@link MessageReader} "read*" call based 
on the message field type.
      */
-    private CodeBlock readMessageCodeBlock(ExecutableElement getter, FieldSpec 
msgField) {
+    private CodeBlock readMessageCodeBlock(ExecutableElement getter) {
         var methodResolver = new MessageReaderMethodResolver(processingEnv);
 
-        String name = getter.getSimpleName().toString();
+        TypeName varType;
 
         if (getter.getAnnotation(Marshallable.class) != null) {
-            name = getByteArrayFieldName(name);
+            varType = ArrayTypeName.of(TypeName.BYTE);
+        } else {
+            varType = TypeName.get(getter.getReturnType());
         }
 
         return CodeBlock.builder()
-                .add("$N.$N(reader.", msgField, name)
+                .add("$T tmp = reader.", varType)
                 .add(methodResolver.resolveReadMethod(getter))
-                .add(")")
                 .build();
     }
 }
diff --git 
a/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NotNullFieldMessages.java
 
b/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NotNullFieldMessages.java
new file mode 100644
index 0000000000..fc87a8e988
--- /dev/null
+++ 
b/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NotNullFieldMessages.java
@@ -0,0 +1,52 @@
+/*
+ * 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.network.processor.tests;
+
+import java.util.UUID;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Marshallable;
+import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
+
+/** Messages with not {@link Nullable} fields. */
+public class NotNullFieldMessages {
+    /** Message with {@link UUID} field that is not {@link Nullable} field. */
+    @Transferable(3)
+    public interface NotNullArbitraryFieldMessage extends NetworkMessage {
+        UUID value();
+    }
+
+    /** Message with {@link Marshallable} field that is not {@link Nullable}. 
*/
+    @Transferable(4)
+    public interface NotNullMarshallableFieldMessage extends NetworkMessage {
+        @Marshallable
+        Object value();
+    }
+
+    /** Message with {@link NetworkMessage} field that is not {@link 
Nullable}. */
+    @Transferable(5)
+    public interface NotNullNetworkMessageFieldMessage extends NetworkMessage {
+        NetworkMessage value();
+    }
+
+    /** Message with array field that is not {@link Nullable}. */
+    @Transferable(6)
+    public interface NotNullArrayFieldMessage extends NetworkMessage {
+        int[] value();
+    }
+}
diff --git 
a/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NullabilityFieldsTest.java
 
b/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NullabilityFieldsTest.java
new file mode 100644
index 0000000000..71c39c73b4
--- /dev/null
+++ 
b/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NullabilityFieldsTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.network.processor.tests;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+/** Tests for messages with and without {@link 
org.jetbrains.annotations.Nullable} fields. */
+public class NullabilityFieldsTest {
+    private final TestMessagesFactory factory = new TestMessagesFactory();
+
+    @Test
+    public void testNotNullArbitraryFieldBuildWithNull() {
+        assertThrows(NullPointerException.class, () -> {
+            // Should throw NPE from setter.
+            factory.notNullArbitraryFieldMessage().value(null);
+        });
+        assertThrows(NullPointerException.class, () -> {
+            // Should throw NPE from build method.
+            factory.notNullArbitraryFieldMessage().build();
+        });
+    }
+
+    @Test
+    public void testNotNullArbitraryFieldBuild() {
+        assertDoesNotThrow(() -> {
+            // Build with value.
+            
factory.notNullArbitraryFieldMessage().value(UUID.randomUUID()).build();
+        });
+    }
+
+    @Test
+    public void testNotNullMarshallableFieldBuildWithNull() {
+        assertThrows(NullPointerException.class, () -> {
+            // Should throw NPE from constructor.
+            factory.notNullMarshallableFieldMessage().build();
+        });
+    }
+
+    @Test
+    public void testNotNullMarshallableFieldBuild() {
+        assertDoesNotThrow(() -> {
+            // Build with value.
+            factory.notNullMarshallableFieldMessage().value(new 
Object()).build();
+
+            // Build with byte array representation of a value.
+            factory.notNullMarshallableFieldMessage().valueByteArray(new 
byte[0]).build();
+        });
+    }
+
+    @Test
+    public void testNotNullNetworkMessageFieldBuild() {
+        assertDoesNotThrow(() -> {
+            // Build with value.
+            factory.notNullNetworkMessageFieldMessage().value(
+                    
factory.notNullArbitraryFieldMessage().value(UUID.randomUUID()).build()
+            ).build();
+        });
+    }
+
+    @Test
+    public void testNotNullArrayFieldBuildWithNull() {
+        assertThrows(NullPointerException.class, () -> {
+            factory.notNullArrayFieldMessage().value(null).build();
+        });
+        assertThrows(NullPointerException.class, () -> {
+            factory.notNullArrayFieldMessage().build();
+        });
+    }
+
+    @Test
+    public void testNotNullArrayFieldBuild() {
+        assertDoesNotThrow(() -> {
+            // Build with value.
+            factory.notNullArrayFieldMessage().value(new int[0]).build();
+        });
+    }
+
+    @Test
+    public void testNullableArbitraryFieldWithNull() {
+        assertDoesNotThrow(() -> {
+            factory.nullableArbitraryFieldMessage().value(null).build();
+            factory.nullableArbitraryFieldMessage().build();
+        });
+    }
+
+    @Test
+    public void testNullableMarshallableFieldWithNull() {
+        assertDoesNotThrow(() -> {
+            factory.nullableMarshallableFieldMessage().value(null).build();
+            factory.nullableMarshallableFieldMessage().build();
+        });
+    }
+
+    @Test
+    public void testNullableNetworkMessageFieldWithNull() {
+        assertDoesNotThrow(() -> {
+            factory.nullableNetworkMessageFieldMessage().value(null).build();
+            factory.nullableNetworkMessageFieldMessage().build();
+        });
+    }
+
+    @Test
+    public void testNullableArrayFieldWithNull() {
+        assertDoesNotThrow(() -> {
+            factory.nullableArrayFieldMessage().value(null).build();
+            factory.nullableArrayFieldMessage().build();
+        });
+    }
+}
diff --git 
a/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NullableFieldMessages.java
 
b/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NullableFieldMessages.java
new file mode 100644
index 0000000000..305d7376cb
--- /dev/null
+++ 
b/modules/network-annotation-processor/src/test/java/org/apache/ignite/internal/network/processor/tests/NullableFieldMessages.java
@@ -0,0 +1,55 @@
+/*
+ * 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.network.processor.tests;
+
+import java.util.UUID;
+import org.apache.ignite.network.NetworkMessage;
+import org.apache.ignite.network.annotations.Marshallable;
+import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
+
+/** Messages with {@link Nullable} fields. */
+public class NullableFieldMessages {
+    /** Message with {@link UUID} field that is {@link Nullable} field. */
+    @Transferable(7)
+    public interface NullableArbitraryFieldMessage extends NetworkMessage {
+        @Nullable
+        UUID value();
+    }
+
+    /** Message with {@link Marshallable} field that is {@link Nullable}. */
+    @Transferable(8)
+    public interface NullableMarshallableFieldMessage extends NetworkMessage {
+        @Nullable
+        @Marshallable
+        Object value();
+    }
+
+    /** Message with {@link NetworkMessage} field that is {@link Nullable}. */
+    @Transferable(9)
+    public interface NullableNetworkMessageFieldMessage extends NetworkMessage 
{
+        @Nullable
+        NetworkMessage value();
+    }
+
+    /** Message with array field that is {@link Nullable}. */
+    @Transferable(10)
+    public interface NullableArrayFieldMessage extends NetworkMessage {
+        int @Nullable [] value();
+    }
+}
diff --git a/modules/network/build.gradle b/modules/network/build.gradle
index 2a1094850b..fb33f0694c 100644
--- a/modules/network/build.gradle
+++ b/modules/network/build.gradle
@@ -72,6 +72,7 @@ dependencies {
     testFixturesImplementation libs.classgraph
     testFixturesImplementation libs.fastutil.core
     testFixturesImplementation libs.scalecube.cluster
+    testFixturesImplementation libs.jetbrains.annotations
 
     integrationTestAnnotationProcessor 
project(":ignite-network-annotation-processor")
 
diff --git 
a/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ItScaleCubeNetworkMessagingTest.java
 
b/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ItScaleCubeNetworkMessagingTest.java
index d9e86b4417..6f5c970339 100644
--- 
a/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ItScaleCubeNetworkMessagingTest.java
+++ 
b/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ItScaleCubeNetworkMessagingTest.java
@@ -48,12 +48,12 @@ import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 import org.apache.ignite.internal.network.NetworkMessageTypes;
 import org.apache.ignite.internal.network.NetworkMessagesFactory;
-import org.apache.ignite.internal.network.message.FieldDescriptorMessage;
 import org.apache.ignite.internal.network.messages.TestMessage;
 import org.apache.ignite.internal.network.messages.TestMessageTypes;
 import org.apache.ignite.internal.network.messages.TestMessagesFactory;
 import 
org.apache.ignite.internal.network.recovery.RecoveryClientHandshakeManager;
 import 
org.apache.ignite.internal.network.recovery.RecoveryServerHandshakeManager;
+import 
org.apache.ignite.internal.network.recovery.message.HandshakeFinishMessage;
 import org.apache.ignite.internal.testframework.jul.NoOpHandler;
 import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.NodeStoppingException;
@@ -304,7 +304,7 @@ class ItScaleCubeNetworkMessagingTest {
         node1.messagingService().addMessageHandler(
                 NetworkMessageTypes.class,
                 (message, sender, correlationId) -> {
-                    if (message instanceof FieldDescriptorMessage) {
+                    if (message instanceof HandshakeFinishMessage) {
                         assertTrue(networkMessageFuture.complete(message));
                     }
                 }
@@ -312,7 +312,7 @@ class ItScaleCubeNetworkMessagingTest {
 
         var testMessage = messageFactory.testMessage().msg("foo").build();
 
-        FieldDescriptorMessage networkMessage = new 
NetworkMessagesFactory().fieldDescriptorMessage().build();
+        HandshakeFinishMessage networkMessage = new 
NetworkMessagesFactory().handshakeFinishMessage().build();
 
         // test that a message gets delivered to both handlers
         node2.messagingService()
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/message/ScaleCubeMessage.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/message/ScaleCubeMessage.java
index 9fb1cddd72..e682f8c35c 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/message/ScaleCubeMessage.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/message/ScaleCubeMessage.java
@@ -23,6 +23,7 @@ import org.apache.ignite.internal.network.NetworkMessageTypes;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Wrapper for ScaleCube's {@link Message}. {@link Message#data} is stored in 
{@link #data} or {@link #message} depending on the type of the
@@ -30,9 +31,11 @@ import org.apache.ignite.network.annotations.Transferable;
  */
 @Transferable(NetworkMessageTypes.SCALE_CUBE_MESSAGE)
 public interface ScaleCubeMessage extends NetworkMessage {
+    @Nullable
     @Marshallable
     Object data();
 
+    @Nullable
     NetworkMessage message();
 
     Map<String, String> headers();
diff --git 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/AllTypesMessage.java
 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/AllTypesMessage.java
index 6c32e3352a..ce36a76008 100644
--- 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/AllTypesMessage.java
+++ 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/AllTypesMessage.java
@@ -28,6 +28,7 @@ import java.util.UUID;
 import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * {@link NetworkMessage} implementation.
@@ -50,41 +51,51 @@ public interface AllTypesMessage extends NetworkMessage, 
Serializable {
 
     boolean booleanH();
 
-    byte[] byteArrI();
+    byte @Nullable [] byteArrI();
 
-    short[] shortArrJ();
+    short @Nullable [] shortArrJ();
 
-    int[] intArrK();
+    int @Nullable [] intArrK();
 
-    long[] longArrL();
+    long @Nullable [] longArrL();
 
-    float[] floatArrM();
+    float @Nullable [] floatArrM();
 
-    double[] doubleArrN();
+    double @Nullable [] doubleArrN();
 
-    char[] charArrO();
+    char @Nullable [] charArrO();
 
-    boolean[] booleanArrP();
+    boolean @Nullable [] booleanArrP();
 
+    @Nullable
     String strQ();
 
+    @Nullable
     BitSet bitSetR();
 
+    @Nullable
     UUID uuidS();
 
+    @Nullable
     IgniteUuid igniteUuidT();
 
+    @Nullable
     NetworkMessage netMsgU();
 
-    NetworkMessage[] netMsgArrV();
+    NetworkMessage @Nullable [] netMsgArrV();
 
+    @Nullable
     Collection<NetworkMessage> netMsgCollW();
 
+    @Nullable
     Map<String, NetworkMessage> netMsgMapX();
 
+    @Nullable
     List<NetworkMessage> netMsgListY();
 
+    @Nullable
     Set<NetworkMessage> netMsgSetY();
 
+    @Nullable
     ByteBuffer byteBufferZ();
 }
diff --git 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/NestedMessageMessage.java
 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/NestedMessageMessage.java
index aeda395fbc..58fd67d413 100644
--- 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/NestedMessageMessage.java
+++ 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/NestedMessageMessage.java
@@ -19,11 +19,13 @@ package org.apache.ignite.internal.network.messages;
 
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Nested {@link NetworkMessage} implementation.
  */
 @Transferable(TestMessageTypes.NESTED_MESSAGE)
 public interface NestedMessageMessage extends NetworkMessage {
+    @Nullable
     NetworkMessage nestedMessage();
 }
diff --git 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/SerializationOrderMessage.java
 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/SerializationOrderMessage.java
index 3243517064..9db0025390 100644
--- 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/SerializationOrderMessage.java
+++ 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/SerializationOrderMessage.java
@@ -19,14 +19,17 @@ package org.apache.ignite.internal.network.messages;
 
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Test message used in {@link SerializationOrderTest}.
  */
 @Transferable(TestMessageTypes.SERIALIZATION_ORDER_MESSAGE)
 public interface SerializationOrderMessage extends NetworkMessage {
+    @Nullable
     String strB();
 
+    @Nullable
     String strD();
 
     int intC();
diff --git 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/TestMessage.java
 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/TestMessage.java
index fdac96ceec..fc37fab97f 100644
--- 
a/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/TestMessage.java
+++ 
b/modules/network/src/testFixtures/java/org/apache/ignite/internal/network/messages/TestMessage.java
@@ -21,13 +21,16 @@ import java.io.Serializable;
 import java.util.Map;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * {@link NetworkMessage} implementation.
  */
 @Transferable(TestMessageTypes.TEST)
 public interface TestMessage extends NetworkMessage, Serializable {
+    @Nullable
     String msg();
 
+    @Nullable
     Map<Integer, String> map();
 }
diff --git a/modules/placement-driver-api/build.gradle 
b/modules/placement-driver-api/build.gradle
index 81779696ef..2d68f81821 100644
--- a/modules/placement-driver-api/build.gradle
+++ b/modules/placement-driver-api/build.gradle
@@ -24,6 +24,7 @@ dependencies {
 
     implementation project(':ignite-core')
     implementation project(':ignite-network-api')
+    implementation libs.jetbrains.annotations
 }
 
 description = 'ignite-placement-driver-api'
diff --git 
a/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/LeaseGrantedMessageResponse.java
 
b/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/LeaseGrantedMessageResponse.java
index c6addb77ad..efd972828e 100644
--- 
a/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/LeaseGrantedMessageResponse.java
+++ 
b/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/LeaseGrantedMessageResponse.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.placementdriver.message;
 
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Response for lease granted message.
@@ -26,5 +27,6 @@ import org.apache.ignite.network.annotations.Transferable;
 public interface LeaseGrantedMessageResponse extends 
PlacementDriverReplicaMessage {
     boolean accepted();
 
+    @Nullable
     String redirectProposal();
 }
diff --git 
a/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/PlacementDriverMessage.java
 
b/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/PlacementDriverMessage.java
index 6b8c798de0..a88bf5c5b0 100644
--- 
a/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/PlacementDriverMessage.java
+++ 
b/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/PlacementDriverMessage.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.placementdriver.message;
 import org.apache.ignite.internal.replicator.ReplicationGroupId;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * A base message for placement driver network messages.
@@ -30,6 +31,8 @@ public interface PlacementDriverMessage extends 
NetworkMessage {
      *
      * @return Replication group id.
      */
+    // TODO: IGNITE-19457 Maybe not nullable.
+    @Nullable
     @Marshallable
     ReplicationGroupId groupId();
 }
diff --git 
a/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/StopLeaseProlongationMessage.java
 
b/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/StopLeaseProlongationMessage.java
index a9f84124c3..e57b9c4f19 100644
--- 
a/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/StopLeaseProlongationMessage.java
+++ 
b/modules/placement-driver-api/src/main/java/org/apache/ignite/internal/placementdriver/message/StopLeaseProlongationMessage.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.placementdriver.message;
 
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * The message is sent to placement driver when a leaseholder does not want to 
hold lease anymore.
@@ -29,5 +30,6 @@ public interface StopLeaseProlongationMessage extends 
PlacementDriverActorMessag
      *
      * @return Consistent id.
      */
+    @Nullable
     String redirectProposal();
 }
diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalFileMetaOutter.java
 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalFileMetaOutter.java
index c6d5f193ff..6a3b09600d 100644
--- 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalFileMetaOutter.java
+++ 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalFileMetaOutter.java
@@ -23,6 +23,7 @@ import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.jraft.RaftMessageGroup;
 import org.apache.ignite.raft.jraft.rpc.Message;
+import org.jetbrains.annotations.Nullable;
 
 public final class LocalFileMetaOutter {
     /**
@@ -72,9 +73,11 @@ public final class LocalFileMetaOutter {
 
     @Transferable(value = 
RaftMessageGroup.RaftOutterMessageGroup.LOCAL_FILE_META)
     public interface LocalFileMeta extends Message {
+        @Nullable
         @Marshallable
         FileSource source();
 
+        @Nullable
         String checksum();
 
         boolean hasUserMeta();
diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalStorageOutter.java
 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalStorageOutter.java
index 616e3b7fec..0abdea997e 100644
--- 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalStorageOutter.java
+++ 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/LocalStorageOutter.java
@@ -24,6 +24,7 @@ import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.jraft.RaftMessageGroup;
 import org.apache.ignite.raft.jraft.rpc.Message;
+import org.jetbrains.annotations.Nullable;
 
 public final class LocalStorageOutter {
     @Transferable(value = 
RaftMessageGroup.RaftOutterMessageGroup.STABLE_PB_META)
@@ -35,6 +36,7 @@ public final class LocalStorageOutter {
 
     @Transferable(value = 
RaftMessageGroup.RaftOutterMessageGroup.LOCAL_SNAPSHOT_PB_META)
     public interface LocalSnapshotPbMeta extends Message {
+        @Nullable
         RaftOutter.SnapshotMeta meta();
 
         @Marshallable
diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/RaftOutter.java
 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/RaftOutter.java
index d4665b4683..8e36f3ec75 100644
--- 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/RaftOutter.java
+++ 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/entity/RaftOutter.java
@@ -24,6 +24,7 @@ import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.jraft.RaftMessageGroup;
 import org.apache.ignite.raft.jraft.rpc.Message;
+import org.jetbrains.annotations.Nullable;
 
 public final class RaftOutter {
     @Transferable(value = RaftMessageGroup.RaftOutterMessageGroup.ENTRY_META)
@@ -33,16 +34,20 @@ public final class RaftOutter {
         @Marshallable
         EnumOutter.EntryType type();
 
+        @Nullable
         Collection<String> peersList();
 
         long dataLen();
 
+        @Nullable
         Collection<String> oldPeersList();
 
         long checksum();
 
+        @Nullable
         Collection<String> learnersList();
 
+        @Nullable
         Collection<String> oldLearnersList();
 
         /**
@@ -57,12 +62,16 @@ public final class RaftOutter {
 
         long lastIncludedTerm();
 
+        @Nullable
         Collection<String> peersList();
 
+        @Nullable
         Collection<String> oldPeersList();
 
+        @Nullable
         Collection<String> learnersList();
 
+        @Nullable
         Collection<String> oldLearnersList();
     }
 }
diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/ActionResponse.java
 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/ActionResponse.java
index 182271deef..91a6410517 100644
--- 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/ActionResponse.java
+++ 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/ActionResponse.java
@@ -20,6 +20,7 @@ package org.apache.ignite.raft.jraft.rpc;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.jraft.RaftMessageGroup;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * The result of an action.
@@ -29,6 +30,7 @@ public interface ActionResponse extends Message {
     /**
      * @return A result for this request, can be of any type.
      */
+    @Nullable
     @Marshallable
     Object result();
 }
diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/CliRequests.java 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/CliRequests.java
index 28e1abb3b0..92610d712e 100644
--- 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/CliRequests.java
+++ 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/CliRequests.java
@@ -25,6 +25,7 @@ import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.jraft.RaftMessageGroup;
 import org.apache.ignite.raft.jraft.RaftMessageGroup.RpcClientMessageGroup;
+import org.jetbrains.annotations.Nullable;
 
 public final class CliRequests {
     @Transferable(value = 
RaftMessageGroup.RpcClientMessageGroup.ADD_PEER_REQUEST)
@@ -38,6 +39,7 @@ public final class CliRequests {
 
     @Transferable(value = 
RaftMessageGroup.RpcClientMessageGroup.ADD_PEER_RESPONSE)
     public interface AddPeerResponse extends Message {
+        @Nullable
         Collection<String> oldPeersList();
 
         Collection<String> newPeersList();
@@ -54,6 +56,7 @@ public final class CliRequests {
 
     @Transferable(value = 
RaftMessageGroup.RpcClientMessageGroup.REMOVE_PEER_RESPONSE)
     public interface RemovePeerResponse extends Message {
+        @Nullable
         Collection<String> oldPeersList();
 
         Collection<String> newPeersList();
@@ -70,6 +73,7 @@ public final class CliRequests {
 
     @Transferable(value = 
RaftMessageGroup.RpcClientMessageGroup.CHANGE_PEERS_RESPONSE)
     public interface ChangePeersResponse extends Message {
+        @Nullable
         Collection<String> oldPeersList();
 
         Collection<String> newPeersList();
@@ -112,6 +116,7 @@ public final class CliRequests {
 
         String peerId();
 
+        @Nullable
         Collection<String> oldPeersList();
 
         Collection<String> newPeersList();
@@ -130,6 +135,7 @@ public final class CliRequests {
     public interface GetLeaderRequest extends Message {
         String groupId();
 
+        @Nullable
         String peerId();
     }
 
@@ -144,6 +150,7 @@ public final class CliRequests {
     public interface GetPeersRequest extends Message {
         String groupId();
 
+        @Nullable
         String leaderId();
 
         boolean onlyAlive();
@@ -185,6 +192,7 @@ public final class CliRequests {
 
     @Transferable(value = 
RaftMessageGroup.RpcClientMessageGroup.LEARNERS_OP_RESPONSE)
     public interface LearnersOpResponse extends Message {
+        @Nullable
         Collection<String> oldLearnersList();
 
         Collection<String> newLearnersList();
diff --git 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/RpcRequests.java 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/RpcRequests.java
index bad6d0a37a..2bde5df2bf 100644
--- 
a/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/RpcRequests.java
+++ 
b/modules/raft/src/main/java/org/apache/ignite/raft/jraft/rpc/RpcRequests.java
@@ -17,7 +17,9 @@
 
 package org.apache.ignite.raft.jraft.rpc;
 
-import static 
org.apache.ignite.internal.hlc.HybridTimestamp.hybridTimestamp;import static 
org.apache.ignite.internal.hlc.HybridTimestamp.nullableHybridTimestamp;import 
java.util.Collection;
+import static org.apache.ignite.internal.hlc.HybridTimestamp.hybridTimestamp;
+import static 
org.apache.ignite.internal.hlc.HybridTimestamp.nullableHybridTimestamp;
+import java.util.Collection;
 import java.util.List;
 import org.apache.ignite.internal.hlc.HybridTimestamp;
 import org.apache.ignite.network.annotations.Marshallable;
@@ -59,6 +61,7 @@ public final class RpcRequests {
          *
          * @return String with error message.
          */
+        @Nullable
         String errorMsg();
 
         /**
@@ -66,7 +69,8 @@ public final class RpcRequests {
          *
          * @return String new leader id, null otherwise.
          */
-        @Nullable String leaderId();
+        @Nullable
+        String leaderId();
     }
 
     @Transferable(value = 
RaftMessageGroup.RpcRequestsMessageGroup.SM_ERROR_RESPONSE)
@@ -168,10 +172,12 @@ public final class RpcRequests {
 
         long prevLogIndex();
 
+        @Nullable
         Collection<EntryMeta> entriesList();
 
         long committedIndex();
 
+        @Nullable
         @Marshallable
         ByteString data();
 
@@ -224,11 +230,14 @@ public final class RpcRequests {
     public interface ReadIndexRequest extends Message {
         String groupId();
 
+        @Nullable
         String serverId();
 
+        @Nullable
         @Marshallable
         List<ByteString> entriesList();
 
+        @Nullable
         String peerId();
     }
 
diff --git 
a/modules/raft/src/testFixtures/java/org/apache/ignite/raft/TestWriteCommand.java
 
b/modules/raft/src/testFixtures/java/org/apache/ignite/raft/TestWriteCommand.java
index 59e208f268..01999ff88a 100644
--- 
a/modules/raft/src/testFixtures/java/org/apache/ignite/raft/TestWriteCommand.java
+++ 
b/modules/raft/src/testFixtures/java/org/apache/ignite/raft/TestWriteCommand.java
@@ -20,12 +20,14 @@ package org.apache.ignite.raft;
 import org.apache.ignite.internal.raft.WriteCommand;
 import org.apache.ignite.network.annotations.Transferable;
 import org.apache.ignite.raft.messages.TestRaftMessagesFactory;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Test WriteCommand.
 */
 @Transferable(10)
 public interface TestWriteCommand extends WriteCommand {
+    @Nullable
     String value();
 
     static TestWriteCommand testWriteCommand() {
diff --git a/modules/replicator/build.gradle b/modules/replicator/build.gradle
index 06d2ad69ff..9ae80c5f26 100644
--- a/modules/replicator/build.gradle
+++ b/modules/replicator/build.gradle
@@ -57,6 +57,7 @@ dependencies {
     testFixturesImplementation project(':ignite-raft-api')
     testFixturesImplementation project(':ignite-core')
     testFixturesImplementation project(':ignite-cluster-management')
+    testFixturesImplementation libs.jetbrains.annotations
 }
 
 description = 'ignite-replicator'
diff --git 
a/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaRequest.java
 
b/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaRequest.java
index bcc6932e5f..77a319e883 100644
--- 
a/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaRequest.java
+++ 
b/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaRequest.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.replicator.message;
 import org.apache.ignite.internal.replicator.ReplicationGroupId;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Replica request.
@@ -30,6 +31,8 @@ public interface ReplicaRequest extends NetworkMessage {
      *
      * @return Replication group id.
      */
+    // TODO: IGNITE-19457 Maybe not nullable.
+    @Nullable
     @Marshallable
     ReplicationGroupId groupId();
 }
diff --git 
a/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaResponse.java
 
b/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaResponse.java
index aa42b4cc99..9a62a2f8fd 100644
--- 
a/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaResponse.java
+++ 
b/modules/replicator/src/main/java/org/apache/ignite/internal/replicator/message/ReplicaResponse.java
@@ -20,12 +20,14 @@ package org.apache.ignite.internal.replicator.message;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Replica response interface.
  */
 @Transferable(ReplicaMessageGroup.REPLICA_RESPONSE)
 public interface ReplicaResponse extends NetworkMessage {
+    @Nullable
     @Marshallable
     Object result();
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/message/QueryStartResponse.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/message/QueryStartResponse.java
index 2e8628bb72..6e74cf3400 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/message/QueryStartResponse.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/message/QueryStartResponse.java
@@ -22,6 +22,7 @@ import java.util.UUID;
 import org.apache.ignite.network.NetworkMessage;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * QueryStartResponse interface.
@@ -42,6 +43,7 @@ public interface QueryStartResponse extends NetworkMessage, 
Serializable {
     /**
      * Get error.
      */
+    @Nullable
     @Marshallable
     Throwable error();
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/command/UpdateCommand.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/command/UpdateCommand.java
index ab9746eaac..358432d1d7 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/command/UpdateCommand.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/command/UpdateCommand.java
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
 import java.util.UUID;
 import org.apache.ignite.internal.table.distributed.TableMessageGroup;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * State machine command to update a row specified by a row id.
@@ -31,5 +32,6 @@ public interface UpdateCommand extends PartitionCommand {
 
     UUID rowUuid();
 
+    @Nullable
     ByteBuffer rowBuffer();
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/snapshot/message/SnapshotRequestMessage.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/snapshot/message/SnapshotRequestMessage.java
index 39bb46137e..92462b6f16 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/snapshot/message/SnapshotRequestMessage.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/raft/snapshot/message/SnapshotRequestMessage.java
@@ -19,11 +19,14 @@ package 
org.apache.ignite.internal.table.distributed.raft.snapshot.message;
 
 import java.util.UUID;
 import org.apache.ignite.network.NetworkMessage;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Base interface for snapshot request messages.
  */
 public interface SnapshotRequestMessage extends NetworkMessage {
     /** Snapshot id. */
+    // TODO: IGNITE-19457 Maybe not nullable.
+    @Nullable
     UUID id();
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteMultiRowReplicaRequest.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteMultiRowReplicaRequest.java
index f2330dbdc3..1739ded91c 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteMultiRowReplicaRequest.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteMultiRowReplicaRequest.java
@@ -21,6 +21,7 @@ import org.apache.ignite.internal.replicator.TablePartitionId;
 import org.apache.ignite.internal.table.distributed.TableMessageGroup;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Read-write multi-row replica request.
@@ -32,6 +33,8 @@ public interface ReadWriteMultiRowReplicaRequest extends 
MultipleRowReplicaReque
      *
      * @return Table partition id.
      */
+    // TODO: IGNITE-19457 Maybe not nullable.
+    @Nullable
     @Marshallable
     TablePartitionId commitPartitionId();
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteReplicaRequest.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteReplicaRequest.java
index 910a39ed05..91316aaf4b 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteReplicaRequest.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteReplicaRequest.java
@@ -21,11 +21,13 @@ import java.util.UUID;
 import org.apache.ignite.internal.replicator.message.PrimaryReplicaRequest;
 import org.apache.ignite.internal.replicator.message.TimestampAware;
 import org.apache.ignite.network.annotations.Marshallable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Read-write replica request.
  */
 public interface ReadWriteReplicaRequest extends PrimaryReplicaRequest, 
TimestampAware {
+    @Nullable
     UUID transactionId();
 
     /**
@@ -34,7 +36,9 @@ public interface ReadWriteReplicaRequest extends 
PrimaryReplicaRequest, Timestam
      *
      * @return Raft term.
      */
+    // TODO: IGNITE-19457 Maybe not nullable.
     @Deprecated
+    @Nullable
     @Marshallable
     Long term();
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteSingleRowReplicaRequest.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteSingleRowReplicaRequest.java
index bd8b1344fd..81527dd3f7 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteSingleRowReplicaRequest.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ReadWriteSingleRowReplicaRequest.java
@@ -21,6 +21,7 @@ import org.apache.ignite.internal.replicator.TablePartitionId;
 import org.apache.ignite.internal.table.distributed.TableMessageGroup;
 import org.apache.ignite.network.annotations.Marshallable;
 import org.apache.ignite.network.annotations.Transferable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Read-write single-row replica request.
@@ -32,6 +33,8 @@ public interface ReadWriteSingleRowReplicaRequest extends 
SingleRowReplicaReques
      *
      * @return Table partition id.
      */
+    // TODO: IGNITE-19457 Maybe not nullable.
+    @Nullable
     @Marshallable
     TablePartitionId commitPartitionId();
 }
diff --git 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ScanRetrieveBatchReplicaRequest.java
 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ScanRetrieveBatchReplicaRequest.java
index e52d70a57f..c785fb4429 100644
--- 
a/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ScanRetrieveBatchReplicaRequest.java
+++ 
b/modules/table/src/main/java/org/apache/ignite/internal/table/distributed/replication/request/ScanRetrieveBatchReplicaRequest.java
@@ -24,6 +24,7 @@ import org.apache.ignite.internal.schema.BinaryTuple;
 import org.apache.ignite.internal.schema.BinaryTuplePrefix;
 import org.apache.ignite.internal.storage.index.SortedIndexStorage;
 import org.apache.ignite.network.annotations.Marshallable;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Scan retrieve batch replica request.
@@ -40,6 +41,7 @@ public interface ScanRetrieveBatchReplicaRequest extends 
ReplicaRequest {
      *
      * @return Index id.
      */
+    @Nullable
     UUID indexToUse();
 
     /**
@@ -47,6 +49,7 @@ public interface ScanRetrieveBatchReplicaRequest extends 
ReplicaRequest {
      *
      * @return Key to search.
      */
+    @Nullable
     @Marshallable
     BinaryTuple exactKey();
 
@@ -56,6 +59,7 @@ public interface ScanRetrieveBatchReplicaRequest extends 
ReplicaRequest {
      *
      * @return lower bound.
      */
+    @Nullable
     @Marshallable
     BinaryTuplePrefix lowerBound();
 
@@ -65,6 +69,7 @@ public interface ScanRetrieveBatchReplicaRequest extends 
ReplicaRequest {
      *
      * @return upper bound.
      */
+    @Nullable
     @Marshallable
     BinaryTuplePrefix upperBound();
 
@@ -81,6 +86,7 @@ public interface ScanRetrieveBatchReplicaRequest extends 
ReplicaRequest {
      *
      * @return Bitset to include columns.
      */
+    @Nullable
     @Marshallable
     BitSet columnsToInclude();
 }

Reply via email to