diff --git a/CHANGELOG.md b/CHANGELOG.md index e651519be0..25cf247392 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# 4.0.0-beta3 (May 27, 2020) +- Sort functions in generated kotlin extension function files deterministically to prevent generated sources from changing +- Avoid generating bitset checks in models when not needed +- Add options to skip generation of functions for getters, reset, and method overloads to reduce generated code + +New annotation processor options are: +- epoxyDisableGenerateOverloads +- epoxyDisableGenerateGetters +- epoxyDisableGenerateReset + +These can also be controlled (and overridden) on a per package level with the `PackageModelViewConfig` package annotation. + # 4.0.0-beta1 (May 22, 2020) - Support for incremental annotation processing as an Aggregating processor (#972) - Removed Litho support @@ -19,6 +31,16 @@ Parallel processing can greatly speed up processing time (moreso than the increm Please report any issues or crashes that you notice. (We are currently using parallel mode in our large project at Airbnb with no problems.) +## Breaking +In order to enable incremental annotation processing a change had to be made in how the processor of +`@AutoModel` annotations work. If you use `@AutoModel` in an EpoxyController the annotated Model types +must be either declared in a different module from the EpoxyController, or in the same module in the same java package. + +Also make sure you have kapt error types enabled. + +However, generally `@AutoModel` is considered legacy and is not recommended. It is a relic of Java Epoxy usage +and instead the current best practice is to use Kotlin with the Kotlin model extension functions to build models. + # 3.11.0 (May 20, 2020) - Introduce partial impression visibility states (#973) - Fix sticky header crash (#976) diff --git a/epoxy-annotations/src/main/java/com/airbnb/epoxy/PackageModelViewConfig.java b/epoxy-annotations/src/main/java/com/airbnb/epoxy/PackageModelViewConfig.java index 9428e09f3d..6ee7b56de6 100644 --- a/epoxy-annotations/src/main/java/com/airbnb/epoxy/PackageModelViewConfig.java +++ b/epoxy-annotations/src/main/java/com/airbnb/epoxy/PackageModelViewConfig.java @@ -45,4 +45,47 @@ * Suffix, which will be appended to generated model's names. "Model_" is a default value. */ String generatedModelSuffix() default "Model_"; + + /** + * Controls whether "builder" setter functions that returns the model type will be duplicated + * from super model classes with the function return type updated to use the generated model name. + * This helps make all setters (such as id(...) ) return the same generated model so they can be + * chained in a builder pattern. This is mainly intended for Java usage and is generally + * unnecessary when using models in kotlin, especially if the generated kotlin model + * build extension functions are used. Disabling this can greatly reduce the number of + * methods generated on models. + * + * Default is false. This may also be set project wide with an annotation processor option. + */ + Option disableGenerateBuilderOverloads() default Option.Default; + + /** + * Controls whether getter functions (that return the value of each attribute) are generated + * on models. + * + * Disabling this can greatly reduce the number of methods generated on models. + * + * Default is false. This may also be set project wide with an annotation processor option. + */ + Option disableGenerateGetters() default Option.Default; + + /** + * Controls whether the "reset" function (that clears all attribute values) are generated + * on models. This function is generally legacy and is not recommended to be used with the modern + * immutable model approach of EpoxyControllers. + * + * Disabling this reduces the amount of generated code. + * + * Default is false. This may also be set project wide with an annotation processor option. + */ + Option disableGenerateReset() default Option.Default; + + /** + * Enable or Disable an option, or inherit the default. + */ + enum Option { + Default, + Enabled, + Disabled + } } diff --git a/epoxy-modelfactorytest/src/test/resources/AllTypesModelViewModel_.java b/epoxy-modelfactorytest/src/test/resources/AllTypesModelViewModel_.java index e87e60ee01..94dcbb353f 100644 --- a/epoxy-modelfactorytest/src/test/resources/AllTypesModelViewModel_.java +++ b/epoxy-modelfactorytest/src/test/resources/AllTypesModelViewModel_.java @@ -33,8 +33,6 @@ public class AllTypesModelViewModel_ extends EpoxyModel imple private OnModelVisibilityChangedListener onModelVisibilityChangedListener_epoxyGeneratedModel; - /** - * Bitset index: 0 */ private boolean booleanValue_Boolean = false; /** @@ -52,12 +50,8 @@ public class AllTypesModelViewModel_ extends EpoxyModel imple @NonNull private Double boxedDoubleValue_Double; - /** - * Bitset index: 4 */ private double doubleValue_Double = 0.0d; - /** - * Bitset index: 5 */ @DrawableRes private int drawableRes_Int = 0; @@ -66,8 +60,6 @@ public class AllTypesModelViewModel_ extends EpoxyModel imple @NonNull private List> epoxyModelList_List; - /** - * Bitset index: 7 */ private int intValue_Int = 0; /** @@ -75,8 +67,6 @@ public class AllTypesModelViewModel_ extends EpoxyModel imple @NonNull private Integer boxedIntValue_Integer; - /** - * Bitset index: 9 */ private long longValue_Long = 0L; /** @@ -89,8 +79,6 @@ public class AllTypesModelViewModel_ extends EpoxyModel imple @NonNull private View.OnClickListener onClickListener_OnClickListener; - /** - * Bitset index: 12 */ @RawRes private int rawRes_Int = 0; @@ -326,7 +314,6 @@ public AllTypesModelViewModel_ onVisibilityChanged( * @see AllTypesModelView#setBooleanValue(boolean) */ public AllTypesModelViewModel_ booleanValue(boolean booleanValue) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); this.booleanValue_Boolean = booleanValue; return this; @@ -402,7 +389,6 @@ public Double boxedDoubleValue() { * @see AllTypesModelView#setDoubleValue(double) */ public AllTypesModelViewModel_ doubleValue(double doubleValue) { - assignedAttributes_epoxyGeneratedModel.set(4); onMutation(); this.doubleValue_Double = doubleValue; return this; @@ -418,7 +404,6 @@ public double doubleValue() { * @see AllTypesModelView#setDrawableRes(int) */ public AllTypesModelViewModel_ drawableRes(@DrawableRes int drawableRes) { - assignedAttributes_epoxyGeneratedModel.set(5); onMutation(); this.drawableRes_Int = drawableRes; return this; @@ -456,7 +441,6 @@ public List> epoxyModelList() { * @see AllTypesModelView#setIntValue(int) */ public AllTypesModelViewModel_ intValue(int intValue) { - assignedAttributes_epoxyGeneratedModel.set(7); onMutation(); this.intValue_Int = intValue; return this; @@ -492,7 +476,6 @@ public Integer boxedIntValue() { * @see AllTypesModelView#setLongValue(long) */ public AllTypesModelViewModel_ longValue(long longValue) { - assignedAttributes_epoxyGeneratedModel.set(9); onMutation(); this.longValue_Long = longValue; return this; @@ -563,7 +546,6 @@ public View.OnClickListener onClickListener() { * @see AllTypesModelView#setRawRes(int) */ public AllTypesModelViewModel_ rawRes(@RawRes int rawRes) { - assignedAttributes_epoxyGeneratedModel.set(12); onMutation(); this.rawRes_Int = rawRes; return this; diff --git a/epoxy-modelfactorytest/src/test/resources/CallbackPropModelViewModel_.java b/epoxy-modelfactorytest/src/test/resources/CallbackPropModelViewModel_.java index d6315a4a40..82857e4e5c 100644 --- a/epoxy-modelfactorytest/src/test/resources/CallbackPropModelViewModel_.java +++ b/epoxy-modelfactorytest/src/test/resources/CallbackPropModelViewModel_.java @@ -8,13 +8,10 @@ import java.lang.Object; import java.lang.Override; import java.lang.String; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class CallbackPropModelViewModel_ extends EpoxyModel implements GeneratedModel, CallbackPropModelViewModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(1); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -23,8 +20,6 @@ public class CallbackPropModelViewModel_ extends EpoxyModel onModelVisibilityChangedListener_epoxyGeneratedModel; - /** - * Bitset index: 0 */ @Nullable private View.OnClickListener onClickListener_OnClickListener = (View.OnClickListener) null; @@ -152,7 +147,6 @@ public CallbackPropModelViewModel_ onVisibilityChanged( * Set a click listener that will provide the parent view, model, and adapter position of the clicked view. This will clear the normal View.OnClickListener if one has been set */ public CallbackPropModelViewModel_ onClickListener( @Nullable final OnModelClickListener onClickListener) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); if (onClickListener == null) { this.onClickListener_OnClickListener = null; @@ -170,7 +164,6 @@ public CallbackPropModelViewModel_ onClickListener( */ public CallbackPropModelViewModel_ onClickListener( @Nullable View.OnClickListener onClickListener) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); this.onClickListener_OnClickListener = onClickListener; return this; @@ -261,7 +254,6 @@ public CallbackPropModelViewModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); this.onClickListener_OnClickListener = (View.OnClickListener) null; super.reset(); return this; diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/BaseProcessor.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/BaseProcessor.kt index c22881e42c..5b9ca2993e 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/BaseProcessor.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/BaseProcessor.kt @@ -1,5 +1,15 @@ package com.airbnb.epoxy.processor +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_DISABLE_GENERATE_BUILDER_OVERLOADS +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_DISABLE_GENERATE_GETTERS +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_DISABLE_GENERATE_RESET +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_DISABLE_KOTLIN_EXTENSION_GENERATION +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_ENABLE_PARALLEL +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_IMPLICITLY_ADD_AUTO_MODELS +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_LOG_TIMINGS +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_REQUIRE_ABSTRACT_MODELS +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_REQUIRE_HASHCODE +import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_VALIDATE_MODEL_USAGE import javax.annotation.processing.AbstractProcessor import javax.annotation.processing.Filer import javax.annotation.processing.Messager @@ -77,13 +87,16 @@ abstract class BaseProcessor : AbstractProcessor(), Asyncable { abstract fun supportedAnnotations(): List> override fun getSupportedOptions(): Set = setOf( - ConfigManager.PROCESSOR_OPTION_IMPLICITLY_ADD_AUTO_MODELS, - ConfigManager.PROCESSOR_OPTION_VALIDATE_MODEL_USAGE, - ConfigManager.PROCESSOR_OPTION_REQUIRE_ABSTRACT_MODELS, - ConfigManager.PROCESSOR_OPTION_REQUIRE_HASHCODE, - ConfigManager.PROCESSOR_OPTION_DISABLE_KOTLIN_EXTENSION_GENERATION, - ConfigManager.PROCESSOR_OPTION_LOG_TIMINGS, - ConfigManager.PROCESSOR_OPTION_ENABLE_PARALLEL + PROCESSOR_OPTION_IMPLICITLY_ADD_AUTO_MODELS, + PROCESSOR_OPTION_VALIDATE_MODEL_USAGE, + PROCESSOR_OPTION_REQUIRE_ABSTRACT_MODELS, + PROCESSOR_OPTION_REQUIRE_HASHCODE, + PROCESSOR_OPTION_DISABLE_KOTLIN_EXTENSION_GENERATION, + PROCESSOR_OPTION_LOG_TIMINGS, + PROCESSOR_OPTION_ENABLE_PARALLEL, + PROCESSOR_OPTION_DISABLE_GENERATE_RESET, + PROCESSOR_OPTION_DISABLE_GENERATE_GETTERS, + PROCESSOR_OPTION_DISABLE_GENERATE_BUILDER_OVERLOADS ) override fun init(processingEnv: ProcessingEnvironment) { diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ConfigManager.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ConfigManager.kt index 99363274c8..6d76392789 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ConfigManager.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ConfigManager.kt @@ -27,6 +27,9 @@ class ConfigManager internal constructor( private val globalRequireAbstractModels: Boolean private val globalImplicitlyAddAutoModels: Boolean private val disableKotlinExtensionGeneration: Boolean + private val disableGenerateReset: Boolean + private val disableGenerateGetters: Boolean + private val disableGenerateBuilderOverloads: Boolean val logTimings: Boolean val enableCoroutines: Boolean @@ -71,6 +74,24 @@ class ConfigManager internal constructor( PROCESSOR_OPTION_ENABLE_PARALLEL, defaultValue = false ) + + disableGenerateReset = getBooleanOption( + options, + PROCESSOR_OPTION_DISABLE_GENERATE_RESET, + defaultValue = false + ) + + disableGenerateGetters = getBooleanOption( + options, + PROCESSOR_OPTION_DISABLE_GENERATE_GETTERS, + defaultValue = false + ) + + disableGenerateBuilderOverloads = getBooleanOption( + options, + PROCESSOR_OPTION_DISABLE_GENERATE_BUILDER_OVERLOADS, + defaultValue = false + ) } fun processPackageEpoxyConfig(roundEnv: RoundEnvironment): List { @@ -185,6 +206,11 @@ class ConfigManager internal constructor( */ fun shouldValidateModelUsage(): Boolean = validateModelUsage + fun getModelViewConfig(modelViewInfo: ModelViewInfo?): PackageModelViewSettings? { + if (modelViewInfo == null) return null + return getModelViewConfig(modelViewInfo.viewElement) + } + fun getModelViewConfig(viewElement: Element): PackageModelViewSettings? { val packageName = elementUtils.getPackageOf(viewElement).qualifiedName.toString() return getObjectFromPackageMap( @@ -207,6 +233,21 @@ class ConfigManager internal constructor( ?: GeneratedModelInfo.GENERATED_MODEL_SUFFIX } + fun disableGenerateBuilderOverloads(modelInfo: GeneratedModelInfo): Boolean { + return getModelViewConfig(modelInfo as? ModelViewInfo)?.disableGenerateBuilderOverloads + ?: disableGenerateBuilderOverloads + } + + fun disableGenerateReset(modelInfo: GeneratedModelInfo): Boolean { + return getModelViewConfig(modelInfo as? ModelViewInfo)?.disableGenerateReset + ?: disableGenerateReset + } + + fun disableGenerateGetters(modelInfo: GeneratedModelInfo): Boolean { + return getModelViewConfig(modelInfo as? ModelViewInfo)?.disableGenerateGetters + ?: disableGenerateGetters + } + private fun getConfigurationForElement(element: Element): PackageConfigSettings { return getConfigurationForPackage(elementUtils.getPackageOf(element)) } @@ -225,6 +266,10 @@ class ConfigManager internal constructor( } companion object { + const val PROCESSOR_OPTION_DISABLE_GENERATE_RESET = "epoxyDisableGenerateReset" + const val PROCESSOR_OPTION_DISABLE_GENERATE_GETTERS = "epoxyDisableGenerateGetters" + const val PROCESSOR_OPTION_DISABLE_GENERATE_BUILDER_OVERLOADS = + "epoxyDisableGenerateOverloads" const val PROCESSOR_OPTION_LOG_TIMINGS = "logEpoxyTimings" const val PROCESSOR_OPTION_ENABLE_PARALLEL = "enableParallelEpoxyProcessing" const val PROCESSOR_OPTION_VALIDATE_MODEL_USAGE = "validateEpoxyModelUsage" diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelInfo.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelInfo.kt index 7fe25e0684..b9472503fc 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelInfo.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelInfo.kt @@ -220,6 +220,10 @@ abstract class GeneratedModelInfo(val memoizer: Memoizer) { return attributeToGroup[attribute]?.attributes?.let { it.size > 1 } == true } + fun attributeGroup(attribute: AttributeInfo): AttributeGroup? { + return attributeToGroup[attribute] + } + class AttributeGroup internal constructor( groupName: String?, attributes: List, diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelWriter.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelWriter.kt index fcc84c7747..cd16bf7bb6 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelWriter.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/GeneratedModelWriter.kt @@ -162,7 +162,9 @@ class GeneratedModelWriter( addMethods(generateDefaultMethodImplementations(info)) addMethods(generateOtherLayoutOptions(info)) addMethods(generateDataBindingMethodsIfNeeded(info)) - addMethod(generateReset(info)) + if (!configManager.disableGenerateReset(info)) { + addMethod(generateReset(info)) + } addMethod(generateEquals(info)) addMethod(generateHashCode(info)) addMethod(generateToString(info)) @@ -331,17 +333,17 @@ class GeneratedModelWriter( classInfo.attributeInfo .filter { it.isGenerated } - .mapTo(fields) { - buildField(it.typeName, it.fieldName) { + .mapTo(fields) { attributeInfo -> + buildField(attributeInfo.typeName, attributeInfo.fieldName) { addModifiers(PRIVATE) - addAnnotations(it.setterAnnotations) + addAnnotations(attributeInfo.setterAnnotations) - if (shouldUseBitSet(classInfo)) { - addJavadoc("Bitset index: \$L", attributeIndex(classInfo, it)) + if (shouldUseBitSet(classInfo, attr = attributeInfo)) { + addJavadoc("Bitset index: \$L", attributeIndex(classInfo, attributeInfo)) } - if (it.codeToSetDefault.isPresent) { - initializer(it.codeToSetDefault.value()) + if (attributeInfo.codeToSetDefault.isPresent) { + initializer(attributeInfo.codeToSetDefault.value()) } } } @@ -1000,7 +1002,8 @@ class GeneratedModelWriter( } private fun generateMethodsReturningClassType(info: GeneratedModelInfo): Iterable { - return info.methodsReturningClassType.map { methodInfo -> + return info.methodsReturningClassType.mapNotNull { methodInfo -> + val builder = MethodSpec.methodBuilder(methodInfo.name) .addModifiers(methodInfo.modifiers) .addParameters(methodInfo.params) @@ -1008,12 +1011,12 @@ class GeneratedModelWriter( .varargs(methodInfo.varargs) .returns(info.parameterizedGeneratedName) - if (info.isProgrammaticView && + val isLayoutUnsupportedOverload = info.isProgrammaticView && "layout" == methodInfo.name && methodInfo.params.size == 1 && methodInfo.params[0].type === TypeName.INT - ) { + if (isLayoutUnsupportedOverload) { builder.addStatement( "throw new \$T(\"Layout resources are unsupported with programmatic " + "views.\")", @@ -1034,7 +1037,15 @@ class GeneratedModelWriter( .addStatement("return this") } - builder.build() + if (configManager.disableGenerateBuilderOverloads(info) && !isLayoutUnsupportedOverload) { + // We want to keep the layout overload when it is throwing an UnsupportedOperationException + // because that actually adds new behavior. All other overloads simply call super + // and return "this", which can be disabled when builder chaining is not needed + // (ie with kotlin). + null + } else { + builder.build() + } } } @@ -1338,7 +1349,7 @@ class GeneratedModelWriter( methods.add(generateSetter(modelInfo, attr)) } - if (attr.generateGetter) { + if (attr.generateGetter && !configManager.disableGenerateGetters(modelInfo)) { methods.add(generateGetter(modelInfo, attr)) } } @@ -1877,9 +1888,27 @@ class GeneratedModelWriter( private val GENERATED_FIELD_SUFFIX = "_epoxyGeneratedModel" private val CREATE_NEW_HOLDER_METHOD_NAME = "createNewHolder" private val GET_DEFAULT_LAYOUT_METHOD_NAME = "getDefaultLayout" - val ATTRIBUTES_BITSET_FIELD_NAME = "assignedAttributes" + GENERATED_FIELD_SUFFIX + val ATTRIBUTES_BITSET_FIELD_NAME = "assignedAttributes$GENERATED_FIELD_SUFFIX" + + fun shouldUseBitSet(info: GeneratedModelInfo): Boolean { + return info.attributeInfo.any { shouldUseBitSet(info, it) } + } + + // Avoid generating bitset code for attributes that don't need it. + fun shouldUseBitSet(info: GeneratedModelInfo, attr: AttributeInfo): Boolean { + if (info !is ModelViewInfo) return false + + // We use the bitset to validate if a required attribute had a value set on it + if (attr.isRequired) return true - fun shouldUseBitSet(info: GeneratedModelInfo): Boolean = info is ModelViewInfo + // If the attribute is not generated then we assume that its parent model + // handles its binding. + if (!attr.isGenerated) return false + + // With default values we use the bitset when our bind code needs to conditionally + // check which attribute value to set (either because its in a group or it has a default value) + return ModelViewWriter.hasConditionals(info.attributeGroup(attr)) + } fun isAttributeSetCode( info: GeneratedModelInfo, @@ -1905,7 +1934,7 @@ class GeneratedModelWriter( attr: AttributeInfo, stringSetter: Builder ) { - if (shouldUseBitSet(modelInfo)) { + if (shouldUseBitSet(modelInfo, attr)) { stringSetter.addStatement( "\$L.set(\$L)", ATTRIBUTES_BITSET_FIELD_NAME, attributeIndex(modelInfo, attr) diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/KotlinModelBuilderExtensionWriter.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/KotlinModelBuilderExtensionWriter.kt index dbd1bdb666..fd0e135845 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/KotlinModelBuilderExtensionWriter.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/KotlinModelBuilderExtensionWriter.kt @@ -57,6 +57,10 @@ internal class KotlinModelBuilderExtensionWriter( } } .flatten() + // Sort by function name to keep ordering consistent across builds. Otherwise if the + // processor processes models in differing orders we can have indeterminate source file + // generation which breaks cache keys. + .sortedBy { it.name } .forEach { fileBuilder.addFunction(it) } // We suppress Deprecation warnings for this class in case any of the models used are deprecated. diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewProcessor.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewProcessor.kt index f94ea38742..cbaeaf4fba 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewProcessor.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewProcessor.kt @@ -62,6 +62,8 @@ class ModelViewProcessor : BaseProcessorWithPackageConfigs() { // Up until here our code generation has assumed that that all attributes in a group are // view attributes (and not attributes inherited from a base model class), so this should be // done after grouping attributes, and these attributes should not be grouped. + // No code to bind these attributes is generated, as it is assumed that the original model + // handles its own bind (also we can't know how to bind these). updatesViewsForInheritedBaseModelAttributes() addStyleAttributes() } diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewWriter.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewWriter.kt index 3292f5bd4d..07a78ee342 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewWriter.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewWriter.kt @@ -46,7 +46,7 @@ internal class ModelViewWriter( // If there are multiple attributes, or a default kotlin value, then we need to generate code to // check which properties have been set. - val noConditionals = attrCount == 1 && !attr(0).hasDefaultKotlinValue + val noConditionals = !hasConditionals(attributeGroup) for (i in 0 until attrCount) { val viewAttribute = attr(i) @@ -123,8 +123,7 @@ internal class ModelViewWriter( for (attributeGroup in modelInfo.attributeGroups) { val attributes = attributeGroup.attributes - val noConditionals = attributes.size == 1 && - !(attributes.first() as ViewAttributeInfo).hasDefaultKotlinValue + val noConditionals = !hasConditionals(attributeGroup) methodBuilder.addCode("\n") @@ -398,4 +397,12 @@ internal class ModelViewWriter( methodBuilder.addStatement(boundObjectParam.name + "." + methodName + "()") } } + + companion object { + fun hasConditionals(attributeGroup: GeneratedModelInfo.AttributeGroup?): Boolean { + if (attributeGroup == null) return false + + return attributeGroup.attributes.size > 1 || (attributeGroup.defaultAttribute as ViewAttributeInfo?)?.hasDefaultKotlinValue == true + } + } } diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageModelViewSettings.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageModelViewSettings.kt index 52b916cc27..c6e0906c2e 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageModelViewSettings.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageModelViewSettings.kt @@ -16,6 +16,10 @@ class PackageModelViewSettings( val layoutName: String = annotation.defaultLayoutPattern val includeAlternateLayouts: Boolean = annotation.useLayoutOverloads val generatedModelSuffix: String = annotation.generatedModelSuffix + val disableGenerateBuilderOverloads: Boolean? = + annotation.disableGenerateBuilderOverloads.toBoolean() + val disableGenerateGetters: Boolean? = annotation.disableGenerateGetters.toBoolean() + val disableGenerateReset: Boolean? = annotation.disableGenerateReset.toBoolean() val defaultBaseModel: TypeMirror? by lazy { @@ -41,4 +45,12 @@ class PackageModelViewSettings( val resourceName = layoutName.replace("%s", viewName) return ResourceValue(rClass, resourceName, 0) } + + private fun PackageModelViewConfig.Option.toBoolean(): Boolean? { + return when (this) { + PackageModelViewConfig.Option.Default -> null + PackageModelViewConfig.Option.Enabled -> true + PackageModelViewConfig.Option.Disabled -> false + } + } } diff --git a/epoxy-processortest/src/test/resources/AutoLayoutModelViewMatchParentModel_.java b/epoxy-processortest/src/test/resources/AutoLayoutModelViewMatchParentModel_.java index 8befe63200..b610cfc72a 100644 --- a/epoxy-processortest/src/test/resources/AutoLayoutModelViewMatchParentModel_.java +++ b/epoxy-processortest/src/test/resources/AutoLayoutModelViewMatchParentModel_.java @@ -9,13 +9,10 @@ import java.lang.Override; import java.lang.String; import java.lang.UnsupportedOperationException; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class AutoLayoutModelViewMatchParentModel_ extends EpoxyModel implements GeneratedModel, AutoLayoutModelViewMatchParentModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(1); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -24,8 +21,6 @@ public class AutoLayoutModelViewMatchParentModel_ extends EpoxyModel onModelVisibilityChangedListener_epoxyGeneratedModel; - /** - * Bitset index: 0 */ private int value_Int = 0; @Override @@ -166,7 +161,6 @@ public AutoLayoutModelViewMatchParentModel_ onVisibilityChanged( * @see AutoLayoutModelViewMatchParent#setValue(int) */ public AutoLayoutModelViewMatchParentModel_ value(int value) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); this.value_Int = value; return this; @@ -255,7 +249,6 @@ public AutoLayoutModelViewMatchParentModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); this.value_Int = 0; super.reset(); return this; diff --git a/epoxy-processortest/src/test/resources/AutoLayoutModelViewModel_.java b/epoxy-processortest/src/test/resources/AutoLayoutModelViewModel_.java index 3f4ff1bad0..b945d98bb8 100644 --- a/epoxy-processortest/src/test/resources/AutoLayoutModelViewModel_.java +++ b/epoxy-processortest/src/test/resources/AutoLayoutModelViewModel_.java @@ -9,13 +9,10 @@ import java.lang.Override; import java.lang.String; import java.lang.UnsupportedOperationException; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class AutoLayoutModelViewModel_ extends EpoxyModel implements GeneratedModel, AutoLayoutModelViewModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(1); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -24,8 +21,6 @@ public class AutoLayoutModelViewModel_ extends EpoxyModel i private OnModelVisibilityChangedListener onModelVisibilityChangedListener_epoxyGeneratedModel; - /** - * Bitset index: 0 */ private int value_Int = 0; @Override @@ -165,7 +160,6 @@ public AutoLayoutModelViewModel_ onVisibilityChanged( * @see AutoLayoutModelView#setValue(int) */ public AutoLayoutModelViewModel_ value(int value) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); this.value_Int = value; return this; @@ -253,7 +247,6 @@ public AutoLayoutModelViewModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); this.value_Int = 0; super.reset(); return this; diff --git a/epoxy-processortest/src/test/resources/BaseModelWithAttributeViewModel_.java b/epoxy-processortest/src/test/resources/BaseModelWithAttributeViewModel_.java index 33e7211842..21309ce842 100644 --- a/epoxy-processortest/src/test/resources/BaseModelWithAttributeViewModel_.java +++ b/epoxy-processortest/src/test/resources/BaseModelWithAttributeViewModel_.java @@ -177,7 +177,6 @@ public String clickListener() { } public BaseModelViewModel_ baseModelString(String baseModelString) { - assignedAttributes_epoxyGeneratedModel.set(1); onMutation(); super.baseModelString = baseModelString; return this; diff --git a/epoxy-processortest/src/test/resources/CustomPackageLayoutPatternViewModel_.java b/epoxy-processortest/src/test/resources/CustomPackageLayoutPatternViewModel_.java index 3ea8d5a431..2798e0215b 100644 --- a/epoxy-processortest/src/test/resources/CustomPackageLayoutPatternViewModel_.java +++ b/epoxy-processortest/src/test/resources/CustomPackageLayoutPatternViewModel_.java @@ -7,13 +7,10 @@ import java.lang.Object; import java.lang.Override; import java.lang.String; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class CustomPackageLayoutPatternViewModel_ extends EpoxyModel implements GeneratedModel, CustomPackageLayoutPatternViewModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(0); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -217,7 +214,6 @@ public CustomPackageLayoutPatternViewModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); super.reset(); return this; } diff --git a/epoxy-processortest/src/test/resources/DefaultPackageLayoutPatternViewModel_.java b/epoxy-processortest/src/test/resources/DefaultPackageLayoutPatternViewModel_.java index 029e7aaeb9..4028a83e40 100644 --- a/epoxy-processortest/src/test/resources/DefaultPackageLayoutPatternViewModel_.java +++ b/epoxy-processortest/src/test/resources/DefaultPackageLayoutPatternViewModel_.java @@ -7,13 +7,10 @@ import java.lang.Object; import java.lang.Override; import java.lang.String; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class DefaultPackageLayoutPatternViewModel_ extends EpoxyModel implements GeneratedModel, DefaultPackageLayoutPatternViewModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(0); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -217,7 +214,6 @@ public DefaultPackageLayoutPatternViewModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); super.reset(); return this; } diff --git a/epoxy-processortest/src/test/resources/GeneratedModelSuffixViewSuffix_.java b/epoxy-processortest/src/test/resources/GeneratedModelSuffixViewSuffix_.java index bde7c6d6ee..0d6ba41d94 100644 --- a/epoxy-processortest/src/test/resources/GeneratedModelSuffixViewSuffix_.java +++ b/epoxy-processortest/src/test/resources/GeneratedModelSuffixViewSuffix_.java @@ -7,13 +7,10 @@ import java.lang.Object; import java.lang.Override; import java.lang.String; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class GeneratedModelSuffixViewSuffix_ extends EpoxyModel implements GeneratedModel, GeneratedModelSuffixViewSuffixBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(0); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -216,7 +213,6 @@ public GeneratedModelSuffixViewSuffix_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); super.reset(); return this; } diff --git a/epoxy-processortest/src/test/resources/LayoutOverloadsViewModel_.java b/epoxy-processortest/src/test/resources/LayoutOverloadsViewModel_.java index 021eaf28e0..0bd7dc47c6 100644 --- a/epoxy-processortest/src/test/resources/LayoutOverloadsViewModel_.java +++ b/epoxy-processortest/src/test/resources/LayoutOverloadsViewModel_.java @@ -7,13 +7,10 @@ import java.lang.Object; import java.lang.Override; import java.lang.String; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class LayoutOverloadsViewModel_ extends EpoxyModel implements GeneratedModel, LayoutOverloadsViewModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(0); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -225,7 +222,6 @@ public LayoutOverloadsViewModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); super.reset(); return this; } diff --git a/epoxy-processortest/src/test/resources/ModelViewExtendingSuperClassModel_.java b/epoxy-processortest/src/test/resources/ModelViewExtendingSuperClassModel_.java index cd7893c606..de075e3379 100644 --- a/epoxy-processortest/src/test/resources/ModelViewExtendingSuperClassModel_.java +++ b/epoxy-processortest/src/test/resources/ModelViewExtendingSuperClassModel_.java @@ -9,13 +9,10 @@ import java.lang.Override; import java.lang.String; import java.lang.UnsupportedOperationException; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class ModelViewExtendingSuperClassModel_ extends EpoxyModel implements GeneratedModel, ModelViewExtendingSuperClassModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(2); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -24,12 +21,8 @@ public class ModelViewExtendingSuperClassModel_ extends EpoxyModel onModelVisibilityChangedListener_epoxyGeneratedModel; - /** - * Bitset index: 0 */ private int subClassValue_Int = 0; - /** - * Bitset index: 1 */ private int superClassValue_Int = 0; @Override @@ -179,7 +172,6 @@ public ModelViewExtendingSuperClassModel_ onVisibilityChanged( * @see ModelViewExtendingSuperClass#subClassValue(int) */ public ModelViewExtendingSuperClassModel_ subClassValue(int subClassValue) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); this.subClassValue_Int = subClassValue; return this; @@ -195,7 +187,6 @@ public int subClassValue() { * @see ModelViewExtendingSuperClass#superClassValue(int) */ public ModelViewExtendingSuperClassModel_ superClassValue(int superClassValue) { - assignedAttributes_epoxyGeneratedModel.set(1); onMutation(); this.superClassValue_Int = superClassValue; return this; @@ -284,7 +275,6 @@ public ModelViewExtendingSuperClassModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); this.subClassValue_Int = 0; this.superClassValue_Int = 0; super.reset(); diff --git a/epoxy-processortest/src/test/resources/ModelViewSuperClassModel_.java b/epoxy-processortest/src/test/resources/ModelViewSuperClassModel_.java index 9c15f044c1..44774f3bc8 100644 --- a/epoxy-processortest/src/test/resources/ModelViewSuperClassModel_.java +++ b/epoxy-processortest/src/test/resources/ModelViewSuperClassModel_.java @@ -9,13 +9,10 @@ import java.lang.Override; import java.lang.String; import java.lang.UnsupportedOperationException; -import java.util.BitSet; /** * Generated file. Do not modify! */ public class ModelViewSuperClassModel_ extends EpoxyModel implements GeneratedModel, ModelViewSuperClassModelBuilder { - private final BitSet assignedAttributes_epoxyGeneratedModel = new BitSet(1); - private OnModelBoundListener onModelBoundListener_epoxyGeneratedModel; private OnModelUnboundListener onModelUnboundListener_epoxyGeneratedModel; @@ -24,8 +21,6 @@ public class ModelViewSuperClassModel_ extends EpoxyModel i private OnModelVisibilityChangedListener onModelVisibilityChangedListener_epoxyGeneratedModel; - /** - * Bitset index: 0 */ private int superClassValue_Int = 0; @Override @@ -167,7 +162,6 @@ public ModelViewSuperClassModel_ onVisibilityChanged( * @see ModelViewSuperClass#superClassValue(int) */ public ModelViewSuperClassModel_ superClassValue(int superClassValue) { - assignedAttributes_epoxyGeneratedModel.set(0); onMutation(); this.superClassValue_Int = superClassValue; return this; @@ -255,7 +249,6 @@ public ModelViewSuperClassModel_ reset() { onModelUnboundListener_epoxyGeneratedModel = null; onModelVisibilityStateChangedListener_epoxyGeneratedModel = null; onModelVisibilityChangedListener_epoxyGeneratedModel = null; - assignedAttributes_epoxyGeneratedModel.clear(); this.superClassValue_Int = 0; super.reset(); return this; diff --git a/epoxy-processortest/src/test/resources/ModelViewWithParisModel_.java b/epoxy-processortest/src/test/resources/ModelViewWithParisModel_.java index 2f33349f82..27ed54e5a6 100644 --- a/epoxy-processortest/src/test/resources/ModelViewWithParisModel_.java +++ b/epoxy-processortest/src/test/resources/ModelViewWithParisModel_.java @@ -17,7 +17,6 @@ import java.lang.String; import java.lang.UnsupportedOperationException; import java.lang.ref.WeakReference; -import java.util.BitSet; import java.util.Objects; /** @@ -31,8 +30,6 @@ public class ModelViewWithParisModel_ extends EpoxyModel imp private static WeakReference