Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support inheritance across modules. Issue #808. #1045

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package butterknife.compiler;

import android.support.annotation.NonNull;
import butterknife.BindAnim;
import butterknife.BindArray;
import butterknife.BindBitmap;
Expand Down Expand Up @@ -50,10 +51,10 @@
import java.util.Arrays;
import java.util.BitSet;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
Expand All @@ -75,6 +76,7 @@
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
Expand Down Expand Up @@ -367,6 +369,12 @@ private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
bindingMap.put(type, builder.build());
} else {
BindingSet parentBinding = bindingMap.get(parentType);

// parent binding is null, let's try to find a previouly generated binding
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment -> "previouly"

if (parentBinding == null && hasViewBinder(parentType)) {
parentBinding = createStubBindingSet(parentType);
}

if (parentBinding != null) {
builder.setParent(parentBinding);
bindingMap.put(type, builder.build());
Expand All @@ -380,6 +388,33 @@ private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
return bindingMap;
}

@NonNull private BindingSet createStubBindingSet(TypeElement parentType) {
BindingSet parentBinding;
BindingSet.Builder parentBuilder = BindingSet.newBuilder(parentType);
if (hasViewBindings(parentType)) {
//add a fake field to the parent class so that it will indicate it has a view bindings.
//this is required for the subclass to generate a proper view binder
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parentBuilder.addField(new Id(-1), new FieldViewBinding("", null, false));
}
parentBinding = parentBuilder.build();
return parentBinding;
}

private boolean hasViewBindings(TypeElement parentType) {
for (VariableElement fieldElement : ElementFilter.fieldsIn(parentType.getEnclosedElements())) {
if (fieldElement.getAnnotation(BindView.class) != null
|| fieldElement.getAnnotation(BindViews.class) != null) {
return true;
}
}
return false;
}

private boolean hasViewBinder(TypeElement typeElement) {
final String viewBindingClassName = typeElement.getQualifiedName().toString() + "_ViewBinding";
return elementUtils.getTypeElement(viewBindingClassName) != null;
}

private void logParsingError(Element element, Class<? extends Annotation> annotation,
Exception e) {
StringWriter stackTrace = new StringWriter();
Expand Down Expand Up @@ -1284,7 +1319,7 @@ private TypeElement findParentType(TypeElement typeElement, Set<TypeElement> par
return null;
}
typeElement = (TypeElement) ((DeclaredType) type).asElement();
if (parents.contains(typeElement)) {
if (parents.contains(typeElement) || hasViewBinder(typeElement)) {
return typeElement;
}
}
Expand Down
1 change: 1 addition & 0 deletions butterknife/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies {
testImplementation deps.junit
testImplementation deps.truth
testImplementation deps.compiletesting
testImplementation deps.auto.common
testImplementation files(getRuntimeJar())
testImplementation files(org.gradle.internal.jvm.Jvm.current().getToolsJar())
testImplementation project(':butterknife-compiler')
Expand Down
62 changes: 62 additions & 0 deletions butterknife/src/test/java/butterknife/InheritanceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package butterknife;

import butterknife.compiler.ButterKnifeProcessor;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.JavaFileObjects;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import org.junit.Test;

import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
import static java.util.Arrays.asList;

public class InheritanceTest {

@Test public void bindingViewFinalClassWithBaseClassAlreadyCompiledInDifferentModule() {
JavaFileObject testSource = JavaFileObjects.forSourceString("test.Test", ""
+ "package test;\n"
+ "import android.view.View;\n"
+ "import butterknife.BindView;\n"
+ "import butterknife.precompiled.Base;\n"
+ "public final class Test extends Base {\n"
+ " @BindView(1) View thing;\n"
+ "}"
);

JavaFileObject bindingTestSource = JavaFileObjects.forSourceString("test/Test_ViewBinding", ""
+ "package test;\n"
+ "import android.support.annotation.UiThread;\n"
+ "import android.view.View;\n"
+ "import butterknife.internal.Utils;\n"
+ "import butterknife.precompiled.Base_ViewBinding;\n"
+ "import java.lang.IllegalStateException;\n"
+ "import java.lang.Override;\n"
+ "public final class Test_ViewBinding extends Base_ViewBinding {\n"
+ " private Test target;\n"
+ " @UiThread\n"
+ " public Test_ViewBinding(Test target, View source) {\n"
+ " super(target, source);\n"
+ " this.target = target;\n"
+ " target.thing = Utils.findRequiredView(source, 1, \"field 'thing'\");\n"
+ " }\n"
+ " @Override\n"
+ " public void unbind() {\n"
+ " Test target = this.target;\n"
+ " if (target == null) throw new IllegalStateException(\"Bindings already cleared.\");\n"
+ " this.target = null\n"
+ " target.thing = null;\n"
+ " super.unbind();\n"
+ " }\n"
+ "}"
);

assertAbout(javaSources()).that(asList(testSource))
.withCompilerOptions("-Xlint:-processing")
.processedWith(new ButterKnifeProcessor())
.compilesWithoutWarnings()
.and()
.generatesSources(bindingTestSource);
}
}
8 changes: 8 additions & 0 deletions butterknife/src/test/java/butterknife/precompiled/Base.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package butterknife.precompiled;

import android.view.View;
import butterknife.BindView;

public class Base {
@BindView(1) View thing;
}
27 changes: 27 additions & 0 deletions sample/base-library/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
buildscript {
repositories {
mavenCentral()
jcenter()
}

dependencies {
classpath "com.jakewharton:butterknife-gradle-plugin:${versions.release}"
}
}

apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'

android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools

defaultConfig {
minSdkVersion versions.minSdk
}
}

dependencies {
compile deps.release.runtime
annotationProcessor deps.release.compiler
}
1 change: 1 addition & 0 deletions sample/base-library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="com.example.butterknife.baselibrary"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.butterknife.baselibrary;

import android.app.Activity;
import butterknife.BindString;

public class BaseActivity extends Activity {
@BindString(R2.string.app_name) protected String butterKnife;
@BindString(R2.string.field_method) protected String fieldMethod;
@BindString(R2.string.by_jake_wharton) protected String byJakeWharton;
@BindString(R2.string.say_hello) protected String sayHello;
}
8 changes: 8 additions & 0 deletions sample/base-library/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>

<resources>
<string name="app_name">Butter Knife</string>
<string name="field_method">Field and method binding for Android views.</string>
<string name="by_jake_wharton">by Jake Wharton</string>
<string name="say_hello">Say Hello</string>
</resources>
7 changes: 6 additions & 1 deletion sample/library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ android {

dependencies {
implementation deps.release.runtime
annotationProcessor deps.release.compiler
implementation project(':sample:base-library')

//TODO this change is just to demonstrate that the new compiler works well
//but should be reversed when the new version is released
//annotationProcessor deps.release.compiler
annotationProcessor project(':butterknife-compiler')

testImplementation deps.junit
testImplementation deps.truth
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.example.butterknife.library;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.View;
Expand All @@ -16,11 +15,12 @@
import butterknife.OnClick;
import butterknife.OnItemClick;
import butterknife.OnLongClick;
import com.example.butterknife.baselibrary.BaseActivity;
import java.util.List;

import static android.widget.Toast.LENGTH_SHORT;

public class SimpleActivity extends Activity {
public class SimpleActivity extends BaseActivity {
private static final ButterKnife.Action<View> ALPHA_FADE = new ButterKnife.Action<View>() {
@Override public void apply(@NonNull View view, int index) {
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
Expand Down Expand Up @@ -62,10 +62,10 @@ public class SimpleActivity extends Activity {
ButterKnife.bind(this);

// Contrived code to use the bound fields.
title.setText("Butter Knife");
subtitle.setText("Field and method binding for Android views.");
footer.setText("by Jake Wharton");
hello.setText("Say Hello");
title.setText(butterKnife);
subtitle.setText(fieldMethod);
footer.setText(byJakeWharton);
hello.setText(sayHello);

adapter = new SimpleAdapter(this);
listOfThings.setAdapter(adapter);
Expand Down
5 changes: 0 additions & 5 deletions sample/library/src/main/res/values/strings.xml

This file was deleted.

1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include ':butterknife-lint'
include ':butterknife-integration-test'

//include ':sample:app'
//include ':sample:base-library'
//include ':sample:library'

rootProject.name = 'butterknife-parent'