Search in sources :

Example 1 with BindViews

use of butterknife.BindViews in project butterknife by JakeWharton.

the class ButterKnifeProcessor method findAndParseTargets.

private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
    Map<TypeElement, BindingSet.Builder> builderMap = new LinkedHashMap<>();
    Set<TypeElement> erasedTargetNames = new LinkedHashSet<>();
    scanForRClasses(env);
    // Process each @BindAnim element.
    for (Element element : env.getElementsAnnotatedWith(BindAnim.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceAnimation(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindAnim.class, e);
        }
    }
    // Process each @BindArray element.
    for (Element element : env.getElementsAnnotatedWith(BindArray.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceArray(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindArray.class, e);
        }
    }
    // Process each @BindBitmap element.
    for (Element element : env.getElementsAnnotatedWith(BindBitmap.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceBitmap(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindBitmap.class, e);
        }
    }
    // Process each @BindBool element.
    for (Element element : env.getElementsAnnotatedWith(BindBool.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceBool(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindBool.class, e);
        }
    }
    // Process each @BindColor element.
    for (Element element : env.getElementsAnnotatedWith(BindColor.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceColor(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindColor.class, e);
        }
    }
    // Process each @BindDimen element.
    for (Element element : env.getElementsAnnotatedWith(BindDimen.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceDimen(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindDimen.class, e);
        }
    }
    // Process each @BindDrawable element.
    for (Element element : env.getElementsAnnotatedWith(BindDrawable.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceDrawable(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindDrawable.class, e);
        }
    }
    // Process each @BindFloat element.
    for (Element element : env.getElementsAnnotatedWith(BindFloat.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceFloat(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindFloat.class, e);
        }
    }
    // Process each @BindFont element.
    for (Element element : env.getElementsAnnotatedWith(BindFont.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceFont(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindFont.class, e);
        }
    }
    // Process each @BindInt element.
    for (Element element : env.getElementsAnnotatedWith(BindInt.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceInt(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindInt.class, e);
        }
    }
    // Process each @BindString element.
    for (Element element : env.getElementsAnnotatedWith(BindString.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceString(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindString.class, e);
        }
    }
    // Process each @BindView element.
    for (Element element : env.getElementsAnnotatedWith(BindView.class)) {
        // so that an unresolved View type can be generated by later processing rounds
        try {
            parseBindView(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindView.class, e);
        }
    }
    // Process each @BindViews element.
    for (Element element : env.getElementsAnnotatedWith(BindViews.class)) {
        // so that an unresolved View type can be generated by later processing rounds
        try {
            parseBindViews(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindViews.class, e);
        }
    }
    // Process each annotation that corresponds to a listener.
    for (Class<? extends Annotation> listener : LISTENERS) {
        findAndParseListener(env, listener, builderMap, erasedTargetNames);
    }
    // Associate superclass binders with their subclass binders. This is a queue-based tree walk
    // which starts at the roots (superclasses) and walks to the leafs (subclasses).
    Deque<Map.Entry<TypeElement, BindingSet.Builder>> entries = new ArrayDeque<>(builderMap.entrySet());
    Map<TypeElement, BindingSet> bindingMap = new LinkedHashMap<>();
    while (!entries.isEmpty()) {
        Map.Entry<TypeElement, BindingSet.Builder> entry = entries.removeFirst();
        TypeElement type = entry.getKey();
        BindingSet.Builder builder = entry.getValue();
        TypeElement parentType = findParentType(type, erasedTargetNames);
        if (parentType == null) {
            bindingMap.put(type, builder.build());
        } else {
            BindingSet parentBinding = bindingMap.get(parentType);
            if (parentBinding != null) {
                builder.setParent(parentBinding);
                bindingMap.put(type, builder.build());
            } else {
                // Has a superclass binding but we haven't built it yet. Re-enqueue for later.
                entries.addLast(entry);
            }
        }
    }
    return bindingMap;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) PackageElement(javax.lang.model.element.PackageElement) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) LinkedHashMap(java.util.LinkedHashMap) BindDimen(butterknife.BindDimen) BindInt(butterknife.BindInt) BindAnim(butterknife.BindAnim) BindFont(butterknife.BindFont) BindFloat(butterknife.BindFloat) BindDrawable(butterknife.BindDrawable) BindBitmap(butterknife.BindBitmap) BindString(butterknife.BindString) TypeElement(javax.lang.model.element.TypeElement) BindArray(butterknife.BindArray) MirroredTypeException(javax.lang.model.type.MirroredTypeException) IOException(java.io.IOException) BindViews(butterknife.BindViews) ArrayDeque(java.util.ArrayDeque) BindColor(butterknife.BindColor) BindBool(butterknife.BindBool) BindView(butterknife.BindView) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 2 with BindViews

