in modules/network-annotation-processor/src/main/java/org/apache/ignite/internal/network/processor/messages/MessageImplGenerator.java [104:321]
public TypeSpec generateMessageImpl(MessageClass message, TypeSpec builderInterface) {
ClassName messageImplClassName = message.implClassName();
processingEnv.getMessager()
.printMessage(Diagnostic.Kind.NOTE, "Generating " + messageImplClassName);
List<ExecutableElement> getters = message.getters();
var fields = new ArrayList<FieldSpec>(getters.size());
var methodImpls = new ArrayList<MethodSpec>(getters.size());
var notNullFieldNames = new HashSet<String>();
var marshallableFieldNames = new HashSet<String>();
// create a field and a getter implementation for every getter in the message interface
for (ExecutableElement getter : getters) {
TypeMirror getterType = getter.getReturnType();
TypeName getterReturnType = TypeName.get(getterType);
String getterName = getter.getSimpleName().toString();
boolean isMarshallable = getter.getAnnotation(Marshallable.class) != null;
if (isMarshallable && !marshallableTypesBlackList.canBeMarshallable(getterType)) {
String error = String.format(
"\"%s\" field is marked as @Marshallable but this type is either directly supported by native serialization "
+ "or is prohibited by a blacklist, remove this annotation from the field",
getterName
);
throw new ProcessingException(error, null, getter);
}
FieldSpec.Builder fieldBuilder = FieldSpec.builder(getterReturnType, getterName)
.addModifiers(Modifier.PRIVATE);
if (getter.getAnnotation(IgniteToStringExclude.class) == null) {
IgniteToStringInclude includeAnnotation = getter.getAnnotation(IgniteToStringInclude.class);
IgniteStringifier stringifierAnnotation = getter.getAnnotation(IgniteStringifier.class);
if (stringifierAnnotation != null) {
AnnotationSpec annotationSpec = AnnotationSpec.builder(IgniteStringifier.class)
.addMember("name", "$S", stringifierAnnotation.name())
.addMember("value", "$T.class", igniteStringifierValueTypeMirror(stringifierAnnotation))
.build();
fieldBuilder.addAnnotation(annotationSpec);
} else if (includeAnnotation != null) {
fieldBuilder.addAnnotation(AnnotationSpec.get(includeAnnotation));
} else {
fieldBuilder.addAnnotation(AnnotationSpec.builder(IgniteToStringInclude.class).build());
}
} else {
fieldBuilder.addAnnotation(IgniteToStringExclude.class);
}
boolean generateSetter = getter.getAnnotation(WithSetter.class) != null;
if (!isMarshallable && !generateSetter) {
fieldBuilder.addModifiers(Modifier.FINAL);
}
if (requiresNotNullCheck(getter)) {
notNullFieldNames.add(getterName);
}
FieldSpec field = fieldBuilder.build();
fields.add(field);
if (isMarshallable) {
marshallableFieldNames.add(getterName);
String name = addByteArrayPostfix(getterName);
FieldSpec marshallableFieldArray = FieldSpec.builder(BYTE_ARRAY_TYPE, name)
.addModifiers(Modifier.PRIVATE)
.build();
fields.add(marshallableFieldArray);
MethodSpec baGetterImpl = MethodSpec.methodBuilder(name)
.returns(BYTE_ARRAY_TYPE)
.addStatement("return $N", marshallableFieldArray)
.build();
methodImpls.add(baGetterImpl);
}
if (generateSetter) {
MethodSpec setterImpl = MethodSpec.methodBuilder(getterName)
.returns(TypeName.VOID)
.addModifiers(Modifier.PUBLIC)
.addParameter(getterReturnType, getterName)
.addAnnotation(Override.class)
.addStatement("this.$L = $L", getterName, getterName)
.build();
methodImpls.add(setterImpl);
}
MethodSpec getterImpl = MethodSpec.overriding(getter)
.addStatement("return $N", field)
.build();
methodImpls.add(getterImpl);
}
TypeSpec.Builder messageImpl = TypeSpec.classBuilder(messageImplClassName)
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(message.className())
.addSuperinterface(Cloneable.class)
.addFields(fields)
.addMethods(methodImpls)
.addMethod(constructor(fields, notNullFieldNames, marshallableFieldNames));
if (message.isAutoSerializable()) {
messageImpl.addMethod(MethodSpec.methodBuilder("serializer")
.returns(MessageSerializer.class)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addCode("return $T.INSTANCE;", message.serializerClassName())
.build());
} else {
messageImpl.addMethod(MethodSpec.methodBuilder("serializer")
.returns(MessageSerializer.class)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addCode("return null;")
.build());
}
// group type constant and getter
FieldSpec groupTypeField = FieldSpec.builder(short.class, "GROUP_TYPE")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$L", messageGroup.groupType())
.build();
messageImpl.addField(groupTypeField);
MethodSpec groupTypeMethod = MethodSpec.methodBuilder("groupType")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(short.class)
.addStatement("return $N", groupTypeField)
.build();
messageImpl.addMethod(groupTypeMethod);
MethodSpec toStringMethod = MethodSpec.methodBuilder("toString")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(String.class)
.addStatement("return $T.toString($T.class, this)", S.class, messageImplClassName)
.build();
messageImpl.addMethod(toStringMethod);
// message type constant and getter
FieldSpec messageTypeField = FieldSpec.builder(short.class, "TYPE")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$L", message.messageType())
.build();
messageImpl.addField(messageTypeField);
MethodSpec messageTypeMethod = MethodSpec.methodBuilder("messageType")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(short.class)
.addStatement("return $N", messageTypeField)
.build();
messageImpl.addMethod(messageTypeMethod);
// equals and hashCode
generateEqualsAndHashCode(messageImpl, message);
// generate clone
MethodSpec cloneMethod = MethodSpec.methodBuilder("clone")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(messageImplClassName)
.addCode(CodeBlock.builder()
.beginControlFlow("try")
.addStatement("return ($T) super.clone()", messageImplClassName)
.endControlFlow()
.beginControlFlow("catch (CloneNotSupportedException e)")
.addStatement("// Never expected to be thrown because whole message class hierarchy implements clone()")
.addStatement("throw new AssertionError(e)")
.endControlFlow()
.build())
.build();
messageImpl.addMethod(cloneMethod);
var builderName = ClassName.get(message.packageName(), builderInterface.name);
// nested builder interface and static factory method
TypeSpec builder = generateBuilderImpl(message, messageImplClassName, builderName, notNullFieldNames, marshallableFieldNames);
messageImpl.addType(builder);
MethodSpec builderMethod = MethodSpec.methodBuilder("builder")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(builderName)
.addStatement("return new $N()", builder)
.build();
messageImpl.addMethod(builderMethod);
generatePrepareMarshal(messageImpl, message);
generateUnmarshalMethod(messageImpl, message);
messageImpl
.addOriginatingElement(message.element())
.addOriginatingElement(messageGroup.element());
return messageImpl.build();
}