in modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/InnerNodeAsmGenerator.java [1622:1798]
private ClassDefinition createPolymorphicExtensionNodeClass(
Class<?> polymorphicExtension,
Collection<Field> polymorphicFields
) {
SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
SchemaClassesInfo polymorphicExtensionClassInfo = cgen.schemaInfo(polymorphicExtension);
// Node class definition.
ClassDefinition classDef = new ClassDefinition(
EnumSet.of(PUBLIC, FINAL),
internalName(polymorphicExtensionClassInfo.nodeClassName),
type(Object.class),
ArrayUtils.concat(nodeClassInterfaces(polymorphicExtension, Set.of()), type(ConstructableTreeNode.class))
);
// private final ParentNode this$0;
FieldDefinition parentInnerNodeFieldDef = classDef.declareField(
EnumSet.of(PRIVATE, FINAL),
"this$0",
typeFromJavaClassName(schemaClassInfo.nodeClassName)
);
// Constructor.
MethodDefinition constructorMtd = classDef.declareConstructor(
EnumSet.of(PUBLIC),
arg("delegate", typeFromJavaClassName(schemaClassInfo.nodeClassName))
);
Variable delegateVar = constructorMtd.getScope().getVariable("delegate");
// Constructor body.
constructorMtd.getBody()
.append(constructorMtd.getThis())
.invokeConstructor(Object.class)
.append(constructorMtd.getThis().setField(
parentInnerNodeFieldDef,
delegateVar
))
.ret();
Map<String, FieldDefinition> fieldDefs = innerNodeClassDef.getFields().stream()
.collect(toMap(FieldDefinition::getName, identity()));
// Creates method to get the internal id. Almost the same as regular view, but with method invocation instead of field access.
if (internalIdField != null) {
addNodeViewMethod(
classDef,
internalIdField,
viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef).invoke(INTERNAL_ID),
null
);
}
// Creates view and change methods for parent schema.
for (Field schemaField : schemaFields) {
FieldDefinition schemaFieldDef = fieldDefs.get(fieldName(schemaField));
addNodeViewMethod(
classDef,
schemaField,
viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef, schemaFieldDef),
null
);
// Read only.
if (isPolymorphicId(schemaField) || isInjectedName(schemaField)) {
continue;
}
List<MethodDefinition> changeMethods = addNodeChangeMethod(
classDef,
schemaField,
changeMtd -> getThisFieldCode(changeMtd, parentInnerNodeFieldDef, schemaFieldDef),
(changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, parentInnerNodeFieldDef, schemaFieldDef),
null
);
// Only first element requires a bridge. Please refer to "addNodeChangeMethod" for explanation.
addNodeChangeBridgeMethod(classDef, schemaClassInfo.changeClassName, changeMethods.get(0));
}
FieldDefinition polymorphicTypeIdFieldDef = fieldDefs.get(polymorphicIdField(schemaClass).getName());
// Creates view and change methods for specific polymorphic instance schema.
for (Field polymorphicField : polymorphicFields) {
FieldDefinition polymorphicFieldDef = fieldDefs.get(fieldName(polymorphicField));
addNodeViewMethod(
classDef,
polymorphicField,
viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef, polymorphicFieldDef),
viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef, polymorphicTypeIdFieldDef)
);
List<MethodDefinition> changeMethods = addNodeChangeMethod(
classDef,
polymorphicField,
changeMtd -> getThisFieldCode(changeMtd, parentInnerNodeFieldDef, polymorphicFieldDef),
(changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, parentInnerNodeFieldDef, polymorphicFieldDef),
changeMtd -> getThisFieldCode(changeMtd, parentInnerNodeFieldDef, polymorphicTypeIdFieldDef)
);
// Only first element requires a bridge. Please refer to "addNodeChangeMethod" for explanation.
addNodeChangeBridgeMethod(classDef, polymorphicExtensionClassInfo.changeClassName, changeMethods.get(0));
}
ParameterizedType returnType = typeFromJavaClassName(schemaClassInfo.changeClassName);
// Creates Node#convert(Class<T> changeClass).
MethodDefinition convertByChangeClassMtd = classDef.declareMethod(
EnumSet.of(PUBLIC),
CONVERT_MTD_NAME,
returnType,
arg("changeClass", Class.class)
);
// return this.this$0.convert(changeClass);
convertByChangeClassMtd.getBody()
.append(getThisFieldCode(convertByChangeClassMtd, parentInnerNodeFieldDef))
.append(convertByChangeClassMtd.getScope().getVariable("changeClass"))
.invokeVirtual(innerNodeClassDef.getType(), CONVERT_MTD_NAME, returnType, type(Class.class))
.retObject();
// Creates Node#convert(String polymorphicId).
MethodDefinition convertByPolymorphicTypeIdMtd = classDef.declareMethod(
EnumSet.of(PUBLIC),
CONVERT_MTD_NAME,
returnType,
arg("polymorphicTypeId", String.class)
);
// return this.this$0.convert(polymorphicTypeId);
convertByPolymorphicTypeIdMtd.getBody()
.append(getThisFieldCode(convertByPolymorphicTypeIdMtd, parentInnerNodeFieldDef))
.append(convertByPolymorphicTypeIdMtd.getScope().getVariable("polymorphicTypeId"))
.invokeVirtual(innerNodeClassDef.getType(), CONVERT_MTD_NAME, returnType, type(String.class))
.retObject();
// Creates ConstructableTreeNode#construct.
MethodDefinition constructMtd = classDef.declareMethod(
EnumSet.of(PUBLIC),
CONSTRUCT_MTD_NAME,
type(void.class),
arg("key", type(String.class)),
arg("src", type(ConfigurationSource.class)),
arg("includeInternal", type(boolean.class))
).addException(NoSuchElementException.class);
// return this.this$0.construct(key, src, includeInternal);
constructMtd.getBody()
.append(getThisFieldCode(constructMtd, parentInnerNodeFieldDef))
.append(constructMtd.getScope().getVariable("key"))
.append(constructMtd.getScope().getVariable("src"))
.append(constructMtd.getScope().getVariable("includeInternal"))
.invokeVirtual(
innerNodeClassDef.getType(),
CONSTRUCT_MTD_NAME,
type(void.class),
type(String.class), type(ConfigurationSource.class), type(boolean.class)
)
.ret();
// Creates ConstructableTreeNode#copy.
MethodDefinition copyMtd = classDef.declareMethod(
EnumSet.of(PUBLIC),
"copy",
type(ConstructableTreeNode.class)
);
// return this.this$0.copy();
copyMtd.getBody()
.append(getThisFieldCode(copyMtd, parentInnerNodeFieldDef))
.invokeVirtual(innerNodeClassDef.getType(), "copy", type(ConstructableTreeNode.class))
.retObject();
return classDef;
}