diff --git a/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithDelegate.kt b/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithDelegate.kt new file mode 100644 index 0000000000..f3cce919b5 --- /dev/null +++ b/epoxy-integrationtest/src/main/java/com/airbnb/epoxy/integrationtest/ViewWithDelegate.kt @@ -0,0 +1,23 @@ +package com.airbnb.epoxy.integrationtest + +import android.content.Context +import android.view.View +import com.airbnb.epoxy.ModelProp +import com.airbnb.epoxy.ModelView + +@ModelView(autoLayout = ModelView.Size.WRAP_WIDTH_MATCH_HEIGHT) +class ViewWithDelegate @JvmOverloads constructor( + context: Context, + implementation: InterfaceImplementation = InterfaceImplementation() +) : View(context), InterfaceWithModelProp by implementation + +interface InterfaceWithModelProp { + + @set:ModelProp + var flag: Boolean +} + +class InterfaceImplementation : InterfaceWithModelProp { + + override var flag: Boolean = false +} diff --git a/epoxy-integrationtest/src/test/java/com/airbnb/epoxy/ModelViewDelegateTest.kt b/epoxy-integrationtest/src/test/java/com/airbnb/epoxy/ModelViewDelegateTest.kt new file mode 100644 index 0000000000..758476f1bd --- /dev/null +++ b/epoxy-integrationtest/src/test/java/com/airbnb/epoxy/ModelViewDelegateTest.kt @@ -0,0 +1,19 @@ +package com.airbnb.epoxy + +import com.airbnb.epoxy.integrationtest.BuildConfig +import com.airbnb.epoxy.integrationtest.ViewWithDelegateModel_ +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(constants = BuildConfig::class, sdk = intArrayOf(21)) +class ModelViewDelegateTest { + + @Test + fun propMethodIsOnModel() { + val model = ViewWithDelegateModel_() + model.flag(true) + } +} diff --git a/epoxy-processor/src/main/java/com/airbnb/epoxy/ModelViewProcessor.kt b/epoxy-processor/src/main/java/com/airbnb/epoxy/ModelViewProcessor.kt index db9dc64a84..953b76d4ae 100644 --- a/epoxy-processor/src/main/java/com/airbnb/epoxy/ModelViewProcessor.kt +++ b/epoxy-processor/src/main/java/com/airbnb/epoxy/ModelViewProcessor.kt @@ -129,6 +129,16 @@ internal class ModelViewProcessor( for (propAnnotation in modelPropAnnotations) { for (prop in roundEnv.getElementsAnnotatedWith(propAnnotation)) { + + // Interfaces can use model property annotations freely, they will be processed if + // and when implementors of that interface are processed. This is particularly + // useful for Kotlin delegation where the model view class may not be overriding + // the interface properties directly, and so doesn't have an opportunity to annotate + // them with Epoxy model property annotations. + if (prop.enclosingElement.kind == ElementKind.INTERFACE) { + continue + } + val info = getModelInfoForPropElement(prop) if (info == null) { errorLogger.logError(