1. 1 – InterceptorProcessor ARouter to explain

  2. 2 – AutowiredProcessor ARouter interpretation

  3. 3 _routeprocessor ARouter interpretation

  4. 4 _core Arouter explanation

Autowired

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {

    // Mark param's name or service name.
    String name(a) default "";

    // If required, app will be crash when value is null.
    // Primitive type wont be check!
    boolean required(a) default false;

    // Description of the field
    String desc(a) default "";
}
Copy the code

An overview of the

The use of Autowired is to inject fields, or else use methods like getIntent().getintextra (). This will also generate a new class in which the injected operations will operate. Like the following classes

Break down

The 1-interceptorProcessor is provided by the ARouter InterceptorProcessor, but it is also provided by the ARouter InterceptorProcessor. The 1-interceptorProcessor is provided by the ARouter InterceptorProcessor, but it is also provided by the ARouter InterceptorProcessor.

// Autowired annotations are applied to fields in a class or interface, where the key in the HashMap is the class or interface and the value is the Autowired annotated element in the class
private Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();


public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
    if (CollectionUtils.isNotEmpty(set)) {
        try {
            this.categories(roundEnvironment.getElementsAnnotatedWith(Autowired.class));
            this.generateHelper();
        } catch (Exception var4) {
            this.logger.error(var4);
        }

        return true;
    } else {
        return false; }}// Elements in the method are field elements, which are usually in the class or interface
private void categories(Set<? extends Element> elements) throws IllegalAccessException {
        if (CollectionUtils.isNotEmpty(elements)) {
            for (Element element : elements) {
                // Get the class or interface of this field
                TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
				// This class or interface cannot be private
                if (element.getModifiers().contains(Modifier.PRIVATE)) {
                    throw new IllegalAccessException("The inject fields CAN NOT BE 'private'!!! please check field ["
                            + element.getSimpleName() + "] in class [" + enclosingElement.getQualifiedName() + "]");
                }
                
                if (parentAndChild.containsKey(enclosingElement)) { // Has categries
                    parentAndChild.get(enclosingElement).add(element);
                } else {
                    List<Element> childs = new ArrayList<>();
                    childs.add(element);
                    parentAndChild.put(enclosingElement, childs);
                }
            }

            logger.info("categories finished."); }}Copy the code

ParentAndChild is a collection of all Autowired annotated fields in a class.

package com.alibaba.android.arouter.facade.template;

