in litho-processor/src/main/java/com/facebook/litho/specmodels/generator/BuilderGenerator.java [133:299]
static TypeSpecDataHolder generateBuilder(SpecModel specModel) {
final String componentName = specModel.getComponentName();
final String componentInstanceRefName = ComponentBodyGenerator.getInstanceRefName(specModel);
final String componentMemberInstanceName = getComponentMemberInstanceName(specModel);
final ClassName componentClass = ClassName.bestGuess(componentName);
final MethodSpec.Builder ctorMethodSpec =
MethodSpec.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.addParameter(specModel.getContextClass(), CONTEXT_PARAM_NAME);
final ImmutableList<PropDefaultModel> propDefaults = specModel.getPropDefaults();
boolean isResResolvable = false;
for (PropDefaultModel propDefault : propDefaults) {
if (propDefault.isResResolvable()) {
isResResolvable = true;
break;
}
}
if (specModel.isStylingSupported()) {
ctorMethodSpec
.addParameter(int.class, "defStyleAttr")
.addParameter(int.class, "defStyleRes")
.addParameter(componentClass, componentInstanceRefName)
.addStatement("super(context, defStyleAttr, defStyleRes, $L)", componentInstanceRefName);
} else {
ctorMethodSpec
.addParameter(componentClass, componentInstanceRefName)
.addStatement("super(context, $L)", componentInstanceRefName);
}
ctorMethodSpec
.addStatement("$L = $L", componentMemberInstanceName, componentInstanceRefName)
.addStatement("$L = $L", CONTEXT_MEMBER_NAME, CONTEXT_PARAM_NAME);
if (isResResolvable) {
ctorMethodSpec.addStatement("initPropDefaults()");
}
final MethodSpec.Builder setComponentMethodSpec =
MethodSpec.methodBuilder("setComponent")
.addModifiers(Modifier.PROTECTED)
.addAnnotation(Override.class)
.addParameter(ClassNames.COMPONENT, "component")
.addStatement(
"$L = ($T) component",
getComponentMemberInstanceName(specModel),
specModel.getComponentTypeName());
final boolean builderHasTypeVariables = !specModel.getTypeVariables().isEmpty();
TypeName builderType = getBuilderType(specModel);
final TypeSpec.Builder propsBuilderClassBuilder =
TypeSpec.classBuilder(BUILDER)
.addAnnotation(Generated.class)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.superclass(
ParameterizedTypeName.get(
ClassName.get(
specModel.getComponentClass().packageName(),
specModel.getComponentClass().simpleName(),
BUILDER),
builderType))
.addField(componentClass, componentMemberInstanceName)
.addField(specModel.getContextClass(), CONTEXT_MEMBER_NAME);
if (builderHasTypeVariables) {
propsBuilderClassBuilder.addTypeVariables(specModel.getTypeVariables());
}
final List<String> requiredPropNames = new ArrayList<>();
int numRequiredProps = 0;
for (PropModel prop : specModel.getProps()) {
if (!prop.isOptional()) {
numRequiredProps++;
requiredPropNames.add(prop.getName());
}
}
if (numRequiredProps > 0) {
propsBuilderClassBuilder.addField(
FieldSpec.builder(String[].class, REQUIRED_PROPS_NAMES, Modifier.PRIVATE, Modifier.FINAL)
.initializer("new String[] {$L}", commaSeparateAndQuoteStrings(requiredPropNames))
.build());
propsBuilderClassBuilder.addField(
FieldSpec.builder(int.class, REQUIRED_PROPS_COUNT, Modifier.PRIVATE, Modifier.FINAL)
.initializer("$L", numRequiredProps)
.build());
propsBuilderClassBuilder.addField(
FieldSpec.builder(BitSet.class, "mRequired", Modifier.PRIVATE, Modifier.FINAL)
.initializer("new $T($L)", BitSet.class, REQUIRED_PROPS_COUNT)
.build());
ctorMethodSpec.addStatement("mRequired.clear()");
}
propsBuilderClassBuilder.addMethod(ctorMethodSpec.build());
if (specModel instanceof LayoutSpecModel || specModel instanceof MountSpecModel) {
propsBuilderClassBuilder.addMethod(setComponentMethodSpec.build());
}
if (isResResolvable) {
MethodSpec.Builder initResTypePropDefaultsSpec = MethodSpec.methodBuilder("initPropDefaults");
for (PropDefaultModel propDefault : propDefaults) {
if (!propDefault.isResResolvable()) {
continue;
}
initResTypePropDefaultsSpec.addStatement(
"this.$L.$L = $L",
getComponentMemberInstanceName(specModel),
propDefault.getName(),
generatePropsDefaultInitializers(specModel, propDefault));
}
propsBuilderClassBuilder.addMethod(initResTypePropDefaultsSpec.build());
}
int requiredPropIndex = 0;
for (PropModel prop : specModel.getProps()) {
generatePropsBuilderMethods(specModel, prop, requiredPropIndex)
.addToTypeSpec(propsBuilderClassBuilder);
if (!prop.isOptional()) {
requiredPropIndex++;
}
}
for (EventDeclarationModel eventDeclaration : specModel.getEventDeclarations()) {
propsBuilderClassBuilder.addMethod(
generateEventDeclarationBuilderMethod(specModel, eventDeclaration));
}
for (SpecMethodModel<EventMethod, EventDeclarationModel> triggerMethod :
specModel.getTriggerMethods()) {
propsBuilderClassBuilder.addMethod(
generateEventTriggerBuilderMethod(specModel, triggerMethod));
propsBuilderClassBuilder.addMethod(
generateEventTriggerChangeKeyMethod(specModel, triggerMethod));
}
if (!specModel.getTriggerMethods().isEmpty()) {
propsBuilderClassBuilder.addMethod(
generateRegisterEventTriggersMethod(specModel.getTriggerMethods()));
}
for (BuilderMethodModel builderMethodModel : specModel.getExtraBuilderMethods()) {
if (builderMethodModel.paramName.equals("key") && !specModel.getTriggerMethods().isEmpty()) {
// The key setter method has been created if we have trigger methods, ignore it.
continue;
}
propsBuilderClassBuilder.addMethod(generateExtraBuilderMethod(specModel, builderMethodModel));
}
propsBuilderClassBuilder
.addMethod(generateGetThisMethod(specModel))
.addMethod(generateBuildMethod(specModel, numRequiredProps));
return TypeSpecDataHolder.newBuilder().addType(propsBuilderClassBuilder.build()).build();
}