use of butterknife.BindViews in project AndroidLife by CaMnter.

the class ButterKnifeProcessor method findAndParseTargets.

/**
 * 1.扫描 R class,并解析
 * 2.SuperficialValidation.validateElement(...) google auto 验证 javax Element
 * 3.处理 @BindArray
 * 4.处理 @BindBitmap
 * 5.处理 @BindBool
 * 6.处理 @BindColor
 * 7.处理 @BindDimen
 * 8.处理 @BindDrawable
 * 9.处理 @BindFloat
 * 10.处理 @BindInt
 * 11.处理 @BindString
 * 12.处理 @BindView
 * 13.处理 @BindViews
 * 14.处理事件( @OnCheckedChanged, @OnClick, @OnEditorAction, @OnFocusChange, @OnItemClick 等)
 * 15.BindingSet.Builder Map 缓存生成 BindingSet Map 缓存
 *
 * @param env RoundEnvironment
 * @return Map
 */
private Map<TypeElement, BindingSet> findAndParseTargets(RoundEnvironment env) {
    Map<TypeElement, BindingSet.Builder> builderMap = new LinkedHashMap<>();
    Set<TypeElement> erasedTargetNames = new LinkedHashSet<>();
    // TODO Mark 1
    scanForRClasses(env);
    // Process each @BindArray element.
    for (Element element : env.getElementsAnnotatedWith(BindArray.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceArray(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindArray.class, e);
        }
    }
    // Process each @BindBitmap element.
    for (Element element : env.getElementsAnnotatedWith(BindBitmap.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceBitmap(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindBitmap.class, e);
        }
    }
    // Process each @BindBool element.
    for (Element element : env.getElementsAnnotatedWith(BindBool.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceBool(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindBool.class, e);
        }
    }
    // Process each @BindColor element.
    for (Element element : env.getElementsAnnotatedWith(BindColor.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceColor(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindColor.class, e);
        }
    }
    // Process each @BindDimen element.
    for (Element element : env.getElementsAnnotatedWith(BindDimen.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceDimen(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindDimen.class, e);
        }
    }
    // Process each @BindDrawable element.
    for (Element element : env.getElementsAnnotatedWith(BindDrawable.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceDrawable(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindDrawable.class, e);
        }
    }
    // Process each @BindFloat element.
    for (Element element : env.getElementsAnnotatedWith(BindFloat.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceFloat(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindFloat.class, e);
        }
    }
    // Process each @BindInt element.
    for (Element element : env.getElementsAnnotatedWith(BindInt.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceInt(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindInt.class, e);
        }
    }
    // Process each @BindString element.
    for (Element element : env.getElementsAnnotatedWith(BindString.class)) {
        if (!SuperficialValidation.validateElement(element))
            continue;
        try {
            parseResourceString(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindString.class, e);
        }
    }
    // Process each @BindView element.
    for (Element element : env.getElementsAnnotatedWith(BindView.class)) {
        // so that an unresolved View type can be generated by later processing rounds
        try {
            parseBindView(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindView.class, e);
        }
    }
    // Process each @BindViews element.
    for (Element element : env.getElementsAnnotatedWith(BindViews.class)) {
        // so that an unresolved View type can be generated by later processing rounds
        try {
            parseBindViews(element, builderMap, erasedTargetNames);
        } catch (Exception e) {
            logParsingError(element, BindViews.class, e);
        }
    }
    // Process each annotation that corresponds to a listener.
    for (Class<? extends Annotation> listener : LISTENERS) {
        findAndParseListener(env, listener, builderMap, erasedTargetNames);
    }
    /*
         * TODO Mark 2
         *
         * 1.遍历 BindingSet.Builder Map 缓存
         * 2.拿到每个 .java 元素 和其对应的 BindingSet.Builder 缓存
         * 3.寻找 .java 元素的父类型元素
         * - 不存在的话,就直接构建
         * - 存在的话,查看父类型的 Builder 缓存。有的话,设置 Parent,开始构建。没有的话,放入 BindingSet.Builder 缓存 的末尾
         * 4.构建后的数据,会生成 BindingSet Map 缓存
         */
    // Associate superclass binders with their subclass binders. This is a queue-based tree walk
    // which starts at the roots (superclasses) and walks to the leafs (subclasses).
    Deque<Map.Entry<TypeElement, BindingSet.Builder>> entries = new ArrayDeque<>(builderMap.entrySet());
    Map<TypeElement, BindingSet> bindingMap = new LinkedHashMap<>();
    while (!entries.isEmpty()) {
        Map.Entry<TypeElement, BindingSet.Builder> entry = entries.removeFirst();
        TypeElement type = entry.getKey();
        BindingSet.Builder builder = entry.getValue();
        TypeElement parentType = findParentType(type, erasedTargetNames);
        if (parentType == null) {
            bindingMap.put(type, builder.build());
        } else {
            BindingSet parentBinding = bindingMap.get(parentType);
            if (parentBinding != null) {
                builder.setParent(parentBinding);
                bindingMap.put(type, builder.build());
            } else {
                // Has a superclass binding but we haven't built it yet. Re-enqueue for later.
                entries.addLast(entry);
            }
        }
    }
    return bindingMap;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) LinkedHashMap(java.util.LinkedHashMap) BindDimen(butterknife.BindDimen) BindInt(butterknife.BindInt) BindFloat(butterknife.BindFloat) BindDrawable(butterknife.BindDrawable) BindBitmap(butterknife.BindBitmap) BindString(butterknife.BindString) TypeElement(javax.lang.model.element.TypeElement) BindArray(butterknife.BindArray) MirroredTypeException(javax.lang.model.type.MirroredTypeException) IOException(java.io.IOException) BindViews(butterknife.BindViews) ArrayDeque(java.util.ArrayDeque) BindColor(butterknife.BindColor) BindBool(butterknife.BindBool) BindView(butterknife.BindView) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap)

