diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aa066613f..595b154067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +# 4.0.0-beta5 (July 9, 2020) +Fixes: +- An occasional processor crash when the option to log timings is enabled +- Incremental annotation processing of databinding models would fail to generate models (#1014) + +Breaking! +- The annotation that support databinding, `EpoxyDataBindingLayouts` and `EpoxyDataBindingPattern`, +must now be placed on a class or interface instead of in a `package-info.java` file. The interface +or class must be in Java, Kotlin is not supported. This is necessary to support incremental processing. + +Example usage: +```java +package com.example.app; + +import com.airbnb.epoxy.EpoxyDataBindingLayouts; +import com.airbnb.epoxy.EpoxyDataBindingPattern; + +@EpoxyDataBindingPattern(rClass = R.class, layoutPrefix = "my_view_prefix") +@EpoxyDataBindingLayouts({R.layout.my_model_layout}) +interface EpoxyDataBindingConfig {} +``` + # 4.0.0-beta4 (June 1, 2020) Fixes: - Synchronize ListUpdateCallback and PagedListModelCache functions (#987) diff --git a/blessedDeps.gradle b/blessedDeps.gradle index fdc3679bbb..60472d39a5 100644 --- a/blessedDeps.gradle +++ b/blessedDeps.gradle @@ -45,10 +45,10 @@ rootProject.ext.ROBOLECTRIC_VERSION = "4.3" rootProject.ext.LOTTIE_VERSION = "2.8.0" rootProject.ext.SO_LOADER_VERSION = "0.2.0" -rootProject.ext.AUTO_VALUE_VERSION = "1.6.2" +rootProject.ext.AUTO_VALUE_VERSION = "1.7.4" rootProject.ext.ANDROID_RUNTIME_VERSION = "4.1.1.4" -rootProject.ext.PARIS_VERSION = "1.2.1" +rootProject.ext.PARIS_VERSION = "1.5.0" rootProject.ext.INCAP_VERSION = "0.2" rootProject.ext.KOTLIN_METADATA_VERSION = "1.4.0" diff --git a/build.gradle b/build.gradle index 1bd0a9d118..793d514f6b 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ buildscript { } plugins { - id 'com.github.ben-manes.versions' version '0.20.0' + id 'com.github.ben-manes.versions' version '0.28.0' } allprojects { diff --git a/epoxy-adapter/src/main/java/com/airbnb/epoxy/WrappedEpoxyModelClickListener.kt b/epoxy-adapter/src/main/java/com/airbnb/epoxy/WrappedEpoxyModelClickListener.kt index e56939ed2b..68a06d6c8c 100644 --- a/epoxy-adapter/src/main/java/com/airbnb/epoxy/WrappedEpoxyModelClickListener.kt +++ b/epoxy-adapter/src/main/java/com/airbnb/epoxy/WrappedEpoxyModelClickListener.kt @@ -133,8 +133,8 @@ class WrappedEpoxyModelClickListener, V> : OnClickListener, On } if (if (originalClickListener != null) { - originalClickListener != other.originalClickListener - } else { + originalClickListener != other.originalClickListener + } else { other.originalClickListener != null } ) { diff --git a/epoxy-adapter/src/main/java/com/airbnb/epoxy/stickyheader/StickyHeaderLinearLayoutManager.kt b/epoxy-adapter/src/main/java/com/airbnb/epoxy/stickyheader/StickyHeaderLinearLayoutManager.kt index f362d2eaec..5589d13140 100644 --- a/epoxy-adapter/src/main/java/com/airbnb/epoxy/stickyheader/StickyHeaderLinearLayoutManager.kt +++ b/epoxy-adapter/src/main/java/com/airbnb/epoxy/stickyheader/StickyHeaderLinearLayoutManager.kt @@ -241,7 +241,8 @@ class StickyHeaderLinearLayoutManager @JvmOverloads constructor( // - Isn't followed by another sticky header; if (headerPos != -1 && (headerPos != anchorPos || isViewOnBoundary(anchorView)) && - nextHeaderPos != headerPos + 1) { + nextHeaderPos != headerPos + 1 + ) { // 1. Ensure existing sticky header, if any, is of correct type. if (stickyHeader != null && getItemViewType(stickyHeader!!) != adapter?.getItemViewType(headerPos)) { // A sticky header was shown before but is not of the correct type. Scrap it. diff --git a/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyModelGroupTest.kt b/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyModelGroupTest.kt index 5f78206b19..5ddadd2104 100644 --- a/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyModelGroupTest.kt +++ b/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyModelGroupTest.kt @@ -134,25 +134,35 @@ class EpoxyModelGroupTest(val useViewStubs: Boolean) { public override fun buildView(parent: ViewGroup): View { return LinearLayout(parent.context).apply { - addView(ViewStub(parent.context).apply { - inflatedId = 0 - }) - - addView(LinearLayout(parent.context).apply { - addView(ViewStub(parent.context).apply { - inflatedId = 1 - }) - - addView(Space(parent.context)) - - addView(ViewStub(parent.context).apply { - inflatedId = 2 - }) - }) - - addView(ViewStub(parent.context).apply { - inflatedId = 3 - }) + addView( + ViewStub(parent.context).apply { + inflatedId = 0 + } + ) + + addView( + LinearLayout(parent.context).apply { + addView( + ViewStub(parent.context).apply { + inflatedId = 1 + } + ) + + addView(Space(parent.context)) + + addView( + ViewStub(parent.context).apply { + inflatedId = 2 + } + ) + } + ) + + addView( + ViewStub(parent.context).apply { + inflatedId = 3 + } + ) } } } diff --git a/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerNestedTest.kt b/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerNestedTest.kt index fe6bc8b51f..a2f9f01776 100644 --- a/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerNestedTest.kt +++ b/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerNestedTest.kt @@ -208,11 +208,13 @@ class EpoxyVisibilityTrackerNestedTest { // Build a test sample of sampleSize items val helpers = mutableListOf>().apply { for (i in 0 until verticalSampleSize) { - add(mutableListOf().apply { - for (j in 0 until horizontalSampleSize) { - add(AssertHelper(ids++)) + add( + mutableListOf().apply { + for (j in 0 until horizontalSampleSize) { + add(AssertHelper(ids++)) + } } - }) + ) } } log(helpers.ids()) @@ -226,35 +228,37 @@ class EpoxyVisibilityTrackerNestedTest { @Before fun setup() { Robolectric.setupActivity(Activity::class.java).apply { - setContentView(EpoxyRecyclerView(this).apply { - epoxyVisibilityTracker.attach(this) - recyclerView = this - // Plug an epoxy controller - epoxyController = object : TypedEpoxyController>>() { - override fun buildModels(data: List>?) { - data?.forEachIndexed { index, helpers -> - val models = mutableListOf>() - helpers.forEach { helper -> - models.add( - TrackerTestModel( - itemPosition = index, - itemHeight = itemHeight, - itemWidth = itemWidth, - helper = helper - ).id("$index-${helper.id}") + setContentView( + EpoxyRecyclerView(this).apply { + epoxyVisibilityTracker.attach(this) + recyclerView = this + // Plug an epoxy controller + epoxyController = object : TypedEpoxyController>>() { + override fun buildModels(data: List>?) { + data?.forEachIndexed { index, helpers -> + val models = mutableListOf>() + helpers.forEach { helper -> + models.add( + TrackerTestModel( + itemPosition = index, + itemHeight = itemHeight, + itemWidth = itemWidth, + helper = helper + ).id("$index-${helper.id}") + ) + } + add( + CarouselModel_() + .id(index) + .paddingDp(0) + .models(models) ) } - add( - CarouselModel_() - .id(index) - .paddingDp(0) - .models(models) - ) } } + recyclerView.adapter = epoxyController.adapter } - recyclerView.adapter = epoxyController.adapter - }) + ) viewportHeight = recyclerView.measuredHeight activity = this } diff --git a/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerTest.kt b/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerTest.kt index 2d6bec9428..047de2730b 100644 --- a/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerTest.kt +++ b/epoxy-adapter/src/test/java/com/airbnb/epoxy/EpoxyVisibilityTrackerTest.kt @@ -881,26 +881,28 @@ class EpoxyVisibilityTrackerTest { @Before fun setup() { Robolectric.setupActivity(Activity::class.java).apply { - setContentView(EpoxyRecyclerView(this).apply { - epoxyVisibilityTracker.setPartialImpressionThresholdPercentage(50) - epoxyVisibilityTracker.attach(this) - recyclerView = this - // Plug an epoxy controller - epoxyController = object : TypedEpoxyController>() { - override fun buildModels(data: List?) { - data?.forEachIndexed { index, helper -> - add( - TrackerTestModel( - itemPosition = index, - itemHeight = itemHeight, - helper = helper - ).id(helper.id) - ) + setContentView( + EpoxyRecyclerView(this).apply { + epoxyVisibilityTracker.setPartialImpressionThresholdPercentage(50) + epoxyVisibilityTracker.attach(this) + recyclerView = this + // Plug an epoxy controller + epoxyController = object : TypedEpoxyController>() { + override fun buildModels(data: List?) { + data?.forEachIndexed { index, helper -> + add( + TrackerTestModel( + itemPosition = index, + itemHeight = itemHeight, + helper = helper + ).id(helper.id) + ) + } } } + recyclerView.adapter = epoxyController.adapter } - recyclerView.adapter = epoxyController.adapter - }) + ) viewportHeight = recyclerView.measuredHeight activity = this } diff --git a/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingLayouts.java b/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingLayouts.java index b776655d2a..2778481db3 100644 --- a/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingLayouts.java +++ b/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingLayouts.java @@ -18,7 +18,7 @@ * Alternatively you can use {@link EpoxyDataBindingPattern} to avoid explicitly declaring each * layout. */ -@Target(ElementType.PACKAGE) +@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface EpoxyDataBindingLayouts { /** A list of databinding layout resources that should have EpoxyModel's generated for them. */ diff --git a/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingPattern.java b/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingPattern.java index c4f42d3cf8..6954823387 100644 --- a/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingPattern.java +++ b/epoxy-annotations/src/main/java/com/airbnb/epoxy/EpoxyDataBindingPattern.java @@ -13,7 +13,7 @@ * The layouts must not specify a custom databinding class name or package via the * class="com.example.CustomClassName" override in the layout xml. */ -@Target(ElementType.PACKAGE) +@Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) public @interface EpoxyDataBindingPattern { /** diff --git a/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/package-info.java b/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/EpoxyDataBindingConfig.java similarity index 87% rename from epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/package-info.java rename to epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/EpoxyDataBindingConfig.java index 17acbc07c0..dbf227b37a 100644 --- a/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/package-info.java +++ b/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/EpoxyDataBindingConfig.java @@ -1,6 +1,8 @@ -@EpoxyDataBindingPattern(rClass = R.class, layoutPrefix = "view_holder") -@EpoxyDataBindingLayouts({R.layout.model_with_data_binding}) package com.airbnb.epoxy.integrationtest; import com.airbnb.epoxy.EpoxyDataBindingLayouts; import com.airbnb.epoxy.EpoxyDataBindingPattern; + +@EpoxyDataBindingPattern(rClass = R.class, layoutPrefix = "view_holder") +@EpoxyDataBindingLayouts({R.layout.model_with_data_binding}) +interface EpoxyDataBindingConfig {} diff --git a/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithInterface.kt b/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithInterface.kt index 7c06191e29..fc7d95f741 100644 --- a/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithInterface.kt +++ b/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithInterface.kt @@ -10,8 +10,12 @@ import com.airbnb.epoxy.ModelView.Size import com.airbnb.epoxy.TextProp @ModelView(autoLayout = Size.WRAP_WIDTH_MATCH_HEIGHT) -class ViewWithInterface(context: Context) : View(context), InterfaceForView, InterfaceForView2, - ClassWithNestedInterface.NestedInterface, InterfaceWithNoPropMethods { +class ViewWithInterface(context: Context) : + View(context), + InterfaceForView, + InterfaceForView2, + ClassWithNestedInterface.NestedInterface, + InterfaceWithNoPropMethods { override fun getSomething() = 5 diff --git a/epoxy-paging/src/androidTest/java/com/airbnb/epoxy/paging/PagedListModelCacheTest.kt b/epoxy-paging/src/androidTest/java/com/airbnb/epoxy/paging/PagedListModelCacheTest.kt index d66435452c..1fd2a73fa5 100644 --- a/epoxy-paging/src/androidTest/java/com/airbnb/epoxy/paging/PagedListModelCacheTest.kt +++ b/epoxy-paging/src/androidTest/java/com/airbnb/epoxy/paging/PagedListModelCacheTest.kt @@ -23,14 +23,14 @@ import android.view.View import androidx.paging.PagedList import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyModel -import java.util.concurrent.Executor -import java.util.concurrent.TimeUnit import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.`is` import org.hamcrest.MatcherAssert.assertThat import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import java.util.concurrent.Executor +import java.util.concurrent.TimeUnit @RunWith(AndroidJUnit4::class) class PagedListModelCacheTest { @@ -317,7 +317,8 @@ class PagedListModelCacheTest { private fun createPagedList(items: List): Pair, ListDataSource> { val dataSource = ListDataSource(items) val pagedList = PagedList.Builder( - dataSource, PagedList.Config.Builder() + dataSource, + PagedList.Config.Builder() .setEnablePlaceholders(true) .setInitialLoadSizeHint(PAGE_SIZE * 2) .setPageSize(PAGE_SIZE) diff --git a/epoxy-paging/src/main/java/com/airbnb/epoxy/paging/PagedListModelCache.kt b/epoxy-paging/src/main/java/com/airbnb/epoxy/paging/PagedListModelCache.kt index 17876a6a37..0458f9879e 100644 --- a/epoxy-paging/src/main/java/com/airbnb/epoxy/paging/PagedListModelCache.kt +++ b/epoxy-paging/src/main/java/com/airbnb/epoxy/paging/PagedListModelCache.kt @@ -156,9 +156,12 @@ internal class PagedListModelCache( val mainThreadExecutorField = AsyncPagedListDiffer::class.java.getDeclaredField("mMainThreadExecutor") mainThreadExecutorField.isAccessible = true - mainThreadExecutorField.set(this, Executor { - modelBuildingHandler.post(it) - }) + mainThreadExecutorField.set( + this, + Executor { + modelBuildingHandler.post(it) + } + ) } catch (t: Throwable) { val msg = "Failed to hijack update handler in AsyncPagedListDiffer." + "You can only build models on the main thread" diff --git a/epoxy-pagingsample/src/main/java/com/airbnb/epoxy/pagingsample/PagingSampleActivity.kt b/epoxy-pagingsample/src/main/java/com/airbnb/epoxy/pagingsample/PagingSampleActivity.kt index b4ccf19fb4..250a964293 100644 --- a/epoxy-pagingsample/src/main/java/com/airbnb/epoxy/pagingsample/PagingSampleActivity.kt +++ b/epoxy-pagingsample/src/main/java/com/airbnb/epoxy/pagingsample/PagingSampleActivity.kt @@ -34,9 +34,12 @@ class PagingSampleActivity : AppCompatActivity() { recyclerView.adapter = pagingController.adapter val viewModel = ViewModelProviders.of(this).get(ActivityViewModel::class.java) - viewModel.pagedList.observe(this, Observer { - pagingController.submitList(it) - }) + viewModel.pagedList.observe( + this, + Observer { + pagingController.submitList(it) + } + ) } } diff --git a/epoxy-preloadersample/src/main/java/com/airbnb/epoxy/preloadersample/KotlinHolder.kt b/epoxy-preloadersample/src/main/java/com/airbnb/epoxy/preloadersample/KotlinHolder.kt index a3e9960bae..b1f678ad14 100644 --- a/epoxy-preloadersample/src/main/java/com/airbnb/epoxy/preloadersample/KotlinHolder.kt +++ b/epoxy-preloadersample/src/main/java/com/airbnb/epoxy/preloadersample/KotlinHolder.kt @@ -19,10 +19,10 @@ abstract class KotlinHolder : EpoxyHolder() { } protected fun bind(id: Int): ReadOnlyProperty = - Lazy { holder: KotlinHolder, prop -> - holder.view.findViewById(id) as V? - ?: throw IllegalStateException("View ID $id for '${prop.name}' not found.") - } + Lazy { holder: KotlinHolder, prop -> + holder.view.findViewById(id) as V? + ?: throw IllegalStateException("View ID $id for '${prop.name}' not found.") + } /** * Taken from Kotterknife. diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/AttributeInfo.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/AttributeInfo.kt index dec00829bd..627da15454 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/AttributeInfo.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/AttributeInfo.kt @@ -200,11 +200,13 @@ abstract class AttributeInfo : Comparable { open fun generatedGetterName(isOverload: Boolean): String = fieldName override fun toString(): String { - return ("Attribute {" + - "model='" + rootClass + '\''.toString() + - ", name='" + fieldName + '\''.toString() + - ", type=" + typeName + - '}'.toString()) + return ( + "Attribute {" + + "model='" + rootClass + '\''.toString() + + ", name='" + fieldName + '\''.toString() + + ", type=" + typeName + + '}'.toString() + ) } override fun equals(other: Any?): Boolean { 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 5b9ca2993e..3f4046a29a 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 @@ -10,6 +10,12 @@ import com.airbnb.epoxy.processor.ConfigManager.Companion.PROCESSOR_OPTION_LOG_T 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 kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.runBlocking import javax.annotation.processing.AbstractProcessor import javax.annotation.processing.Filer import javax.annotation.processing.Messager @@ -21,12 +27,6 @@ import javax.lang.model.element.TypeElement import javax.lang.model.util.Elements import javax.lang.model.util.Types import kotlin.reflect.KClass -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.runBlocking abstract class BaseProcessor : AbstractProcessor(), Asyncable { 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 6d76392789..a2e625a951 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 @@ -183,13 +183,17 @@ class ConfigManager internal constructor( } fun requiresAbstractModels(classElement: TypeElement): Boolean { - return (globalRequireAbstractModels || - getConfigurationForElement(classElement).requireAbstractModels) + return ( + globalRequireAbstractModels || + getConfigurationForElement(classElement).requireAbstractModels + ) } fun implicitlyAddAutoModels(controller: ControllerClassInfo): Boolean { - return (globalImplicitlyAddAutoModels || - getConfigurationForElement(controller.controllerClassElement).implicitlyAddAutoModels) + return ( + globalImplicitlyAddAutoModels || + getConfigurationForElement(controller.controllerClassElement).implicitlyAddAutoModels + ) } fun disableKotlinExtensionGeneration(): Boolean = disableKotlinExtensionGeneration diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ControllerProcessor.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ControllerProcessor.kt index 755486a6bc..a8b1128947 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ControllerProcessor.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ControllerProcessor.kt @@ -9,6 +9,8 @@ import com.squareup.javapoet.ParameterSpec import com.squareup.javapoet.ParameterizedTypeName import com.squareup.javapoet.TypeName import com.squareup.javapoet.TypeSpec +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor +import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType import java.util.ArrayList import java.util.LinkedHashMap import javax.annotation.processing.RoundEnvironment @@ -17,8 +19,6 @@ import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement import javax.lang.model.type.TypeKind import kotlin.reflect.KClass -import net.ltgt.gradle.incap.IncrementalAnnotationProcessor -import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType // TODO: This could be an isolating processor except that the PackageEpoxyConfig annotation // can change the `implicitlyAddAutoModels` setting. @@ -83,10 +83,10 @@ class ControllerProcessor : BaseProcessorWithPackageConfigs() { } val otherControllerModelFields: Set = controllerInfo.models if (Utils.belongToTheSamePackage( - thisClass, - otherClass, - elementUtils - ) + thisClass, + otherClass, + elementUtils + ) ) { value.addModels(otherControllerModelFields) } else { @@ -159,7 +159,7 @@ class ControllerProcessor : BaseProcessorWithPackageConfigs() { .imports .firstOrNull { it.endsWith(simpleName) } ?.substringBeforeLast(".$simpleName") - // With no import we assume the model is in the same package as the controller + // With no import we assume the model is in the same package as the controller ?: controllerClass.generatedClassName.packageName() ClassName.get(packageName, simpleName) diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingModelInfo.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingModelInfo.kt index 8fd1a89784..41f044fe2d 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingModelInfo.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingModelInfo.kt @@ -70,7 +70,8 @@ internal class DataBindingModelInfo( layoutResource: ResourceValue, moduleName: String ): ClassName { - val modelName = layoutResource.resourceName!!.toUpperCamelCase().plus(BINDING_SUFFIX) + val modelName = layoutResource.resourceName?.toUpperCamelCase()?.plus(BINDING_SUFFIX) + ?: error("Resource name not found for layout: ${layoutResource.debugDetails()}") return ClassName.get("$moduleName.databinding", modelName) } diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingProcessor.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingProcessor.kt index 9926c05336..26b7fe7c2f 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingProcessor.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/DataBindingProcessor.kt @@ -4,12 +4,12 @@ import com.airbnb.epoxy.EpoxyDataBindingLayouts import com.airbnb.epoxy.EpoxyDataBindingPattern import com.airbnb.epoxy.processor.Utils.getClassParamFromAnnotation import com.squareup.javapoet.ClassName +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor +import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType import java.util.Collections import javax.annotation.processing.RoundEnvironment import javax.lang.model.element.VariableElement import kotlin.reflect.KClass -import net.ltgt.gradle.incap.IncrementalAnnotationProcessor -import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType @IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.AGGREGATING) class DataBindingProcessor : BaseProcessor() { diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/EpoxyProcessor.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/EpoxyProcessor.kt index 89a9fb6e86..3d750e981a 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/EpoxyProcessor.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/EpoxyProcessor.kt @@ -2,6 +2,8 @@ package com.airbnb.epoxy.processor import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor +import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType import java.util.LinkedHashMap import java.util.concurrent.ConcurrentHashMap import javax.annotation.processing.RoundEnvironment @@ -11,8 +13,6 @@ import javax.lang.model.element.TypeElement import javax.lang.model.util.Elements import javax.lang.model.util.Types import kotlin.reflect.KClass -import net.ltgt.gradle.incap.IncrementalAnnotationProcessor -import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType /** * Looks for [EpoxyAttribute] annotations and generates a subclass for all classes that have @@ -140,8 +140,8 @@ class EpoxyProcessor : BaseProcessorWithPackageConfigs() { } if (configManager.requiresAbstractModels(classElement) && !classElement.modifiers.contains( - Modifier.ABSTRACT - ) + Modifier.ABSTRACT + ) ) { logger .logError( 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 b9472503fc..1cea5e9352 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 @@ -158,10 +158,12 @@ abstract class GeneratedModelInfo(val memoizer: Memoizer) { ) override fun toString(): String { - return ("GeneratedModelInfo{" + - "attributeInfo=" + attributeInfo + - ", superClassName=" + superClassName + - '}') + return ( + "GeneratedModelInfo{" + + "attributeInfo=" + attributeInfo + + ", superClassName=" + superClassName + + '}' + ) } @Throws(EpoxyProcessorException::class) 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 cd16bf7bb6..2bf07d958a 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 @@ -205,18 +205,22 @@ class GeneratedModelWriter( } var layoutDescription = "" - for (namePart in otherLayout.resourceName!!.substring(defaultLayoutNameLength).split( - "_".toRegex() - ).dropLastWhile { it.isEmpty() }) { + for ( + namePart in otherLayout.resourceName!!.substring(defaultLayoutNameLength).split( + "_".toRegex() + ).dropLastWhile { it.isEmpty() } + ) { layoutDescription += Utils.capitalizeFirstLetter(namePart) } - result.add(buildMethod("with" + layoutDescription + "Layout") { - returns(info.parameterizedGeneratedName) - addModifiers(PUBLIC) - addStatement("layout(\$L)", otherLayout.code) - addStatement("return this") - }) + result.add( + buildMethod("with" + layoutDescription + "Layout") { + returns(info.parameterizedGeneratedName) + addModifiers(PUBLIC) + addStatement("layout(\$L)", otherLayout.code) + addStatement("return this") + } + ) } return result @@ -245,7 +249,8 @@ class GeneratedModelWriter( "new \$T().addDefault().build()", styleBuilderInfo.styleBuilderClass ) - }) + } + ) // We store styles in a weak reference since if a controller uses it // once it is likely to be used in other models and when models are rebuilt @@ -278,7 +283,8 @@ class GeneratedModelWriter( "new \$T(\$L)", BitSet::class.java, classInfo.attributeInfo.size ) - }) + } + ) } // Add fields for the bind/unbind listeners @@ -457,33 +463,37 @@ class GeneratedModelWriter( val methods = ArrayList() // getViewType method so that view type is generated at runtime - methods.add(buildMethod("getViewType") { - addAnnotation(Override::class.java) - addModifiers(PROTECTED) - returns(TypeName.INT) - addStatement("return 0", modelInfo.modelType) - }) + methods.add( + buildMethod("getViewType") { + addAnnotation(Override::class.java) + addModifiers(PROTECTED) + returns(TypeName.INT) + addStatement("return 0", modelInfo.modelType) + } + ) // buildView method to return new view instance - methods.add(buildMethod("buildView") { - addAnnotation(Override::class.java) - addParameter(ClassNames.ANDROID_VIEW_GROUP, "parent") - addModifiers(PROTECTED) - returns(modelInfo.modelType) - addStatement( - "\$T v = new \$T(parent.getContext())", modelInfo.modelType, - modelInfo.modelType - ) + methods.add( + buildMethod("buildView") { + addAnnotation(Override::class.java) + addParameter(ClassNames.ANDROID_VIEW_GROUP, "parent") + addModifiers(PROTECTED) + returns(modelInfo.modelType) + addStatement( + "\$T v = new \$T(parent.getContext())", modelInfo.modelType, + modelInfo.modelType + ) - val (layoutWidth, layoutHeight) = getLayoutDimensions(modelInfo) + val (layoutWidth, layoutHeight) = getLayoutDimensions(modelInfo) - addStatement( - "v.setLayoutParams(new \$T(\$L, \$L))", - ClassNames.ANDROID_MARGIN_LAYOUT_PARAMS, layoutWidth, layoutHeight - ) + addStatement( + "v.setLayoutParams(new \$T(\$L, \$L))", + ClassNames.ANDROID_MARGIN_LAYOUT_PARAMS, layoutWidth, layoutHeight + ) - addStatement("return v") - }) + addStatement("return v") + } + ) return methods } @@ -1193,11 +1203,11 @@ class GeneratedModelWriter( // If the base method is already implemented don't bother checking for the payload method if (implementsMethod( - info.superClassElement, - bindVariablesMethod, - types, - elements - ) + info.superClassElement, + bindVariablesMethod, + types, + elements + ) ) { return emptyList() } @@ -1274,7 +1284,7 @@ class GeneratedModelWriter( val annotation = classElement.getAnnotation( EpoxyModelClass::class.java ) // This is an error. The model must have an EpoxyModelClass annotation - // since getDefaultLayout is not implemented + // since getDefaultLayout is not implemented ?: return null val layoutRes: Int @@ -1673,7 +1683,7 @@ class GeneratedModelWriter( .addStatement( attribute.setterCode(), if (hasMultipleParams) - (attribute as MultiParamAttribute).valueToSetOnAttribute + (attribute as MultiParamAttribute).valueToSetOnAttribute else paramName ) 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 fd0e135845..6b08337014 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 @@ -10,7 +10,6 @@ import com.squareup.kotlinpoet.ParameterizedTypeName import com.squareup.kotlinpoet.TypeVariableName import javax.annotation.processing.Filer import javax.lang.model.element.Modifier -import kotlinx.coroutines.coroutineScope internal class KotlinModelBuilderExtensionWriter( val filer: Filer, @@ -36,26 +35,25 @@ internal class KotlinModelBuilderExtensionWriter( } } - private suspend fun buildExtensionFile( + private fun buildExtensionFile( packageName: String, models: List, processorName: String - ): FileSpec = coroutineScope { + ): FileSpec { val fileBuilder = FileSpec.builder( packageName, "Epoxy${processorName.removePrefix("Epoxy")}KotlinExtensions" ) - models - .map("buildExtensionFile") { - if (it.constructors.isEmpty()) { - listOf(buildExtensionsForModel(it, null)) - } else { - it.constructors.map { constructor -> - buildExtensionsForModel(it, constructor) - } + models.map { + if (it.constructors.isEmpty()) { + listOf(buildExtensionsForModel(it, null)) + } else { + it.constructors.map { constructor -> + buildExtensionsForModel(it, constructor) } } + } .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 @@ -71,7 +69,7 @@ internal class KotlinModelBuilderExtensionWriter( .build() ) - fileBuilder.build() + return fileBuilder.build() } private fun buildExtensionsForModel( diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Memoizer.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Memoizer.kt index b4a26256c6..f98085fc4e 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Memoizer.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Memoizer.kt @@ -86,10 +86,10 @@ class Memoizer( val methodReturnType = (subElement.asType() as ExecutableType).returnType if (methodReturnType != classType && !isSubtype( - classType, - methodReturnType, - types - ) + classType, + methodReturnType, + types + ) ) { return@mapNotNull null } @@ -335,7 +335,8 @@ class Memoizer( resourceProcessor = resourceProcessor, memoizer = this ) - }) + } + ) ) } } diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelBuilderInterfaceWriter.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelBuilderInterfaceWriter.kt index 9f1d1c97d9..94984aac50 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelBuilderInterfaceWriter.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelBuilderInterfaceWriter.kt @@ -131,11 +131,13 @@ class ModelBuilderInterfaceWriter( val interfaceSpec = buildInterface(interfaceName) { addModifiers(Modifier.PUBLIC) - addMethods(details.methodsOnInterface.map { - it.methodSpec.copy { - returns(interfaceName) + addMethods( + details.methodsOnInterface.map { + it.methodSpec.copy { + returns(interfaceName) + } } - }) + ) details.implementingViews.forEach { // Note: If a brand new model view class is added that implements this interface diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewInfo.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewInfo.kt index ea01ead30d..3a1dd2381d 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewInfo.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ModelViewInfo.kt @@ -3,6 +3,10 @@ package com.airbnb.epoxy.processor import com.airbnb.epoxy.ModelView import com.squareup.javapoet.ClassName import com.squareup.javapoet.ParameterizedTypeName +import kotlinx.metadata.Flag.ValueParameter.DECLARES_DEFAULT_VALUE +import kotlinx.metadata.KmFunction +import kotlinx.metadata.jvm.KotlinClassHeader +import kotlinx.metadata.jvm.KotlinClassMetadata import java.util.Collections import javax.lang.model.element.Element import javax.lang.model.element.ExecutableElement @@ -12,10 +16,6 @@ import javax.lang.model.type.DeclaredType import javax.lang.model.type.TypeMirror import javax.lang.model.util.Elements import javax.lang.model.util.Types -import kotlinx.metadata.Flag.ValueParameter.DECLARES_DEFAULT_VALUE -import kotlinx.metadata.KmFunction -import kotlinx.metadata.jvm.KotlinClassHeader -import kotlinx.metadata.jvm.KotlinClassMetadata class ModelViewInfo( val viewElement: TypeElement, 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 cbaeaf4fba..2795004652 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 @@ -9,6 +9,8 @@ import com.airbnb.epoxy.OnVisibilityChanged import com.airbnb.epoxy.OnVisibilityStateChanged import com.airbnb.epoxy.TextProp import com.airbnb.epoxy.processor.Utils.isSubtypeOfType +import net.ltgt.gradle.incap.IncrementalAnnotationProcessor +import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType import java.util.HashMap import java.util.HashSet import java.util.concurrent.ConcurrentHashMap @@ -22,8 +24,6 @@ import javax.lang.model.element.TypeElement import javax.lang.model.element.VariableElement import javax.lang.model.type.TypeKind import kotlin.reflect.KClass -import net.ltgt.gradle.incap.IncrementalAnnotationProcessor -import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType @IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.AGGREGATING) class ModelViewProcessor : BaseProcessorWithPackageConfigs() { diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageConfigSettings.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageConfigSettings.kt index 58c14ca6f9..bc6665c456 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageConfigSettings.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PackageConfigSettings.kt @@ -14,14 +14,15 @@ class PackageConfigSettings private constructor( companion object { fun forDefaults() = PackageConfigSettings( - PackageEpoxyConfig.REQUIRE_HASHCODE_DEFAULT, - PackageEpoxyConfig.REQUIRE_ABSTRACT_MODELS_DEFAULT, - PackageEpoxyConfig.IMPLICITLY_ADD_AUTO_MODELS_DEFAULT + PackageEpoxyConfig.REQUIRE_HASHCODE_DEFAULT, + PackageEpoxyConfig.REQUIRE_ABSTRACT_MODELS_DEFAULT, + PackageEpoxyConfig.IMPLICITLY_ADD_AUTO_MODELS_DEFAULT ) fun create(configAnnotation: PackageEpoxyConfig) = PackageConfigSettings( - configAnnotation.requireHashCode, - configAnnotation.requireAbstractModels, - configAnnotation.implicitlyAddAutoModels) + configAnnotation.requireHashCode, + configAnnotation.requireAbstractModels, + configAnnotation.implicitlyAddAutoModels + ) } } diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PoetExtensions.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PoetExtensions.kt index f777c24647..abdeb20e6c 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PoetExtensions.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/PoetExtensions.kt @@ -57,10 +57,10 @@ fun JavaClassName.toKPoet(): KotlinClassName { /** Some classes, like List or Byte have the same class name but a different package for their kotlin equivalent. */ private fun JavaClassName.getPackageNameInKotlin(): String { if (packageName() in listOf( - javaUtilPkg, - javaLangPkg, - kotlinJvmFunction - ) && simpleNames().size == 1 + javaUtilPkg, + javaLangPkg, + kotlinJvmFunction + ) && simpleNames().size == 1 ) { val transformedPkg = when { diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ResourceValue.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ResourceValue.kt index 5ff94e36b5..0ae1a51118 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ResourceValue.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ResourceValue.kt @@ -65,4 +65,6 @@ class ResourceValue { override fun toString(): String { throw UnsupportedOperationException("Please use value or code explicitly") } + + fun debugDetails(): String = code.toString() } diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Utils.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Utils.kt index d46e03724b..9b46960eb2 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Utils.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/Utils.kt @@ -137,8 +137,10 @@ internal object Utils { @JvmStatic fun isEpoxyModel(type: TypeMirror): Boolean { - return (isSubtypeOfType(type, EPOXY_MODEL_TYPE) || - isSubtypeOfType(type, UNTYPED_EPOXY_MODEL_TYPE)) + return ( + isSubtypeOfType(type, EPOXY_MODEL_TYPE) || + isSubtypeOfType(type, UNTYPED_EPOXY_MODEL_TYPE) + ) } fun isEpoxyModel(type: TypeElement): Boolean { @@ -248,9 +250,11 @@ internal object Utils { @JvmStatic fun isFieldPackagePrivate(element: Element): Boolean { val modifiers = element.modifiers - return (Modifier.PUBLIC !in modifiers && - Modifier.PROTECTED !in modifiers && - Modifier.PRIVATE !in modifiers) + return ( + Modifier.PUBLIC !in modifiers && + Modifier.PROTECTED !in modifiers && + Modifier.PRIVATE !in modifiers + ) } /** @@ -288,11 +292,11 @@ internal object Utils { continue } if (!areParamsTheSame( - methodElement, - method, - typeUtils, - elements - ) + methodElement, + method, + typeUtils, + elements + ) ) { continue } @@ -341,7 +345,7 @@ internal object Utils { * Returns the type of the Epoxy model. * * Eg for "class MyModel extends EpoxyModel" it would return TextView. - */ + */ fun getEpoxyObjectType( clazz: TypeElement, typeUtils: Types @@ -369,9 +373,9 @@ internal object Utils { // to figure out the base model type. We just look for the first type that is a view or // view holder. if (isSubtypeOfType( - superTypeArgument, - ANDROID_VIEW_TYPE - ) || + superTypeArgument, + ANDROID_VIEW_TYPE + ) || isSubtypeOfType( superTypeArgument, EPOXY_HOLDER_TYPE @@ -395,8 +399,8 @@ internal object Utils { // Verify method modifiers. val modifiers = fieldElement.modifiers if (modifiers.contains(Modifier.PRIVATE) && !skipPrivateFieldCheck || modifiers.contains( - Modifier.STATIC - ) + Modifier.STATIC + ) ) { logger.logError( "%s annotations must not be on private or static fields. (class: %s, field: %s)", @@ -453,8 +457,10 @@ internal object Utils { } val method = element as ExecutableElement val methodName = method.simpleName.toString() - return (PATTERN_STARTS_WITH_SET.matcher(methodName).matches() && - method.parametersThreadSafe.size == 1) + return ( + PATTERN_STARTS_WITH_SET.matcher(methodName).matches() && + method.parametersThreadSafe.size == 1 + ) } fun removeSetPrefix(string: String): String { diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ViewAttributeInfo.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ViewAttributeInfo.kt index f511e324fc..6bbde00e5c 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ViewAttributeInfo.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/processor/ViewAttributeInfo.kt @@ -17,6 +17,7 @@ import com.squareup.javapoet.CodeBlock import com.squareup.javapoet.ParameterizedTypeName import com.squareup.javapoet.TypeName import com.squareup.javapoet.TypeVariableName +import org.jetbrains.annotations.NotNull import java.util.HashSet import javax.lang.model.element.Element import javax.lang.model.element.ElementKind @@ -27,7 +28,6 @@ import javax.lang.model.element.VariableElement import javax.lang.model.type.TypeMirror import javax.lang.model.util.Elements import javax.lang.model.util.Types -import org.jetbrains.annotations.NotNull private val NOT_NULL_ANNOTATION_SPEC = AnnotationSpec.builder(NotNull::class.java).build() private val NON_NULL_ANNOTATION_SPEC = AnnotationSpec.builder(NonNull::class.java).build() @@ -324,8 +324,8 @@ class ViewAttributeInfo( } if (options.contains(Option.GenerateStringOverloads) && !isAssignable( - getTypeMirror(CharSequence::class.java, elements), typeMirror, types - ) + getTypeMirror(CharSequence::class.java, elements), typeMirror, types + ) ) { logger .logError( @@ -374,8 +374,9 @@ class ViewAttributeInfo( val elementClassName = ClassName.get(annotationType) if (elementClassName in ModelViewProcessor.modelPropAnnotations.map { - it.className() - }) { + it.className() + } + ) { continue } @@ -473,11 +474,13 @@ class ViewAttributeInfo( } override fun toString(): String { - return ("View Prop {" + - "view='" + viewElement.simpleName + '\'' + - ", name='" + viewAttributeName + '\'' + - ", type=" + typeName + - ", hasDefaultKotlinValue=" + hasDefaultKotlinValue + - '}') + return ( + "View Prop {" + + "view='" + viewElement.simpleName + '\'' + + ", name='" + viewAttributeName + '\'' + + ", type=" + typeName + + ", hasDefaultKotlinValue=" + hasDefaultKotlinValue + + '}' + ) } } diff --git a/epoxy-processor/src/test/java/com/airbnb/epoxy/PoetExtensionsTest.kt b/epoxy-processor/src/test/java/com/airbnb/epoxy/PoetExtensionsTest.kt index f090e9fc6c..8f56b56e7c 100644 --- a/epoxy-processor/src/test/java/com/airbnb/epoxy/PoetExtensionsTest.kt +++ b/epoxy-processor/src/test/java/com/airbnb/epoxy/PoetExtensionsTest.kt @@ -4,13 +4,13 @@ import androidx.annotation.FloatRange import androidx.annotation.NonNull import com.airbnb.epoxy.EpoxyModelClass import com.squareup.kotlinpoet.asTypeName -import javax.lang.model.element.Modifier import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Test +import javax.lang.model.element.Modifier class PoetExtensionsTest { diff --git a/epoxy-processortest/src/test/java/com/airbnb/epoxy/DataBindingModelTest.java b/epoxy-processortest/src/test/java/com/airbnb/epoxy/DataBindingModelTest.java index 0749ce1428..9ed1ed397a 100644 --- a/epoxy-processortest/src/test/java/com/airbnb/epoxy/DataBindingModelTest.java +++ b/epoxy-processortest/src/test/java/com/airbnb/epoxy/DataBindingModelTest.java @@ -107,7 +107,7 @@ public void testSimpleModelNoValidation() { @Test public void testFullyGeneratedModel() { JavaFileObject packageInfo = JavaFileObjects - .forResource(GuavaPatch.patchResource("package-info.java")); + .forResource(GuavaPatch.patchResource("DataBindingConfig.java")); JavaFileObject binding = JavaFileObjects .forResource(GuavaPatch.patchResource("ModelWithDataBindingBinding.java")); @@ -126,10 +126,11 @@ public void testFullyGeneratedModel() { @Test public void testFullyGeneratedModelWithoutDoNotHash() { JavaFileObject packageInfo = JavaFileObjects - .forSourceString("com.airbnb.epoxy.package-info", - "@EpoxyDataBindingLayouts(value = {R.layout" + .forSourceString("EpoxyDataBindingConfig.java", + "package com.airbnb.epoxy;\n" + + "@EpoxyDataBindingLayouts(value = {R.layout" + ".model_with_data_binding_without_donothash}, enableDoNotHash = false)\n" - + "package com.airbnb.epoxy;\n" + + "interface EpoxyDataBindingConfig {} " ); JavaFileObject binding = JavaFileObjects diff --git a/epoxy-processortest/src/test/java/com/airbnb/epoxy/ModelProcessorTest.kt b/epoxy-processortest/src/test/java/com/airbnb/epoxy/ModelProcessorTest.kt index ab550b8459..52b1d9872d 100644 --- a/epoxy-processortest/src/test/java/com/airbnb/epoxy/ModelProcessorTest.kt +++ b/epoxy-processortest/src/test/java/com/airbnb/epoxy/ModelProcessorTest.kt @@ -153,8 +153,10 @@ class ModelProcessorTest { .forResource("ModelWithAnnotatedClassAndSuperAttributes_.java".patchResource()) val generatedSubClassModel = JavaFileObjects.forResource( - ("ModelWithAnnotatedClassAndSuperAttributes\$SubModel" + - "WithAnnotatedClassAndSuperAttributes_.java").patchResource() + ( + "ModelWithAnnotatedClassAndSuperAttributes\$SubModel" + + "WithAnnotatedClassAndSuperAttributes_.java" + ).patchResource() ) Truth.assert_() .about(JavaSourceSubjectFactory.javaSource()) diff --git a/epoxy-processortest/src/test/java/com/airbnb/epoxy/ViewProcessorTest.kt b/epoxy-processortest/src/test/java/com/airbnb/epoxy/ViewProcessorTest.kt index 222b29a37e..32c183a9f4 100644 --- a/epoxy-processortest/src/test/java/com/airbnb/epoxy/ViewProcessorTest.kt +++ b/epoxy-processortest/src/test/java/com/airbnb/epoxy/ViewProcessorTest.kt @@ -6,8 +6,8 @@ import com.airbnb.epoxy.ProcessorTestUtils.processors import com.google.common.truth.Truth.assert_ import com.google.testing.compile.JavaFileObjects import com.google.testing.compile.JavaSourcesSubjectFactory.javaSources -import javax.tools.JavaFileObject import org.junit.Test +import javax.tools.JavaFileObject class ViewProcessorTest { @@ -241,7 +241,8 @@ class ViewProcessorTest { val baseModel = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.TestBaseModel", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.TestBaseModel", + "package com.airbnb.epoxy;\n" + "\n" + "import android.widget.FrameLayout;\n" + "\n" + @@ -276,7 +277,8 @@ class ViewProcessorTest { @Test fun baseModelWithDiffBind() { val baseModel = JavaFileObjects.forSourceLines( - "com.airbnb.epoxy.TestBaseModel", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.TestBaseModel", + "package com.airbnb.epoxy;\n" + "\n" + "import android.widget.FrameLayout;\n" + "\n" + @@ -302,7 +304,8 @@ class ViewProcessorTest { .forResource("BaseModelView.java".patchResource()) val baseModel = JavaFileObjects.forSourceLines( - "com.airbnb.epoxy.TestBaseModel", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.TestBaseModel", + "package com.airbnb.epoxy;\n" + "\n" + "import android.widget.FrameLayout;\n" + "\n" + @@ -327,7 +330,8 @@ class ViewProcessorTest { fun throwsIfBaseModelNotEpoxyModel() { val model = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.BaseModelView", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.BaseModelView", + "package com.airbnb.epoxy;\n" + "\n" + "import android.content.Context;\n" + "import android.widget.FrameLayout;\n" + @@ -348,7 +352,8 @@ class ViewProcessorTest { val baseModel = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.TestBaseModel", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.TestBaseModel", + "package com.airbnb.epoxy;\n" + "\n" + "public abstract class TestBaseModel{\n" + "}\n" @@ -367,7 +372,8 @@ class ViewProcessorTest { fun baseModelFromPackageConfig() { val model = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.BaseModelView", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.BaseModelView", + "package com.airbnb.epoxy;\n" + "\n" + "import android.content.Context;\n" + "import android.widget.FrameLayout;\n" + @@ -400,7 +406,8 @@ class ViewProcessorTest { val baseModel = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.TestBaseModel", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.TestBaseModel", + "package com.airbnb.epoxy;\n" + "\n" + "import android.view.View;\n" + "\n" + @@ -428,7 +435,8 @@ class ViewProcessorTest { val model = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.BaseModelView", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.BaseModelView", + "package com.airbnb.epoxy;\n" + "\n" + "import android.content.Context;\n" + "import android.view.View;\n" + @@ -461,7 +469,8 @@ class ViewProcessorTest { val baseModel = JavaFileObjects .forSourceLines( - "com.airbnb.epoxy.TestBaseModel", "package com.airbnb.epoxy;\n" + + "com.airbnb.epoxy.TestBaseModel", + "package com.airbnb.epoxy;\n" + "\n" + "import android.view.View;\n" + "\n" + @@ -569,7 +578,8 @@ class ViewProcessorTest { ) val R = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R", "" + + "com.airbnb.epoxy.R", + "" + "package com.airbnb.epoxy;\n" + "public final class R {\n" + " public static final class layout {\n" + @@ -622,7 +632,8 @@ class ViewProcessorTest { ) val R2 = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R2", "" + + "com.airbnb.epoxy.R2", + "" + "package com.airbnb.epoxy;\n" + "public final class R2 {\n" + " public static final class layout {\n" + @@ -632,7 +643,8 @@ class ViewProcessorTest { ) val R = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R", "" + + "com.airbnb.epoxy.R", + "" + "package com.airbnb.epoxy;\n" + "public final class R {\n" + " public static final class layout {\n" + @@ -685,7 +697,8 @@ class ViewProcessorTest { ) val R = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R", "" + + "com.airbnb.epoxy.R", + "" + "package com.airbnb.epoxy;\n" + "public final class R {\n" + " public static final class layout {\n" + @@ -739,7 +752,8 @@ class ViewProcessorTest { ) val R = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R", "" + + "com.airbnb.epoxy.R", + "" + "package com.airbnb.epoxy;\n" + "public final class R {\n" + " public static final class layout {\n" + @@ -793,7 +807,8 @@ class ViewProcessorTest { ) val R = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R", "" + + "com.airbnb.epoxy.R", + "" + "package com.airbnb.epoxy;\n" + "public final class R {\n" + " public static final class layout {\n" + @@ -1019,7 +1034,8 @@ class ViewProcessorTest { companion object { private val R: JavaFileObject = JavaFileObjects.forSourceString( - "com.airbnb.epoxy.R", "" + + "com.airbnb.epoxy.R", + "" + "package com.airbnb.epoxy;\n" + "public final class R {\n" + " public static final class layout {\n" + diff --git a/epoxy-processortest/src/test/resources/package-info.java b/epoxy-processortest/src/test/resources/DataBindingConfig.java similarity index 70% rename from epoxy-processortest/src/test/resources/package-info.java rename to epoxy-processortest/src/test/resources/DataBindingConfig.java index c276b8e896..df5330aad5 100644 --- a/epoxy-processortest/src/test/resources/package-info.java +++ b/epoxy-processortest/src/test/resources/DataBindingConfig.java @@ -1,2 +1,4 @@ -@EpoxyDataBindingLayouts({R.layout.model_with_data_binding}) package com.airbnb.epoxy; + +@EpoxyDataBindingLayouts({R.layout.model_with_data_binding}) +interface EpoxyDataBindingConfig {} diff --git a/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/EpoxyDataBindingConfig.java b/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/EpoxyDataBindingConfig.java new file mode 100644 index 0000000000..c1fda9e657 --- /dev/null +++ b/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/EpoxyDataBindingConfig.java @@ -0,0 +1,7 @@ +package com.airbnb.epoxy.sample; + +import com.airbnb.epoxy.EpoxyDataBindingLayouts; + +@EpoxyDataBindingLayouts(R.layout.button) +interface EpoxyDataBindingConfig {} + diff --git a/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/package-info.java b/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/package-info.java index 5947e3ee18..ad4bfa361f 100644 --- a/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/package-info.java +++ b/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/package-info.java @@ -1,6 +1,4 @@ -@EpoxyDataBindingLayouts(R.layout.button) @PackageModelViewConfig(rClass = R.class) package com.airbnb.epoxy.sample; -import com.airbnb.epoxy.EpoxyDataBindingLayouts; import com.airbnb.epoxy.PackageModelViewConfig; diff --git a/gradle.properties b/gradle.properties index 365f9ef150..0e025987e2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=4.0.0-beta4 +VERSION_NAME=4.0.0-beta5 GROUP=com.airbnb.android POM_DESCRIPTION=Epoxy is a system for composing complex screens with a ReyclerView in Android. POM_URL=https://github.com/airbnb/epoxy diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 21e622da69..ac33e9944a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/EpoxyDataBindingPatterns.kt b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/EpoxyDataBindingPatterns.kt new file mode 100644 index 0000000000..720d242036 --- /dev/null +++ b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/EpoxyDataBindingPatterns.kt @@ -0,0 +1,6 @@ +package com.airbnb.epoxy.kotlinsample + +import com.airbnb.epoxy.EpoxyDataBindingPattern + +@EpoxyDataBindingPattern(rClass = R::class, layoutPrefix = "epoxy_layout") +object EpoxyDataBindingPatterns diff --git a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/MainActivity.kt b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/MainActivity.kt index 5b646cfc54..a268acb5c8 100644 --- a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/MainActivity.kt +++ b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/MainActivity.kt @@ -35,7 +35,7 @@ class MainActivity : AppCompatActivity() { for (i in 0 until 100) { dataBindingItem { id("data binding $i") - text("this is a data binding model") + text("this is a data binding model2") onClick { _ -> Toast.makeText(this@MainActivity, "clicked", Toast.LENGTH_LONG).show() } diff --git a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/StickyHeaderAdapter.kt b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/StickyHeaderAdapter.kt index 31b8d51967..895e18236c 100644 --- a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/StickyHeaderAdapter.kt +++ b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/StickyHeaderAdapter.kt @@ -18,23 +18,25 @@ class StickyHeaderAdapter( init { enableDiffing() for (i in 0 until 100) { - addModel(when { - i % 5 == 0 -> StickyItemEpoxyHolder_().apply { - id("sticky-header $i") - title("Sticky header $i") - listener { - Toast.makeText(context, "clicked", Toast.LENGTH_LONG).show() + addModel( + when { + i % 5 == 0 -> StickyItemEpoxyHolder_().apply { + id("sticky-header $i") + title("Sticky header $i") + listener { + Toast.makeText(context, "clicked", Toast.LENGTH_LONG).show() + } } - } - else -> ItemEpoxyHolder_().apply { - id("view holder $i") - title("this is a View Holder item") - listener { - Toast.makeText(context, "clicked", Toast.LENGTH_LONG) - .show() + else -> ItemEpoxyHolder_().apply { + id("view holder $i") + title("this is a View Holder item") + listener { + Toast.makeText(context, "clicked", Toast.LENGTH_LONG) + .show() + } } } - }) + ) } notifyModelsChanged() } diff --git a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/helpers/KotlinModel.kt b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/helpers/KotlinModel.kt index 8a46f40da0..afaa3ba528 100644 --- a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/helpers/KotlinModel.kt +++ b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/helpers/KotlinModel.kt @@ -38,7 +38,7 @@ abstract class KotlinModel( // be optimized with a map @Suppress("UNCHECKED_CAST") return view?.findViewById(id) as V? - ?: throw IllegalStateException("View ID $id for '${property.name}' not found.") + ?: throw IllegalStateException("View ID $id for '${property.name}' not found.") } } } diff --git a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/models/ItemCustomView.kt b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/models/ItemCustomView.kt index 32b3a1b462..ae488342db 100644 --- a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/models/ItemCustomView.kt +++ b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/models/ItemCustomView.kt @@ -114,8 +114,8 @@ class ItemCustomView @JvmOverloads constructor( TAG, "$title onChanged ${percentVisibleHeight.toInt()} ${percentVisibleWidth.toInt()} " + "$visibleHeight $visibleWidth ${System.identityHashCode( - this - )}" + this + )}" ) with(onVisibilityEventDrawable) { if ((percentVisibleHeight < 100 || percentVisibleWidth < 100) && fullImpression) { diff --git a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/package-info.java b/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/package-info.java deleted file mode 100644 index 0e728a6d0a..0000000000 --- a/kotlinsample/src/main/java/com/airbnb/epoxy/kotlinsample/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@EpoxyDataBindingPattern(rClass = R.class, layoutPrefix = "epoxy_layout") -package com.airbnb.epoxy.kotlinsample; - -import com.airbnb.epoxy.EpoxyDataBindingPattern; diff --git a/ktlint.gradle b/ktlint.gradle index f62d3176af..2acd0caeed 100644 --- a/ktlint.gradle +++ b/ktlint.gradle @@ -7,7 +7,7 @@ configurations { } dependencies { - ktlint "com.pinterest:ktlint:0.36.0" + ktlint "com.pinterest:ktlint:0.37.2" // additional 3rd party ruleset(s) can be specified here // just add them to the classpath (e.g. ktlint 'groupId:artifactId:version') and // ktlint will pick them up