in packages/jsii-pacmak/lib/targets/java.ts [2408:2576]
private emitDataType(ifc: spec.InterfaceType) {
// collect all properties from all base structs and dedupe by name. It is assumed that the generation of the
// assembly will not permit multiple overloaded inherited properties with the same name and that this will be
// enforced by Typescript constraints.
const propsByName: { [name: string]: JavaProp } = {};
function collectProps(
this: JavaGenerator,
currentIfc: spec.InterfaceType,
isBaseClass = false,
) {
for (const property of currentIfc.properties ?? []) {
const javaProp = this.toJavaProp(property, currentIfc, isBaseClass);
propsByName[javaProp.propName] = javaProp;
}
// add props of base struct
for (const base of currentIfc.interfaces ?? []) {
collectProps.call(
this,
this.findType(base) as spec.InterfaceType,
true,
);
}
}
collectProps.call(this, ifc);
const props = Object.values(propsByName);
this.emitInterfaceBuilder(ifc, INTERFACE_PROXY_CLASS_NAME, props);
// Start implementation class
this.code.line();
this.code.line('/**');
this.code.line(` * An implementation for {@link ${ifc.name}}`);
this.code.line(' */');
this.emitStabilityAnnotations(ifc);
this.code.line(ANN_INTERNAL);
this.code.openBlock(
`final class ${INTERFACE_PROXY_CLASS_NAME} extends software.amazon.jsii.JsiiObject implements ${ifc.name}`,
);
// Immutable properties
props.forEach((prop) =>
this.code.line(`private final ${prop.fieldJavaType} ${prop.fieldName};`),
);
// Start JSII reference constructor
this.code.line();
this.code.line('/**');
this.code.line(
' * Constructor that initializes the object based on values retrieved from the JsiiObject.',
);
this.code.line(' * @param objRef Reference to the JSII managed object.');
this.code.line(' */');
this.code.openBlock(
`protected ${INTERFACE_PROXY_CLASS_NAME}(final software.amazon.jsii.JsiiObjectRef objRef)`,
);
this.code.line('super(objRef);');
props.forEach((prop) =>
this.code.line(
`this.${prop.fieldName} = software.amazon.jsii.Kernel.get(this, "${prop.jsiiName}", ${prop.fieldNativeType});`,
),
);
this.code.closeBlock();
// End JSII reference constructor
// Start builder constructor
this.code.line();
this.code.line('/**');
this.code.line(
' * Constructor that initializes the object based on literal property values passed by the {@link Builder}.',
);
this.code.line(' */');
if (props.some((prop) => prop.fieldJavaType !== prop.paramJavaType)) {
this.code.line('@SuppressWarnings("unchecked")');
}
this.code.openBlock(
`protected ${INTERFACE_PROXY_CLASS_NAME}(final ${BUILDER_CLASS_NAME} builder)`,
);
this.code.line(
'super(software.amazon.jsii.JsiiObject.InitializationMode.JSII);',
);
props.forEach((prop) => {
const explicitCast =
prop.fieldJavaType !== prop.paramJavaType
? `(${prop.fieldJavaType})`
: '';
this.code.line(
`this.${prop.fieldName} = ${explicitCast}${_validateIfNonOptional(
`builder.${prop.fieldName}`,
prop,
)};`,
);
});
this.code.closeBlock();
// End literal constructor
// Getters
props.forEach((prop) => {
this.code.line();
this.code.line('@Override');
this.code.openBlock(
`public final ${prop.fieldJavaType} get${prop.propName}()`,
);
this.code.line(`return this.${prop.fieldName};`);
this.code.closeBlock();
});
// emit $jsii$toJson which will be called to serialize this object when sent to JS
this.code.line();
this.code.line('@Override');
this.code.line(ANN_INTERNAL);
this.code.openBlock(
'public com.fasterxml.jackson.databind.JsonNode $jsii$toJson()',
);
this.code.line(
'final com.fasterxml.jackson.databind.ObjectMapper om = software.amazon.jsii.JsiiObjectMapper.INSTANCE;',
);
this.code.line(
`final com.fasterxml.jackson.databind.node.ObjectNode data = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode();`,
);
this.code.line();
for (const prop of props) {
if (prop.nullable) {
this.code.openBlock(`if (this.get${prop.propName}() != null)`);
}
this.code.line(
`data.set("${prop.spec.name}", om.valueToTree(this.get${prop.propName}()));`,
);
if (prop.nullable) {
this.code.closeBlock();
}
}
this.code.line();
this.code.line(
'final com.fasterxml.jackson.databind.node.ObjectNode struct = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode();',
);
this.code.line(`struct.set("fqn", om.valueToTree("${ifc.fqn}"));`);
this.code.line('struct.set("data", data);');
this.code.line();
this.code.line(
'final com.fasterxml.jackson.databind.node.ObjectNode obj = com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.objectNode();',
);
this.code.line('obj.set("$jsii.struct", struct);');
this.code.line();
this.code.line('return obj;');
this.code.closeBlock();
// End $jsii$toJson
// Generate equals() override
this.emitEqualsOverride(ifc.name, props);
// Generate hashCode() override
this.emitHashCodeOverride(props);
this.code.closeBlock();
// End implementation class
function _validateIfNonOptional(variable: string, prop: JavaProp): string {
if (prop.nullable) {
return variable;
}
return `java.util.Objects.requireNonNull(${variable}, "${prop.fieldName} is required")`;
}
}