/** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.specmodels.generator; import javax.lang.model.element.Modifier; import com.facebook.litho.specmodels.model.SpecModel; import com.squareup.javapoet.FieldSpec; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeName; import static com.facebook.litho.specmodels.generator.GeneratorConstants.DELEGATE_FIELD_NAME; import static com.facebook.litho.specmodels.generator.GeneratorConstants.SPEC_INSTANCE_NAME; /** * Class that generates the preamble for a Component. */ public class PreambleGenerator { private PreambleGenerator() { } public static TypeSpecDataHolder generate(SpecModel specModel) { return TypeSpecDataHolder.newBuilder() .addTypeSpecDataHolder(generateSourceDelegate(specModel)) .addTypeSpecDataHolder(generateConstructor(specModel)) .addTypeSpecDataHolder(generateGetter(specModel)) .build(); } /** * Generate a delegate to the Spec that defines this component. */ static TypeSpecDataHolder generateSourceDelegate(SpecModel specModel) { if (!specModel.hasInjectedDependencies()) { return TypeSpecDataHolder.newBuilder().build(); } final TypeName delegateTypeName = specModel.getDependencyInjectionHelper().getSourceDelegateTypeName(specModel); final FieldSpec.Builder builder = FieldSpec.builder(delegateTypeName, DELEGATE_FIELD_NAME) .addModifiers(Modifier.PRIVATE); return TypeSpecDataHolder.newBuilder().addField(builder.build()).build(); } /** * If the spec has injected dependencies, generate a DI constructor. Otherwise, generate a * private constructor to enforce singleton-ity. */ static TypeSpecDataHolder generateConstructor(SpecModel specModel) { final TypeSpecDataHolder.Builder typeSpecDataHolder = TypeSpecDataHolder.newBuilder(); if (specModel.hasInjectedDependencies()) { typeSpecDataHolder.addMethod( specModel.getDependencyInjectionHelper().generateConstructor(specModel)); } else { typeSpecDataHolder.addMethod( MethodSpec.constructorBuilder() .addModifiers(Modifier.PRIVATE) .build()); } return typeSpecDataHolder.build(); } /** * Generate a method for this component which either lazily instantiates a singleton reference or * returns this depending upon whether this spec injects dependencies or not. */ static TypeSpecDataHolder generateGetter(SpecModel specModel) { final TypeSpecDataHolder.Builder typeSpecDataHolder = TypeSpecDataHolder.newBuilder(); if (!specModel.hasInjectedDependencies()) { typeSpecDataHolder.addField( FieldSpec .builder( specModel.getComponentTypeName(), SPEC_INSTANCE_NAME, Modifier.PRIVATE, Modifier.STATIC) .initializer("null") .build()); typeSpecDataHolder.addMethod( MethodSpec.methodBuilder("get") .addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.STATIC) .addModifiers(Modifier.SYNCHRONIZED) .returns(specModel.getComponentTypeName()) .beginControlFlow("if ($L == null)", SPEC_INSTANCE_NAME) .addStatement("$L = new $T()", SPEC_INSTANCE_NAME, specModel.getComponentTypeName()) .endControlFlow() .addStatement("return $L", SPEC_INSTANCE_NAME) .build()); } else { typeSpecDataHolder.addMethod( MethodSpec.methodBuilder("get") .addModifiers(Modifier.PUBLIC) .returns(specModel.getComponentTypeName()) .addStatement("return this") .build()); } return typeSpecDataHolder.build(); } }