in modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationImplAsmGenerator.java [332:519]
private void addConfigurationImplConstructor(
Map<String, FieldDefinition> fieldDefs,
@Nullable FieldDefinition extensionConfigTypesFieldDef
) {
MethodDefinition ctor = cfgImplClassDef.declareConstructor(
EnumSet.of(PUBLIC),
arg("prefix", List.class),
arg("key", String.class),
arg("rootKey", RootKey.class),
arg("changer", DynamicConfigurationChanger.class),
arg("listenOnly", boolean.class)
);
Variable rootKeyVar = ctor.getScope().getVariable("rootKey");
Variable changerVar = ctor.getScope().getVariable("changer");
Variable listenOnlyVar = ctor.getScope().getVariable("listenOnly");
SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
Variable thisVar = ctor.getThis();
BytecodeBlock ctorBody = ctor.getBody()
.append(thisVar)
.append(ctor.getScope().getVariable("prefix"))
.append(ctor.getScope().getVariable("key"))
.append(rootKeyVar)
.append(changerVar)
.append(listenOnlyVar)
.invokeConstructor(DYNAMIC_CONFIGURATION_CTOR);
BytecodeExpression thisKeysVar = thisVar.getField("keys", List.class);
// Wrap object into list to reuse the loop below.
List<Field> internalIdFieldAsList = internalIdField == null ? emptyList() : List.of(internalIdField);
int newIdx = 0;
for (Field schemaField :
concat(schemaFields, publicExtensionFields, internalExtensionFields, polymorphicFields, internalIdFieldAsList)
) {
String publicName = publicName(schemaField);
BytecodeExpression newValue;
if (isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField)) {
// A field with @InjectedName is special (auxiliary), it is not stored in storages as a regular field, and therefore there
// is no direct access to it. It is stored in the InnerNode and does not participate in its traversal, so in order to get
// it we need to get the InnerNode, and only then the value of this field.
// newValue = new DynamicProperty(this.keys, fieldName, rootKey, changer, listenOnly, readOnly);
newValue = newInstance(
DynamicProperty.class,
thisKeysVar,
constantString(isInjectedName(schemaField) ? InnerNode.INJECTED_NAME
: isInternalId(schemaField) ? InnerNode.INTERNAL_ID : publicName),
rootKeyVar,
changerVar,
listenOnlyVar,
constantBoolean(isReadOnly(schemaField))
);
} else {
SchemaClassesInfo fieldInfo = cgen.schemaInfo(schemaField.getType());
ParameterizedType cfgImplParameterizedType = typeFromJavaClassName(fieldInfo.cfgImplClassName);
if (isConfigValue(schemaField)) {
// newValue = new MyConfigurationImpl(super.keys, fieldName, rootKey, changer, listenOnly);
newValue = newInstance(
cfgImplParameterizedType,
thisKeysVar,
constantString(publicName),
rootKeyVar,
changerVar,
listenOnlyVar
);
} else {
// We have to create method "$new$<idx>" to reference it in lambda expression. That's the way it
// works, it'll invoke constructor with all 5 arguments, not just 2 as in BiFunction.
MethodDefinition newMtd = cfgImplClassDef.declareMethod(
EnumSet.of(PRIVATE, STATIC, SYNTHETIC),
"$new$" + newIdx++,
typeFromJavaClassName(fieldInfo.cfgClassName),
arg("rootKey", RootKey.class),
arg("changer", DynamicConfigurationChanger.class),
arg("listenOnly", boolean.class),
arg("prefix", List.class),
arg("key", String.class)
);
// newValue = new NamedListConfiguration(this.keys, fieldName, rootKey, changer, listenOnly,
// (p, k) -> new ValueConfigurationImpl(p, k, rootKey, changer, listenOnly),
// (p, c) -> new ValueDirectProxy(p, c),
// new ValueConfigurationImpl(this.keys, "any", rootKey, changer, true)
// );
newValue = newInstance(
NamedListConfiguration.class,
thisKeysVar,
constantString(publicName),
rootKeyVar,
changerVar,
listenOnlyVar,
invokeDynamic(
LAMBDA_METAFACTORY,
asList(
getMethodType(getType(Object.class), getType(Object.class), getType(Object.class)),
new Handle(
Opcodes.H_INVOKESTATIC,
internalName(schemaClassInfo.cfgImplClassName),
newMtd.getName(),
newMtd.getMethodDescriptor(),
false
),
getMethodType(
typeFromJavaClassName(fieldInfo.cfgClassName).getAsmType(),
getType(List.class),
getType(String.class)
)
),
"apply",
BiFunction.class,
rootKeyVar,
changerVar,
listenOnlyVar
),
newDirectProxyLambda(fieldInfo),
newInstance(
cfgImplParameterizedType,
thisKeysVar,
constantString("any"),
rootKeyVar,
changerVar,
constantBoolean(true)
).cast(ConfigurationProperty.class)
);
newMtd.getBody()
.append(newInstance(
cfgImplParameterizedType,
newMtd.getScope().getVariable("prefix"),
newMtd.getScope().getVariable("key"),
newMtd.getScope().getVariable("rootKey"),
newMtd.getScope().getVariable("changer"),
newMtd.getScope().getVariable("listenOnly")
))
.retObject();
}
}
FieldDefinition fieldDef = fieldDefs.get(fieldName(schemaField));
// this.field = newValue;
ctorBody.append(thisVar.setField(fieldDef, newValue));
if (!isPolymorphicConfigInstance(schemaField.getDeclaringClass()) && !isInternalId(schemaField)) {
// add(this.field);
ctorBody.append(thisVar.invoke(DYNAMIC_CONFIGURATION_ADD_MTD, thisVar.getField(fieldDef)));
}
}
if (extensionConfigTypesFieldDef != null) {
assert !extensions.isEmpty() : cfgImplClassDef;
// Class[] tmp;
Variable tmpVar = ctor.getScope().createTempVariable(Class[].class);
BytecodeBlock initExtensionConfigTypesField = new BytecodeBlock();
// tmp = new Class[size];
initExtensionConfigTypesField.append(tmpVar.set(newArray(type(Class[].class), extensions.size())));
int i = 0;
for (Class<?> extension : extensions) {
// tmp[i] = InternalTableConfiguration.class;
initExtensionConfigTypesField.append(set(
tmpVar,
constantInt(i++),
constantClass(typeFromJavaClassName(configurationClassName(extension)))
));
}
// this._extensionConfigTypes = tmp;
initExtensionConfigTypesField.append(setThisFieldCode(ctor, tmpVar, extensionConfigTypesFieldDef));
ctorBody.append(initExtensionConfigTypesField);
}
ctorBody.ret();
}