public interface ISyringe {
    void inject(Object target);
}
Copy the code
private void generateHelper(a) throws IOException, IllegalAccessException {

    // Prepare some elements first
    // com.alibaba.android.arouter.facade.template.ISyringe
    TypeElement type_ISyringe = elementUtils.getTypeElement(ISYRINGE);
    / / com. Alibaba. Android. Arouter. Facade. Service. This is a IProvider SerializationService, behind us
    TypeElement type_JsonService = elementUtils.getTypeElement(JSON_SERVICE);
    
    // com.alibaba.android.arouter.facade.template.IProvider
    TypeMirror iProvider = elementUtils.getTypeElement(Consts.IPROVIDER).asType();
    
    // android.app.Activity
    TypeMirror activityTm = elementUtils.getTypeElement(Consts.ACTIVITY).asType();
    
    // android.app.Fragment
    TypeMirror fragmentTm = elementUtils.getTypeElement(Consts.FRAGMENT).asType();
    
    // android.support.v4.app.Fragment
    TypeMirror fragmentTmV4 = elementUtils.getTypeElement(Consts.FRAGMENT_V4).asType();

    
    // Build input param name.
    // The method parameter type and parameter name
    ParameterSpec objectParamSpec = ParameterSpec.builder(TypeName.OBJECT, "target").build();

    if (MapUtils.isNotEmpty(parentAndChild)) {
        // Iterate over a field with an Autowired annotation inside each class
        for (Map.Entry<TypeElement, List<Element>> entry : parentAndChild.entrySet()) {
            // Build method : 'inject'
            // Build a method, public void inject(Object target)
            MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder(METHOD_INJECT)
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .addParameter(objectParamSpec);

            TypeElement parent = entry.getKey();
            List<Element> childs = entry.getValue();

            // The fully qualified name of the class
            String qualifiedName = parent.getQualifiedName().toString();
            // Class package name
            String packageName = qualifiedName.substring(0, qualifiedName.lastIndexOf("."));
            $$ARouter$$Autowired $$ARouter$$Autowired
            String fileName = parent.getSimpleName() + NAME_OF_AUTOWIRED;


            // Build a class that implements the ISyringe interface. Access is public
            TypeSpec.Builder helper = TypeSpec.classBuilder(fileName)
                    .addJavadoc(WARNING_TIPS)
                    .addSuperinterface(ClassName.get(type_ISyringe))
                    .addModifiers(PUBLIC);

            // Add a member variable serializationService
            FieldSpec jsonServiceField = FieldSpec.builder(TypeName.get(type_JsonService.asType()), "serializationService", Modifier.PRIVATE).build();
            helper.addField(jsonServiceField);

            // Inside the inject method
            // serializationService = ARouter.getInstance().navigation(SerializationService.class);
            // serializationService serializes objects and converts them to JSON for delivery
            injectMethodBuilder.addStatement("serializationService = $T.getInstance().navigation($T.class)", ARouterClass, ClassName.get(type_JsonService));
            injectMethodBuilder.addStatement("$T substitute = ($T)target", ClassName.get(parent), ClassName.get(parent));

            // Generate method body, start inject.
            for (Element element : childs) {
                Autowired fieldConfig = element.getAnnotation(Autowired.class);
                // The element name
                String fieldName = element.getSimpleName().toString();
                
                if (types.isSubtype(element.asType(), iProvider)) {  // It's provider
                    If element is a subclass of IProvider
                    if ("".equals(fieldConfig.name())) {    // User has not set service path, then use byType.

                        // Getter
                        // substitute.{fieldName} = arouter.getInstance ().navigation({elementClass}.class),{} indicates placeholder
                        injectMethodBuilder.addStatement(
                                "substitute." + fieldName + " = $T.getInstance().navigation($T.class)",
                                ARouterClass,
                                ClassName.get(element.asType())
                        );
                    } else {    // use byName
                        // Getter
                          // substitute.{fieldName} =({elementClass}) ARouter.getInstance().build({ConfigName}).navigation()
                        injectMethodBuilder.addStatement(
                                "substitute." + fieldName + " = ($T)$T.getInstance().build($S).navigation()",
                                ClassName.get(element.asType()),
                                ARouterClass,
                                fieldConfig.name()
                        );
                    }

                    // Validator
                    if (fieldConfig.required()) {
                        // If required is true, check for null after injection
                        injectMethodBuilder.beginControlFlow("if (substitute." + fieldName + " == null)");
                        injectMethodBuilder.addStatement(
                                "throw new RuntimeException(\"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"! \ ")", ClassName.get(parent)); injectMethodBuilder.endControlFlow(); }}else {    // It's normal intent value
                   
                    String originalValue = "substitute." + fieldName;
                    String statement = "substitute." + fieldName + "=" + buildCastCode(element) + "substitute.";
                    boolean isActivity = false;
                    if (types.isSubtype(parent.asType(), activityTm)) {  // Activity, then use getIntent()
                        Age = substitute. GetIntent (). GetIntExtra ("age", substitute. Age);
                        isActivity = true;
                        statement += "getIntent().";
                    } else if (types.isSubtype(parent.asType(), fragmentTm) || types.isSubtype(parent.asType(), fragmentTmV4)) {   // Fragment, then use getArguments()
                        // Analogs substitute.name = substitute.getarguments ().getString("name", substitute.name);
                        statement += "getArguments().";
                    } else {
                        throw new IllegalAccessException("The field [" + fieldName + "] need autowired from intent, its parent must be activity or fragment!");
                    }

                    statement = buildStatement(originalValue, statement, typeUtils.typeExchange(element), isActivity, isKtClass(parent));
                    if (statement.startsWith("serializationService.")) {   // Not mortals
                        injectMethodBuilder.beginControlFlow("if (null ! = serializationService)");
                        injectMethodBuilder.addStatement(
                                "substitute." + fieldName + "=" + statement,
                                (StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name()),
                                ClassName.get(element.asType())
                        );
                        injectMethodBuilder.nextControlFlow("else");
                        injectMethodBuilder.addStatement(
                                "$T.e(\"" + Consts.TAG + "\", \"You want automatic inject the field '" + fieldName + "' in class '$T' , then you should implement 'SerializationService' to support object auto inject! \ ")", AndroidLog, ClassName.get(parent));
                        injectMethodBuilder.endControlFlow();
                    } else {
                        injectMethodBuilder.addStatement(statement, StringUtils.isEmpty(fieldConfig.name()) ? fieldName : fieldConfig.name());
                    }

                    // Validator
                    if(fieldConfig.required() && ! element.asType().getKind().isPrimitive()) {// Primitive wont be check.
                        injectMethodBuilder.beginControlFlow("if (null == substitute." + fieldName + ")");
                        injectMethodBuilder.addStatement(
                                "$T.e(\"" + Consts.TAG + "\", \"The field '" + fieldName + "' is null, in class '\" + $T.class.getName() + \"! \ ")", AndroidLog, ClassName.get(parent));
                        injectMethodBuilder.endControlFlow();
                    }
                }
            }

            helper.addMethod(injectMethodBuilder.build());

            // Generate autowire helper
            JavaFile.builder(packageName, helper.build()).build().writeTo(mFiler);

            logger.info("> > >" + parent.getSimpleName() + " has been processed, " + fileName + " has been generated. <<<");
        }

        logger.info(">>> Autowired processor stop. <<<"); }}Copy the code

The resulting class looks something like this