Example 3 with BindViews

use of butterknife.BindViews in project AndroidLife by CaMnter.

the class ButterKnifeProcessor method parseBindViews.

/**
 * 解析 BindViews
 *
 * 1.拿到 BindArray 注解元素 的 .java 类元素
 * 2.检查注解使用错误,或者注解所在的环境问题( 比如 private or static,所在的 .java 是 private 等 )
 * - 有错误就 return
 * 3.获取元素的类型
 * 4.校验是否是 Array 或者 List,不是则报错返回
 * 5.校验元素类型( 不是 View 的子类,并且不是接口类型 ),报错返回
 * 6.获取该 .java 元素对应的 BindingSet.Builder,没有则创建
 * 7.注解中抽出一组 Id,校验是否有重复 id
 * 8.包装成  FieldCollectionViewBinding 添加到 BindingSet.Builder
 * 9.记录 .java 元素 为要删除的目录
 *
 * @param element BindBitmap 注解元素
 * @param builderMap BindingSet.Builder 缓存 Map
 * @param erasedTargetNames 要删除元素的目录,存在的是 .java 的元素
 */
private void parseBindViews(Element element, Map<TypeElement, BindingSet.Builder> builderMap, Set<TypeElement> erasedTargetNames) {
    TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
    // Start by verifying common generated code restrictions.
    boolean hasError = isInaccessibleViaGeneratedCode(BindViews.class, "fields", element) || isBindingInWrongPackage(BindViews.class, element);
    // Verify that the type is a List or an array.
    TypeMirror elementType = element.asType();
    String erasedType = doubleErasure(elementType);
    TypeMirror viewType = null;
    FieldCollectionViewBinding.Kind kind = null;
    if (elementType.getKind() == TypeKind.ARRAY) {
        ArrayType arrayType = (ArrayType) elementType;
        viewType = arrayType.getComponentType();
        kind = FieldCollectionViewBinding.Kind.ARRAY;
    } else if (LIST_TYPE.equals(erasedType)) {
        DeclaredType declaredType = (DeclaredType) elementType;
        List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
        if (typeArguments.size() != 1) {
            error(element, "@%s List must have a generic component. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
            hasError = true;
        } else {
            viewType = typeArguments.get(0);
        }
        kind = FieldCollectionViewBinding.Kind.LIST;
    } else {
        error(element, "@%s must be a List or array. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
        hasError = true;
    }
    if (viewType != null && viewType.getKind() == TypeKind.TYPEVAR) {
        TypeVariable typeVariable = (TypeVariable) viewType;
        viewType = typeVariable.getUpperBound();
    }
    // Verify that the target type extends from View.
    if (viewType != null && !isSubtypeOfType(viewType, VIEW_TYPE) && !isInterface(viewType)) {
        if (viewType.getKind() == TypeKind.ERROR) {
            note(element, "@%s List or array with unresolved type (%s) " + "must elsewhere be generated as a View or interface. (%s.%s)", BindViews.class.getSimpleName(), viewType, enclosingElement.getQualifiedName(), element.getSimpleName());
        } else {
            error(element, "@%s List or array type must extend from View or be an interface. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
            hasError = true;
        }
    }
    // Assemble information on the field.
    String name = element.getSimpleName().toString();
    int[] ids = element.getAnnotation(BindViews.class).value();
    if (ids.length == 0) {
        error(element, "@%s must specify at least one ID. (%s.%s)", BindViews.class.getSimpleName(), enclosingElement.getQualifiedName(), element.getSimpleName());
        hasError = true;
    }
    Integer duplicateId = findDuplicate(ids);
    if (duplicateId != null) {
        error(element, "@%s annotation contains duplicate ID %d. (%s.%s)", BindViews.class.getSimpleName(), duplicateId, enclosingElement.getQualifiedName(), element.getSimpleName());
        hasError = true;
    }
    if (hasError) {
        return;
    }
    // Always false as hasError would have been true.
    assert viewType != null;
    TypeName type = TypeName.get(viewType);
    boolean required = isFieldRequired(element);
    List<Id> idVars = new ArrayList<>();
    for (int id : ids) {
        QualifiedId qualifiedId = elementToQualifiedId(element, id);
        idVars.add(getId(qualifiedId));
    }
    BindingSet.Builder builder = getOrCreateBindingBuilder(builderMap, enclosingElement);
    builder.addFieldCollection(new FieldCollectionViewBinding(name, type, kind, idVars, required));
    erasedTargetNames.add(enclosingElement);
}
Also used : TypeName(com.squareup.javapoet.TypeName) TypeElement(javax.lang.model.element.TypeElement) ArrayList(java.util.ArrayList) BindString(butterknife.BindString) BindViews(butterknife.BindViews) ArrayType(javax.lang.model.type.ArrayType) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) List(java.util.List) ArrayList(java.util.ArrayList) DeclaredType(javax.lang.model.type.DeclaredType)

Aggregations

BindString (butterknife.BindString)3 BindViews (butterknife.BindViews)3 TypeElement (javax.lang.model.element.TypeElement)3 BindArray (butterknife.BindArray)2 BindBitmap (butterknife.BindBitmap)2 BindBool (butterknife.BindBool)2 BindColor (butterknife.BindColor)2 BindDimen (butterknife.BindDimen)2 BindDrawable (butterknife.BindDrawable)2 BindFloat (butterknife.BindFloat)2 BindInt (butterknife.BindInt)2 BindView (butterknife.BindView)2 IOException (java.io.IOException)2 ArrayDeque (java.util.ArrayDeque)2 LinkedHashMap (java.util.LinkedHashMap)2 LinkedHashSet (java.util.LinkedHashSet)2 Map (java.util.Map)2 Element (javax.lang.model.element.Element)2 ExecutableElement (javax.lang.model.element.ExecutableElement)2 VariableElement (javax.lang.model.element.VariableElement)2