This is an automated email from the ASF dual-hosted git repository.
tkalkirill 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 e1dca925ef IGNITE-22651 Add @Nullable for NetworkMessage fields for
generated classes (#4037)
e1dca925ef is described below
commit e1dca925efefac68f919bf578f119a2ab3cd9fb6
Author: Kirill Tkalenko <[email protected]>
AuthorDate: Wed Jul 3 15:31:28 2024 +0300
IGNITE-22651 Add @Nullable for NetworkMessage fields for generated classes
(#4037)
---
.../network/processor/MessageGeneratorUtils.java | 75 ++++++++++++++++++++++
.../messages/MessageBuilderGenerator.java | 67 +++++++++++++------
.../processor/messages/MessageImplGenerator.java | 45 ++++---------
.../MessageDeserializerGenerator.java | 4 +-
.../serialization/MessageReaderMethodResolver.java | 4 +-
.../serialization/MessageWriterMethodResolver.java | 4 +-
6 files changed, 138 insertions(+), 61 deletions(-)
diff --git
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/MessageGeneratorUtils.java
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/MessageGeneratorUtils.java
new file mode 100644
index 0000000000..2da7486b8b
--- /dev/null
+++
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/MessageGeneratorUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ArrayTypeName;
+import com.squareup.javapoet.TypeName;
+import java.util.List;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import org.apache.ignite.internal.network.NetworkMessage;
+import org.jetbrains.annotations.Nullable;
+
+/** Сlass that contains useful constants and methods when generating classes
for {@link NetworkMessage}. */
+public class MessageGeneratorUtils {
+ /** {@link Nullable} spec. */
+ public static final AnnotationSpec NULLABLE_ANNOTATION_SPEC =
AnnotationSpec.builder(Nullable.class).build();
+
+ /** Type name of the {@code byte[]}. */
+ public static final TypeName BYTE_ARRAY_TYPE =
ArrayTypeName.of(TypeName.BYTE);
+
+ /** Type name of the {@code byte @Nullable []}. */
+ public static final TypeName NULLABLE_BYTE_ARRAY_TYPE =
ArrayTypeName.of(TypeName.BYTE).annotated(NULLABLE_ANNOTATION_SPEC);
+
+ /** Returns {@link true} if the method return value is marked with {@link
Nullable}. */
+ public static boolean methodReturnsNullableValue(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 true;
+ }
+ }
+
+ return false;
+ }
+
+ return el.getAnnotation(Nullable.class) != null;
+ }
+
+ /** Returns {@link true} if the method return primitive value. */
+ public static boolean methodReturnsPrimitive(ExecutableElement el) {
+ return el.getReturnType().getKind().isPrimitive();
+ }
+
+ /** Adds postfix "ByteArray". */
+ public static String addByteArrayPostfix(String s) {
+ return s + "ByteArray";
+ }
+}
diff --git
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageBuilderGenerator.java
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageBuilderGenerator.java
index f214f3c45a..d1d2e07059 100644
---
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageBuilderGenerator.java
+++
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageBuilderGenerator.java
@@ -17,8 +17,12 @@
package org.apache.ignite.internal.network.processor.messages;
-import static
org.apache.ignite.internal.network.processor.messages.MessageImplGenerator.BYTE_ARRAY_TYPE;
-import static
org.apache.ignite.internal.network.processor.messages.MessageImplGenerator.getByteArrayFieldName;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.BYTE_ARRAY_TYPE;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.NULLABLE_ANNOTATION_SPEC;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.NULLABLE_BYTE_ARRAY_TYPE;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.addByteArrayPostfix;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.methodReturnsNullableValue;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.methodReturnsPrimitive;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
@@ -29,7 +33,6 @@ import java.util.List;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
-import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.apache.ignite.internal.network.annotations.Marshallable;
import org.apache.ignite.internal.network.processor.MessageClass;
@@ -75,33 +78,42 @@ public class MessageBuilderGenerator {
return TypeSpec.interfaceBuilder(builderName)
.addModifiers(Modifier.PUBLIC)
- .addMethods(generateGettersAndSetters(message,
message.getters()))
- .addMethods(generateByteArrayGettersAndSetters(message,
message.getters()))
+ .addMethods(generateGettersAndSetters(message))
+ .addMethods(generateByteArrayGettersAndSetters(message))
.addMethod(buildMethod)
.addOriginatingElement(message.element())
.addOriginatingElement(messageGroup.element())
.build();
}
- private List<MethodSpec> generateGettersAndSetters(MessageClass message,
List<ExecutableElement> fields) {
- List<MethodSpec> methods = new ArrayList<>();
+ private static List<MethodSpec> generateGettersAndSetters(MessageClass
message) {
+ var methods = new ArrayList<MethodSpec>();
- for (ExecutableElement field : fields) {
- String fieldName = field.getSimpleName().toString();
+ for (ExecutableElement networkMessageGetter : message.getters()) {
+ String fieldName = networkMessageGetter.getSimpleName().toString();
- TypeMirror type = field.getReturnType();
+ TypeName returnTypeName =
TypeName.get(networkMessageGetter.getReturnType());
+
+ if
(methodReturnsNotPrimitiveButNullableValue(networkMessageGetter)) {
+ // Allows us to generate (for example):
+ // TestMessageBuilder value(@Nullable String value);
+ // @Nullable String value();
+ // TestMessageBuilder values(String @Nullable [] value);
+ // String @Nullable [] values();
+ returnTypeName =
returnTypeName.annotated(NULLABLE_ANNOTATION_SPEC);
+ }
// generate a setter for each getter in the original interface
MethodSpec setterSpec = MethodSpec.methodBuilder(fieldName)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addParameter(TypeName.get(type), fieldName)
+ .addParameter(returnTypeName, fieldName)
.returns(message.builderClassName())
.build();
// generate a getter for each getter in the original interface
MethodSpec getterSpec = MethodSpec.methodBuilder(fieldName)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .returns(TypeName.get(type))
+ .returns(returnTypeName)
.build();
methods.add(setterSpec);
@@ -111,22 +123,31 @@ public class MessageBuilderGenerator {
return methods;
}
- private List<MethodSpec> generateByteArrayGettersAndSetters(MessageClass
message, List<ExecutableElement> fields) {
- List<MethodSpec> methods = new ArrayList<>();
+ private static List<MethodSpec>
generateByteArrayGettersAndSetters(MessageClass message) {
+ var methods = new ArrayList<MethodSpec>();
+
+ for (ExecutableElement networkMessageGetter : message.getters()) {
+ if (networkMessageGetter.getAnnotation(Marshallable.class) !=
null) {
+ String fieldName =
networkMessageGetter.getSimpleName().toString();
- for (ExecutableElement field : fields) {
- if (field.getAnnotation(Marshallable.class) != null) {
- String fieldName = field.getSimpleName().toString();
+ TypeName getterAndSetterTypeName = BYTE_ARRAY_TYPE;
- MethodSpec baSetter =
MethodSpec.methodBuilder(getByteArrayFieldName(fieldName))
+ if
(methodReturnsNotPrimitiveButNullableValue(networkMessageGetter)) {
+ // Allows us to generate (for example):
+ // TestMessageBuilder valueByteArray(byte @Nullable []
value);
+ // byte @Nullable [] valueByteArray();
+ getterAndSetterTypeName = NULLABLE_BYTE_ARRAY_TYPE;
+ }
+
+ MethodSpec baSetter =
MethodSpec.methodBuilder(addByteArrayPostfix(fieldName))
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addParameter(BYTE_ARRAY_TYPE,
getByteArrayFieldName(fieldName))
+ .addParameter(getterAndSetterTypeName,
addByteArrayPostfix(fieldName))
.returns(message.builderClassName())
.build();
- MethodSpec baGetter =
MethodSpec.methodBuilder(getByteArrayFieldName(fieldName))
+ MethodSpec baGetter =
MethodSpec.methodBuilder(addByteArrayPostfix(fieldName))
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .returns(BYTE_ARRAY_TYPE)
+ .returns(getterAndSetterTypeName)
.build();
methods.add(baSetter);
@@ -136,4 +157,8 @@ public class MessageBuilderGenerator {
return methods;
}
+
+ private static boolean
methodReturnsNotPrimitiveButNullableValue(ExecutableElement method) {
+ return !methodReturnsPrimitive(method) &&
methodReturnsNullableValue(method);
+ }
}
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 3c17b3806a..3d836a96f7 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
@@ -17,8 +17,12 @@
package org.apache.ignite.internal.network.processor.messages;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.BYTE_ARRAY_TYPE;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.addByteArrayPostfix;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.methodReturnsNullableValue;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.methodReturnsPrimitive;
+
import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -41,7 +45,6 @@ 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;
@@ -60,16 +63,12 @@ import
org.apache.ignite.internal.network.serialization.MessageSerializer;
import org.apache.ignite.internal.tostring.IgniteToStringExclude;
import org.apache.ignite.internal.tostring.IgniteToStringInclude;
import org.apache.ignite.internal.tostring.S;
-import org.jetbrains.annotations.Nullable;
/**
* Class for generating implementations of the {@link NetworkMessage}
interfaces and their builders, generated by a {@link
* MessageBuilderGenerator}.
*/
public class MessageImplGenerator {
- /** Type name of the {@code byte[]}. */
- static final ArrayTypeName BYTE_ARRAY_TYPE =
ArrayTypeName.of(TypeName.BYTE);
-
/** Processing environment. */
private final ProcessingEnvironment processingEnv;
@@ -164,7 +163,7 @@ public class MessageImplGenerator {
if (isMarshallable) {
marshallableFieldNames.add(getterName);
- String name = getByteArrayFieldName(getterName);
+ String name = addByteArrayPostfix(getterName);
FieldSpec marshallableFieldArray =
FieldSpec.builder(BYTE_ARRAY_TYPE, name)
.addModifiers(Modifier.PRIVATE)
.build();
@@ -360,7 +359,7 @@ public class MessageImplGenerator {
if (executableElement.getAnnotation(Marshallable.class) != null) {
isNeeded = true;
- String baName = getByteArrayFieldName(objectName);
+ String baName = addByteArrayPostfix(objectName);
String moName = baName + "mo";
prepareMarshal.addStatement("$T $N = marshaller.marshal($N)",
marshalledObjectClass, moName, objectName);
prepareMarshal.addStatement("usedDescriptors.addAll($N.usedDescriptorIds())",
moName);
@@ -422,7 +421,7 @@ public class MessageImplGenerator {
if (executableElement.getAnnotation(Marshallable.class) != null) {
isNeeded = true;
- String baName = getByteArrayFieldName(objectName);
+ String baName = addByteArrayPostfix(objectName);
unmarshal.addStatement("$N = marshaller.unmarshal($N,
descriptorsObj)", objectName, baName);
unmarshal.addStatement("$N = null", baName);
} else {
@@ -670,7 +669,7 @@ public class MessageImplGenerator {
if (notNullFieldNames.contains(fieldName) &&
marshallableFieldNames.contains(fieldName)) {
CodeBlock nullCheck = CodeBlock.builder()
- .beginControlFlow("if ($L == null && $L == null)",
fieldName, getByteArrayFieldName(fieldName))
+ .beginControlFlow("if ($L == null && $L == null)",
fieldName, addByteArrayPostfix(fieldName))
.addStatement("throw new $T($S)",
NullPointerException.class, fieldName + " is not marked @Nullable")
.endControlFlow()
.build();
@@ -737,7 +736,7 @@ public class MessageImplGenerator {
getters.add(getter);
if (isMarshallable) {
- String name = getByteArrayFieldName(getterName);
+ String name = addByteArrayPostfix(getterName);
FieldSpec baField = FieldSpec.builder(BYTE_ARRAY_TYPE, name)
.addModifiers(Modifier.PRIVATE)
.build();
@@ -809,29 +808,7 @@ public class MessageImplGenerator {
}
private static boolean requiresNotNullCheck(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";
+ return !methodReturnsPrimitive(el) && !methodReturnsNullableValue(el);
}
/** Types that may hold network message. */
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 7c0c06c401..777d981d81 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
@@ -18,7 +18,7 @@
package org.apache.ignite.internal.network.processor.serialization;
import static java.util.stream.Collectors.toList;
-import static
org.apache.ignite.internal.network.processor.messages.MessageImplGenerator.getByteArrayFieldName;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.addByteArrayPostfix;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
@@ -139,7 +139,7 @@ public class MessageDeserializerGenerator {
String name = getter.getSimpleName().toString();
if (getter.getAnnotation(Marshallable.class) != null) {
- name = getByteArrayFieldName(name);
+ name = addByteArrayPostfix(name);
}
method
diff --git
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageReaderMethodResolver.java
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageReaderMethodResolver.java
index e6a51b63bd..2e439b76a2 100644
---
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageReaderMethodResolver.java
+++
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageReaderMethodResolver.java
@@ -17,7 +17,7 @@
package org.apache.ignite.internal.network.processor.serialization;
-import static
org.apache.ignite.internal.network.processor.messages.MessageImplGenerator.getByteArrayFieldName;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.addByteArrayPostfix;
import com.squareup.javapoet.CodeBlock;
import java.util.List;
@@ -62,7 +62,7 @@ class MessageReaderMethodResolver {
String parameterName = getter.getSimpleName().toString();
if (getter.getAnnotation(Marshallable.class) != null) {
- parameterName = getByteArrayFieldName(parameterName);
+ parameterName = addByteArrayPostfix(parameterName);
return CodeBlock.builder()
.add("readByteArray($S)", parameterName)
.build();
diff --git
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageWriterMethodResolver.java
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageWriterMethodResolver.java
index 7a872d4b48..36e3fddcab 100644
---
a/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageWriterMethodResolver.java
+++
b/modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/serialization/MessageWriterMethodResolver.java
@@ -17,7 +17,7 @@
package org.apache.ignite.internal.network.processor.serialization;
-import static
org.apache.ignite.internal.network.processor.messages.MessageImplGenerator.getByteArrayFieldName;
+import static
org.apache.ignite.internal.network.processor.MessageGeneratorUtils.addByteArrayPostfix;
import com.squareup.javapoet.CodeBlock;
import java.util.Collection;
@@ -75,7 +75,7 @@ class MessageWriterMethodResolver {
String parameterName = getter.getSimpleName().toString();
if (getter.getAnnotation(Marshallable.class) != null) {
- parameterName = getByteArrayFieldName(parameterName);
+ parameterName = addByteArrayPostfix(parameterName);
return CodeBlock.builder()
.add("writeByteArray($S, message.$L())", parameterName,
parameterName)
.build();