先对AbstractProcessor有个认识,每一个处理器都是继承于AbstractProcessor,如下所示:
package com.example.butterknife_complier;
public class ButterKnifeProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment env){ }
@Override
public boolean process(Set<extends TypeElement> annoations, RoundEnvironment env) { }
@Override
public Set<String> getSupportedAnnotationTypes() { }
@Override
public SourceVersion getSupportedSourceVersion() { }
}
? init(ProcessingEnvironment env): 输入ProcessingEnviroment参数,ProcessingEnviroment提供很多有用的工具类Elements, Types和Filer。
? process(Set<extends TypeElement> annotations, RoundEnvironment env): 这相当于每个处理器的主函数main()。你在这里写你的扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让你查询出包含特定注解的被注解元素。
? getSupportedAnnotationTypes(): 这里你必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
? getSupportedSourceVersion(): 用来指定你使用的Java版本。通常这里返回SourceVersion.latestSupported()。
完整代码如下:
package com.example.butterknife_complier;
import com.example.butterknife_annotations.BindView;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeName;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.tools.Diagnostic;
@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {
private Filer filer;
private Messager messager;
static final String VIEW_TYPE = "android.view.View";
static final String ACTIVITY_TYPE = "android.app.Activity";
static final String DIALOG_TYPE = "android.app.Dialog";
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
filer = processingEnvironment.getFiler();
messager = processingEnvironment.getMessager(); //这里初始化打印message的工具messager
messager.printMessage(Diagnostic.Kind.MANDATORY_WARNING,"processor init");
}
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
types.add(BindView.class.getCanonicalName()); // 返回支持的注解的集合
return types;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set<extends TypeElement> set, RoundEnvironment env) {
messager.printMessage(Diagnostic.Kind.WARNING,"processor process env" + env.toString());
Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);
for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
TypeElement typeElement = entry.getKey();
BindingSet binding = entry.getValue();
JavaFile javaFile = binding.brewJava();
try {
javaFile.writeTo(filer);
} catch (IOException e) {
messager.printMessage(Diagnostic.Kind.ERROR, String.format("Unable to write binding for type %s: %s", typeElement, e.getMessage()), typeElement);
}
}
return false;
}
private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
Map<TypeElement, BindingSet.Builder> builderMap = new LinkedHashMap<>();
for (Element element : env.getElementsAnnotatedWith(BindView.class)) {
try {
parseBindView(element, builderMap); //这里只查找BindView注解
} catch (Exception e) {
logParsingError(element, BindView.class, e);
}
}
Map<TypeElement, BindingSet> bindingMap = new LinkedHashMap<>();
for (Map.Entry<TypeElement, BindingSet.Builder> entry : builderMap.entrySet()) {
TypeElement type = entry.getKey();
BindingSet.Builder builder = entry.getValue();
bindingMap.put(type, builder.build());
}
return bindingMap;
}
private void parseBindView(Element element, Map<TypeElement, BindingSet.Builder> builderMap) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Start by verifying common generated code restrictions.
boolean hasError = isInaccessibleViaGeneratedCode(BindView.class, "fields", element)
|| isBindingInWrongPackage(BindView.class, element);
// Verify that the target type extends from View.
TypeMirror elementType = element.asType();
if (elementType.getKind() == TypeKind.TYPEVAR) {
TypeVariable typeVariable = (TypeVariable) elementType;
elementType = typeVariable.getUpperBound();
}
Name qualifiedName = enclosingElement.getQualifiedName();
Name simpleName = element.getSimpleName();
if (!isSubtypeOfType(elementType, VIEW_TYPE) && !isInterface(elementType)) {
if (elementType.getKind() == TypeKind.ERROR) {
error(element, "@%s field with unresolved type (%s) "
+ "must elsewhere be generated as a View or interface. (%s.%s)",
BindView.class.getSimpleName(), elementType, qualifiedName, simpleName);
} else {
error(element, "@%s fields must extend from View or be an interface. (%s.%s)",
BindView.class.getSimpleName(), qualifiedName, simpleName);
hasError = true;
}
}
if (hasError) {
return;
}
// Assemble information on the field.
int id = element.getAnnotation(BindView.class).value();
BindingSet.Builder builder = builderMap.get(enclosingElement);
if (builder == null) {
builder = BindingSet.newBuilder(enclosingElement);
builderMap.put(enclosingElement, builder);
}
String name = simpleName.toString();
TypeName type = TypeName.get(elementType);
// TypeMirror typeMirror = enclosingElement.asType();
// boolean isView = isSubtypeOfType(typeMirror, VIEW_TYPE);
// boolean isActivity = isSubtypeOfType(typeMirror, ACTIVITY_TYPE);
// boolean isDialog = isSubtypeOfType(typeMirror, DIALOG_TYPE);
// messager.printMessage(Diagnostic.Kind.ERROR,"enclosingElement:" + typeMirror.toString() + "isView:" + isView + ",isActivity:" + isActivity + ",isDialog:" + isDialog);
builder.addField(new Id(id), new FieldViewBinding(name, type, true));
}
private boolean isInaccessibleViaGeneratedCode(Class<extends Annotation> annotationClass, String targetThing, Element element) {
boolean hasError = false;
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
// Verify field or method modifiers.
Set<Modifier> modifiers = element.getModifiers();
//这里验证属性不能是private或者static修饰
if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) {
error(element, "@%s %s must not be private or static. (%s.%s)",
annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
// Verify containing type.
if (enclosingElement.getKind() != ElementKind.CLASS) {
error(enclosingElement, "@%s %s may only be contained in classes. (%s.%s)",
annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
// Verify containing class visibility is not private.
if (enclosingElement.getModifiers().contains(Modifier.PRIVATE)) {
error(enclosingElement, "@%s %s may not be contained in private classes. (%s.%s)",
annotationClass.getSimpleName(), targetThing, enclosingElement.getQualifiedName(),
element.getSimpleName());
hasError = true;
}
return hasError;
}
private boolean isBindingInWrongPackage(Class<extends Annotation> annotationClass, Element element) {
TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
String qualifiedName = enclosingElement.getQualifiedName().toString();
if (qualifiedName.startsWith("android.")) {
error(element, "@%s-annotated class incorrectly in Android framework package. (%s)",
annotationClass.getSimpleName(), qualifiedName);
return true;
}
if (qualifiedName.startsWith("java.")) {
error(element, "@%s-annotated class incorrectly in Java framework package. (%s)",
annotationClass.getSimpleName(), qualifiedName);
return true;
}
return false;
}
private boolean isInterface(TypeMirror typeMirror) {
return typeMirror instanceof DeclaredType
&& ((DeclaredType) typeMirror).asElement().getKind() == ElementKind.INTERFACE;
}
static boolean isSubtypeOfType(TypeMirror typeMirror, String otherType) {
if (isTypeEqual(typeMirror, otherType)) {
return true;
}
if (typeMirror.getKind() != TypeKind.DECLARED) {
return false;
}
DeclaredType declaredType = (DeclaredType) typeMirror;
List<extends TypeMirror> typeArguments = declaredType.getTypeArguments();
if (typeArguments.size() > 0) {
StringBuilder typeString = new StringBuilder(declaredType.asElement().toString());
typeString.append('<');
for (int i = 0; i < typeArguments.size(); i++) {
if (i > 0) {
typeString.append(',');
}
typeString.append('?');
}
typeString.append('>');
if (typeString.toString().equals(otherType)) {
return true;
}
}
Element element = declaredType.asElement();
if (!(element instanceof TypeElement)) {
return false;
}
TypeElement typeElement = (TypeElement) element;
TypeMirror superType = typeElement.getSuperclass();
if (isSubtypeOfType(superType, otherType)) {
return true;
}
for (TypeMirror interfaceType : typeElement.getInterfaces()) {
if (isSubtypeOfType(interfaceType, otherType)) {
return true;
}
}
return false;
}
private static boolean isTypeEqual(TypeMirror typeMirror, String otherType) {
return otherType.equals(typeMirror.toString());
}
private void error(Element element, String errorMsg, Object... args) {
messager.printMessage(Diagnostic.Kind.ERROR, String.format(errorMsg, args), element);
}
private void logParsingError(Element element, Class<extends Annotation> annotation, Exception e) {
StringWriter stackTrace = new StringWriter();
e.printStackTrace(new PrintWriter(stackTrace));
error(element, "Unable to parse @%s binding.\n\n%s", annotation.getSimpleName(), stackTrace);
}
}
1.通过messager打印的日志可以在build里面看到如下:
也可以帮我们查看扫描注解的结果,以及错误信息
- Elements 和 TypeMirrors
Element代表程序的元素,例如包、类或者方法。每个Element代表一个静态的、语言级别的构件。然而,TypeElement并不包含类本身的信息。你可以从TypeElement中获取类的名字,但是你获取不到类的信息,例如它的父类。这种信息需要通过TypeMirror获取。你可以通过调用elements.asType()获取元素的TypeMirror。
Element的类型可以通过element.getKind()获取,TypeKind时一个枚举类:
public enum TypeKind {
BOOLEAN,
BYTE,
SHORT,
INT,
LONG,
CHAR,
FLOAT,
DOUBLE,
VOID,
NONE,
NULL,
ARRAY,
DECLARED,
ERROR,
TYPEVAR,
WILDCARD,
PACKAGE,
EXECUTABLE,
OTHER,
UNION,
INTERSECTION;
private TypeKind() {
}
public boolean isPrimitive() {
switch(this) {
case BOOLEAN:
case BYTE:
case SHORT:
case INT:
case LONG:
case CHAR:
case FLOAT:
case DOUBLE:
return true;
default:
return false;
}
}
}
举例:
package com.example; // PackageElement
public class Foo { // TypeElement
private int a; // VariableElement
private Foo other; // VariableElement
public Foo () {} // ExecuteableElement
public void setA ( // ExecuteableElement
int newA // VariableElement
) {}
}
parseBindView里面有一些验证:比如属性不能时private或者static的,当我在text View前面加上private:
@BindView(R.id.sample_text)
private TextView textView;
点击运行,报错如下:
还有其他,如不能被包含在private修改的类型,注解的对象必须是View的子类或者是一个接口类型。
验证通过,生成一个FieldViewBinding对象,记录要绑定的属性信息。
3.生成ViewBinding类
package com.example.butterknife_complier;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import static com.example.butterknife_complier.ButterKnifeProcessor.ACTIVITY_TYPE;
import static com.example.butterknife_complier.ButterKnifeProcessor.DIALOG_TYPE;
import static com.example.butterknife_complier.ButterKnifeProcessor.VIEW_TYPE;
import static com.example.butterknife_complier.ButterKnifeProcessor.isSubtypeOfType;
import static com.google.auto.common.MoreElements.getPackage;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
/**
* A set of all the bindings requested by a single type.
*/
final class BindingSet implements BindingInformationProvider {
static final ClassName UTILS = ClassName.get("butterknife.internal", "Utils");
private static final ClassName VIEW = ClassName.get("android.view", "View");
private static final ClassName CONTEXT = ClassName.get("android.content", "Context");
private static final ClassName UI_THREAD =
ClassName.get("androidx.annotation", "UiThread");
private static final ClassName CALL_SUPER = ClassName.get("androidx.annotation", "CallSuper");
private static final ClassName UNBINDER = ClassName.get("butterknife", "Unbinder");
private final TypeName targetTypeName;
private final ClassName bindingClassName;
private final TypeElement enclosingElement;
private final boolean isFinal;
private final boolean isView;
private final boolean isActivity;
private final boolean isDialog;
private final ImmutableList<ViewBinding> viewBindings;
private final @Nullable
BindingInformationProvider parentBinding;
private boolean debuggable = true;
private BindingSet(
TypeName targetTypeName, ClassName bindingClassName, TypeElement enclosingElement,
boolean isFinal, boolean isView, boolean isActivity, boolean isDialog,
ImmutableList<ViewBinding> viewBindings,
@Nullable BindingInformationProvider parentBinding) {
this.isFinal = isFinal;
this.targetTypeName = targetTypeName;
this.bindingClassName = bindingClassName;
this.enclosingElement = enclosingElement;
this.isView = isView;
this.isActivity = isActivity;
this.isDialog = isDialog;
this.viewBindings = viewBindings;
this.parentBinding = parentBinding;
}
@Override
public ClassName getBindingClassName() {
return bindingClassName;
}
JavaFile brewJava() {
TypeSpec bindingConfiguration = createType(); //从这里开始生成配置信息
return JavaFile.builder(bindingClassName.packageName(), bindingConfiguration)
.addFileComment("Generated code from Butter Knife. Do not modify!")
.build();
}
private TypeSpec createType() {
TypeSpec.Builder result = TypeSpec.classBuilder(bindingClassName.simpleName())
.addModifiers(PUBLIC)
.addOriginatingElement(enclosingElement);
if (isFinal) {
result.addModifiers(FINAL);
}
if (parentBinding != null) {
result.superclass(parentBinding.getBindingClassName());
} else {
result.addSuperinterface(UNBINDER);
}
if (hasTargetField()) {
result.addField(targetTypeName, "target", PRIVATE);
}
if (isView) {
result.addMethod(createBindingConstructorForView());
} else if (isActivity) {
result.addMethod(createBindingConstructorForActivity());//会走到这里,生成activity
} else if (isDialog) {
result.addMethod(createBindingConstructorForDialog());
}
if (!constructorNeedsView()) {
// Add a delegating constructor with a target type + view signature for reflective use.
result.addMethod(createBindingViewDelegateConstructor());
}
result.addMethod(createBindingConstructor());
if (hasViewBindings() || parentBinding == null) {
result.addMethod(createBindingUnbindMethod()); //然后到这里,初始化需要绑定的类
}
return result.build();
}
private MethodSpec createBindingViewDelegateConstructor() {
return MethodSpec.constructorBuilder()
.addJavadoc("@deprecated Use {@link #$T($T, $T)} for direct creation.\n "
+ "Only present for runtime invocation through {@code ButterKnife.bind()}.\n",
bindingClassName, targetTypeName, CONTEXT)
.addAnnotation(Deprecated.class)
.addAnnotation(UI_THREAD)
.addModifiers(PUBLIC)
.addParameter(targetTypeName, "target")
.addParameter(VIEW, "source")
.addStatement(("this(target, source.getContext())"))
.build();
}
private MethodSpec createBindingConstructorForView() {
MethodSpec.Builder builder = MethodSpec.constructorBuilder()
.addAnnotation(UI_THREAD)
.addModifiers(PUBLIC)
.addParameter(targetTypeName, "target");
if (constructorNeedsView()) {
builder.addStatement("this(target, target)");
} else {
builder.addStatement("this(target, target.getContext())");
}
return builder.build();
}
private MethodSpec createBindingConstructorForActivity() {
MethodSpec.Builder builder = MethodSpec.constructorBuilder()
.addAnnotation(UI_THREAD)
.addModifiers(PUBLIC)
.addParameter(targetTypeName, "target");
if (constructorNeedsView()) {
builder.addStatement("this(target, target.getWindow().getDecorView())");
} else {
builder.addStatement("this(target, target)");
}
return builder.build();
}
private MethodSpec createBindingConstructorForDialog() {
MethodSpec.Builder builder = MethodSpec.constructorBuilder()
.addAnnotation(UI_THREAD)
.addModifiers(PUBLIC)
.addParameter(targetTypeName, "target");
if (constructorNeedsView()) {
builder.addStatement("this(target, target.getWindow().getDecorView())");
} else {
builder.addStatement("this(target, target.getContext())");
}
return builder.build();
}
private MethodSpec createBindingConstructor() {
MethodSpec.Builder constructor = MethodSpec.constructorBuilder()
.addAnnotation(UI_THREAD)
.addModifiers(PUBLIC);
if (hasMethodBindings()) {
constructor.addParameter(targetTypeName, "target", FINAL);
} else {
constructor.addParameter(targetTypeName, "target");
}
if (constructorNeedsView()) {
constructor.addParameter(VIEW, "source");
} else {
constructor.addParameter(CONTEXT, "context");
}
if (parentBinding != null) {
if (parentBinding.constructorNeedsView()) {
constructor.addStatement("super(target, source)");
} else if (constructorNeedsView()) {
constructor.addStatement("super(target, source.getContext())");
} else {
constructor.addStatement("super(target, context)");
}
constructor.addCode("\n");
}
if (hasTargetField()) {
constructor.addStatement("this.target = target"); //这里给target赋值
constructor.addCode("\n");
}
if (hasViewBindings()) {
if (hasViewLocal()) {
// Local variable in which all views will be temporarily stored.
constructor.addStatement("$T view", VIEW);
}
for (ViewBinding binding : viewBindings) {
addViewBinding(constructor, binding);
}
}
return constructor.build();
}
private MethodSpec createBindingUnbindMethod() {
MethodSpec.Builder result = MethodSpec.methodBuilder("unbind")
.addAnnotation(Override.class)
.addModifiers(PUBLIC);
if (!isFinal && parentBinding == null) {
result.addAnnotation(CALL_SUPER);
}
if (hasTargetField()) {
if (hasFieldBindings()) {
result.addStatement("$T target = this.target", targetTypeName);
}
result.addStatement("if (target == null) throw new $T($S)", IllegalStateException.class,
"Bindings already cleared.");
result.addStatement("$N = null", hasFieldBindings() "this.target" : "target");
result.addCode("\n");
for (ViewBinding binding : viewBindings) {
if (binding.getFieldBinding() != null) {
result.addStatement("target.$L = null", binding.getFieldBinding().getName());
}
}
}
if (parentBinding != null) {
result.addCode("\n");
result.addStatement("super.unbind()");
}
return result.build();
}
private void addViewBinding(MethodSpec.Builder result, ViewBinding binding) {
if (binding.isSingleFieldBinding()) {
// Optimize the common case where there's a single binding directly to a field.
FieldViewBinding fieldBinding = requireNonNull(binding.getFieldBinding());
CodeBlock.Builder builder = CodeBlock.builder()
.add("target.$L = ", fieldBinding.getName());
boolean requiresCast = requiresCast(fieldBinding.getType());
if (!debuggable || (!requiresCast && !fieldBinding.isRequired())) {
if (requiresCast) {
builder.add("($T) ", fieldBinding.getType());
}
builder.add("source.findViewById($L)", binding.getId().code);
} else {
builder.add("$T.find", UTILS);
builder.add(fieldBinding.isRequired() "RequiredView" : "OptionalView");
if (requiresCast) {
builder.add("AsType");
}
builder.add("(source, $L", binding.getId().code);
if (fieldBinding.isRequired() || requiresCast) {
builder.add(", $S", asHumanDescription(singletonList(fieldBinding)));
}
if (requiresCast) {
builder.add(", $T.class", fieldBinding.getRawType());
}
builder.add(")");
}
result.addStatement("$L", builder.build());
return;
}
List<MemberViewBinding> requiredBindings = binding.getRequiredBindings();
if (!debuggable || requiredBindings.isEmpty()) {
result.addStatement("view = source.findViewById($L)", binding.getId().code);
} else if (!binding.isBoundToRoot()) {
result.addStatement("view = $T.findRequiredView(source, $L, $S)", UTILS,
binding.getId().code, asHumanDescription(requiredBindings));
}
addFieldBinding(result, binding, debuggable);
addMethodBindings(result, binding, debuggable);
}
private void addFieldBinding(MethodSpec.Builder result, ViewBinding binding, boolean debuggable) {
FieldViewBinding fieldBinding = binding.getFieldBinding();
if (fieldBinding != null) {
if (requiresCast(fieldBinding.getType())) {
if (debuggable) {
result.addStatement("target.$L = $T.castView(view, $L, $S, $T.class)",
fieldBinding.getName(), UTILS, binding.getId().code,
asHumanDescription(singletonList(fieldBinding)), fieldBinding.getRawType());
} else {
result.addStatement("target.$L = ($T) view", fieldBinding.getName(),
fieldBinding.getType());
}
} else {
result.addStatement("target.$L = view", fieldBinding.getName());
}
}
}
private void addMethodBindings(MethodSpec.Builder result, ViewBinding binding, boolean debuggable) {
// Map<ListenerClass, Map<ListenerMethod, Set<MethodViewBinding>>> classMethodBindings =
// binding.getMethodBindings();
// if (classMethodBindings.isEmpty()) {
// return;
// }
//
// // We only need to emit the null check if there are zero required bindings.
// boolean needsNullChecked = binding.getRequiredBindings().isEmpty();
// if (needsNullChecked) {
// result.beginControlFlow("if (view != null)");
// }
//
// // Add the view reference to the binding.
// String fieldName = "viewSource";
// String bindName = "source";
// if (!binding.isBoundToRoot()) {
// fieldName = "view" + Integer.toHexString(binding.getId().value);
// bindName = "view";
// }
// result.addStatement("$L = $N", fieldName, bindName);
//
// for (Map.Entry<ListenerClass, Map<ListenerMethod, Set<MethodViewBinding>>> e
// : classMethodBindings.entrySet()) {
// ListenerClass listener = e.getKey();
// Map<ListenerMethod, Set<MethodViewBinding>> methodBindings = e.getValue();
//
// TypeSpec.Builder callback = TypeSpec.anonymousClassBuilder("")
// .superclass(ClassName.bestGuess(listener.type()));
//
// for (ListenerMethod method : getListenerMethods(listener)) {
// MethodSpec.Builder callbackMethod = MethodSpec.methodBuilder(method.name())
// .addAnnotation(Override.class)
// .addModifiers(PUBLIC)
// .returns(bestGuess(method.returnType()));
// String[] parameterTypes = method.parameters();
// for (int i = 0, count = parameterTypes.length; i < count; i++) {
// callbackMethod.addParameter(bestGuess(parameterTypes[i]), "p" + i);
// }
//
// boolean hasReturnValue = false;
// CodeBlock.Builder builder = CodeBlock.builder();
// Set<MethodViewBinding> methodViewBindings = methodBindings.get(method);
// if (methodViewBindings != null) {
// for (MethodViewBinding methodBinding : methodViewBindings) {
// if (methodBinding.hasReturnValue()) {
// hasReturnValue = true;
// builder.add("return "); // TODO what about multiple methods?
// }
// builder.add("target.$L(", methodBinding.getName());
// List<Parameter> parameters = methodBinding.getParameters();
// String[] listenerParameters = method.parameters();
// for (int i = 0, count = parameters.size(); i < count; i++) {
// if (i > 0) {
// builder.add(", ");
// }
//
// Parameter parameter = parameters.get(i);
// int listenerPosition = parameter.getListenerPosition();
//
// if (parameter.requiresCast(listenerParameters[listenerPosition])) {
// if (debuggable) {
// builder.add("$T.castParam(p$L, $S, $L, $S, $L, $T.class)", UTILS,
// listenerPosition, method.name(), listenerPosition, methodBinding.getName(), i,
// parameter.getType());
// } else {
// builder.add("($T) p$L", parameter.getType(), listenerPosition);
// }
// } else {
// builder.add("p$L", listenerPosition);
// }
// }
// builder.add(");\n");
// }
// }
//
// if (!"void".equals(method.returnType()) && !hasReturnValue) {
// builder.add("return $L;\n", method.defaultReturn());
// }
//
// callbackMethod.addCode(builder.build());
// callback.addMethod(callbackMethod.build());
// }
//
// boolean requiresRemoval = listener.remover().length() != 0;
// String listenerField = null;
// if (requiresRemoval) {
// TypeName listenerClassName = bestGuess(listener.type());
// listenerField = fieldName + ((ClassName) listenerClassName).simpleName();
// result.addStatement("$L = $L", listenerField, callback.build());
// }
//
// String targetType = listener.targetType();
// if (!VIEW_TYPE.equals(targetType)) {
// result.addStatement("(($T) $N).$L($L)", bestGuess(targetType), bindName,
// listener.setter(), requiresRemoval listenerField : callback.build());
// } else {
// result.addStatement("$N.$L($L)", bindName, listener.setter(),
// requiresRemoval listenerField : callback.build());
// }
// }
//
// if (needsNullChecked) {
// result.endControlFlow();
// }
}
// private static List<ListenerMethod> getListenerMethods(ListenerClass listener) {
// if (listener.method().length == 1) {
// return Arrays.asList(listener.method());
// }
//
// try {
// List<ListenerMethod> methods = new ArrayList<>();
// Class<extends Enum<?>> callbacks = listener.callbacks();
// for (Enum<?> callbackMethod : callbacks.getEnumConstants()) {
// Field callbackField = callbacks.getField(callbackMethod.name());
// ListenerMethod method = callbackField.getAnnotation(ListenerMethod.class);
// if (method == null) {
// throw new IllegalStateException(String.format("@%s's %s.%s missing @%s annotation.",
// callbacks.getEnclosingClass().getSimpleName(), callbacks.getSimpleName(),
// callbackMethod.name(), ListenerMethod.class.getSimpleName()));
// }
// methods.add(method);
// }
// return methods;
// } catch (NoSuchFieldException e) {
// throw new AssertionError(e);
// }
// }
static String asHumanDescription(Collection<extends MemberViewBinding> bindings) {
Iterator<extends MemberViewBinding> iterator = bindings.iterator();
switch (bindings.size()) {
case 1:
return iterator.next().getDescription();
case 2:
return iterator.next().getDescription() + " and " + iterator.next().getDescription();
default:
StringBuilder builder = new StringBuilder();
for (int i = 0, count = bindings.size(); i < count; i++) {
if (i != 0) {
builder.append(", ");
}
if (i == count - 1) {
builder.append("and ");
}
builder.append(iterator.next().getDescription());
}
return builder.toString();
}
}
/**
* True when this type's bindings require a view hierarchy.
*/
private boolean hasViewBindings() {
return !viewBindings.isEmpty();
}
private boolean hasMethodBindings() {
// for (ViewBinding bindings : viewBindings) {
// if (!bindings.getMethodBindings().isEmpty()) {
// return true;
// }
// }
return false;
}
private boolean hasFieldBindings() {
for (ViewBinding bindings : viewBindings) {
if (bindings.getFieldBinding() != null) {
return true;
}
}
return false;
}
private boolean hasTargetField() {
return hasFieldBindings() || hasMethodBindings();
}
private boolean hasViewLocal() {
for (ViewBinding bindings : viewBindings) {
if (bindings.requiresLocal()) {
return true;
}
}
return false;
}
/**
* True if this binding requires a view. Otherwise only a context is needed.
*/
@Override
public boolean constructorNeedsView() {
return hasViewBindings() //
|| (parentBinding != null && parentBinding.constructorNeedsView());
}
static boolean requiresCast(TypeName type) {
return !VIEW_TYPE.equals(type.toString());
}
@Override
public String toString() {
return bindingClassName.toString();
}
static Builder newBuilder(TypeElement enclosingElement) {
TypeMirror typeMirror = enclosingElement.asType();
boolean isView = isSubtypeOfType(typeMirror, VIEW_TYPE);
boolean isActivity = isSubtypeOfType(typeMirror, ACTIVITY_TYPE);
boolean isDialog = isSubtypeOfType(typeMirror, DIALOG_TYPE);
TypeName targetType = TypeName.get(typeMirror);
if (targetType instanceof ParameterizedTypeName) {
targetType = ((ParameterizedTypeName) targetType).rawType;
}
ClassName bindingClassName = getBindingClassName(enclosingElement);
boolean isFinal = enclosingElement.getModifiers().contains(Modifier.FINAL);
return new Builder(targetType, bindingClassName, enclosingElement, isFinal, isView, isActivity, isDialog);
}
static ClassName getBindingClassName(TypeElement typeElement) {
String packageName = getPackage(typeElement).getQualifiedName().toString();
String className = typeElement.getQualifiedName().toString().substring(
packageName.length() + 1).replace('.', '$');
return ClassName.get(packageName, className + "_ViewBinding"); //这里指定生成类名
}
static final class Builder {
private final TypeName targetTypeName;
private final ClassName bindingClassName;
private final TypeElement enclosingElement;
private final boolean isFinal;
private final boolean isView;
private final boolean isActivity;
private final boolean isDialog;
private @Nullable
BindingInformationProvider parentBinding;
private final Map<Id, ViewBinding.Builder> viewIdMap = new LinkedHashMap<>();
private Builder(TypeName targetTypeName, ClassName bindingClassName, TypeElement enclosingElement,
boolean isFinal, boolean isView, boolean isActivity, boolean isDialog) {
this.targetTypeName = targetTypeName;
this.bindingClassName = bindingClassName;
this.enclosingElement = enclosingElement;
this.isFinal = isFinal;
this.isView = isView;
this.isActivity = isActivity;
this.isDialog = isDialog;
}
void addField(Id id, FieldViewBinding binding) {
getOrCreateViewBindings(id).setFieldBinding(binding);
}
void setParent(BindingInformationProvider parent) {
this.parentBinding = parent;
}
private ViewBinding.Builder getOrCreateViewBindings(Id id) {
ViewBinding.Builder viewId = viewIdMap.get(id);
if (viewId == null) {
viewId = new ViewBinding.Builder(id);
viewIdMap.put(id, viewId);
}
return viewId;
}
BindingSet build() {
ImmutableList.Builder<ViewBinding> viewBindings = ImmutableList.builder();
for (ViewBinding.Builder builder : viewIdMap.values()) {
viewBindings.add(builder.build());
}
return new BindingSet(targetTypeName, bindingClassName, enclosingElement, isFinal, isView,
isActivity, isDialog, viewBindings.build(), parentBinding);
}
}
}
interface BindingInformationProvider {
boolean constructorNeedsView();
ClassName getBindingClassName();
}
执行过程后面加了注释
代码地址:https://gitee.com/sunshuo1092373331/apt.git