public class MainActivity extends AppCompatActivity { @Bind(R.id.fab) private FloatingActionButton mFab; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ac_main); mFab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); ButterKnife.bind(this); } }
Error:(15, 34) error: @Bind fields must not be private or static. (moscow.droidcon2015.activity.MainActivity.mFab)
@Retention(RetentionPolicy.SOURCE) @Target({ElementType.FIELD}) public @interface BindView { int value(); }
src/main/resources/META-INF.services/javax.annotation.processing.Processor
The content of this file is a single line containing the full class name of the connected processor: moscow.droidcon2015.processor.DroidConProcessor
@SupportedAnnotationTypes({"moscow.droidcon2015.processor.BindView"}) public class DroidConProcessor extends AbstractProcessor { private final Map<TypeElement, BindViewVisitor> mVisitors = new HashMap<>(); @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { if (annotations.isEmpty()) { return false; } final Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(BindView.class); for (final Element element : elements) { // element == MainActivity.mFab final TypeElement object = (TypeElement) element.getEnclosingElement(); // object == MainActivity BindViewVisitor visitor = mVisitors.get(object); if (visitor == null) { visitor = new BindViewVisitor(processingEnv, object); mVisitors.put(object, visitor); } element.accept(visitor, null); } for (final BindViewVisitor visitor : mVisitors.values()) { visitor.brewJava(); } return true; } @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } }
public class BindViewVisitor extends ElementScanner7<Void, Void> { private final CodeBlock.Builder mFindViewById = CodeBlock.builder(); private final Trees mTrees; private final Messager mLogger; private final Filer mFiler; private final TypeElement mOriginElement; private final TreeMaker mTreeMaker; private final Names mNames; public BindViewVisitor(ProcessingEnvironment env, TypeElement element) { super(); mTrees = Trees.instance(env); mLogger = env.getMessager(); mFiler = env.getFiler(); mOriginElement = element; final JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) env; mTreeMaker = TreeMaker.instance(javacEnv.getContext()); mNames = Names.instance(javacEnv.getContext()); } }
@Override public Void visitVariable(VariableElement field, Void aVoid) { ((JCTree) mTrees.getTree(field)).accept(new TreeTranslator() { @Override public void visitVarDef(JCTree.JCVariableDecl jcVariableDecl) { super.visitVarDef(jcVariableDecl); jcVariableDecl.mods.flags &= ~Flags.PRIVATE; } }); final BindView bindView = field.getAnnotation(BindView.class); mFindViewById.addStatement("(($T) this).$L = ($T) findViewById($L)", ClassName.get(mOriginElement), field.getSimpleName(), ClassName.get(field.asType()), bindView.value()); return super.visitVariable(field, aVoid); }
public void brewJava() { final TypeSpec typeSpec = TypeSpec.classBuilder(mOriginElement.getSimpleName() + "$$Proxy") // MainActivity$$Proxy .addModifiers(Modifier.ABSTRACT) .superclass(ClassName.get(mOriginElement.getSuperclass())) // extends AppCompatActivity .addOriginatingElement(mOriginElement) .addMethod(MethodSpec.methodBuilder("setContentView") .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC) .addParameter(TypeName.INT, "layoutResId") .addStatement("super.setContentView(layoutResId)") .addCode(mFindViewById.build()) // findViewById... .build()) .build(); final JavaFile javaFile = JavaFile.builder(mOriginElement.getEnclosingElement().toString(), typeSpec) .addFileComment("Generated by DroidCon processor, do not modify") .build(); try { final JavaFileObject sourceFile = mFiler.createSourceFile( javaFile.packageName + "." + typeSpec.name, mOriginElement); try (final Writer writer = new BufferedWriter(sourceFile.openWriter())) { javaFile.writeTo(writer); } // TODO: MAGIC } catch (IOException e) { mLogger.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), mOriginElement); } }
JCTree.JCExpression selector = mTreeMaker.Ident(mNames.fromString(javaFile.packageName)); selector = mTreeMaker.Select(selector, mNames.fromString(typeSpec.name)); ((JCTree.JCClassDecl) mTrees.getTree(mOriginElement)).extending = selector;
MainActivity extends MainActivity$$Proxy extends AppCompatActivity
// Generated by DroidCon processor, do not modify package moscow.droidcon2015.activity; import android.support.design.widget.FloatingActionButton; import android.support.v7.app.AppCompatActivity; import java.lang.Override; abstract class MainActivity$$Proxy extends AppCompatActivity { @Override public void setContentView(int layoutResId) { super.setContentView(layoutResId); ((MainActivity) this).mFab = (FloatingActionButton) findViewById(2131492965); } }
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package moscow.droidcon2015.activity; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.view.View; import android.view.View.OnClickListener; import moscow.droidcon2015.activity.MainActivity$$Proxy; public class MainActivity extends MainActivity$$Proxy { FloatingActionButton mFab; public MainActivity() { } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2130968600); this.mFab.setOnClickListener(new OnClickListener() { public void onClick(View v) { } }); } }
@Override public void visitMethodDef(JCTree.JCMethodDecl methodDecl) { super.visitMethodDef(methodDecl); methodDecl.body.stats = com.sun.tools.javac.util.List.<JCTree.JCStatement>of( mTreeMaker.Try( mTreeMaker.Block(0, methodDecl.body.stats), com.sun.tools.javac.util.List.<JCTree.JCCatch>nil(), mTreeMaker.Block(0, com.sun.tools.javac.util.List.<JCTree.JCStatement>of( mTreeMaker.Exec(mTreeMaker.Apply( com.sun.tools.javac.util.List.<JCTree.JCExpression>nil(), ident(mPackageName, mHelperClassName, "update"), com.sun.tools.javac.util.List.of( mTreeMaker.Literal(TypeTag.CLASS, mColumnName), mTreeMaker.Select(mTreeMaker.Ident(mNames._this), mNames.fromString(mFieldName)), mTreeMaker.Select(mTreeMaker.Ident(mNames._this), mNames.fromString(mPrimaryKey.call())) ) )) )) ) ); }
// public void setText(String text) { mText = text; } // public void setText(String text) { try { this.mText = text; } finally { Foo$$SQLiteHelper.update("text", this.mText, this.mId); } }
Source: https://habr.com/ru/post/206208/
All Articles