Search in sources :

Example 1 with Pair

use of com.google.common.base.Pair in project tiger by google.

the class CoreInjectorGenerator method generateTopLevelInjectors.

private void generateTopLevelInjectors() {
    messager.printMessage(Kind.NOTE, "generateTopLevelInjectors");
    SetMultimap<BindingKey, ClassName> keyToPackagedInjectorMap = utils.reverseSetMultimap(generatedBindingsForPackagedInjector);
    for (CoreInjectorInfo coreInjectorInfo : orderedCoreinjectors) {
        TypeSpec.Builder injectorBuilder = TypeSpec.classBuilder(getTopLevelInjectorName(coreInjectorInfo, topLevelInjectorPrefix, topLevelInjectorSuffix)).addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", "$S", GENERATOR_NAME).build()).addModifiers(Modifier.PUBLIC);
        // method simple name and type.
        Set<Pair<String, TypeName>> injectionMethodsDone = new HashSet<>();
        // Member injector interfaces.
        for (TypeElement injector : coreInjectorToComponentMap.get(coreInjectorInfo)) {
            injectorBuilder.addSuperinterface(TypeName.get(injector.asType()));
        }
        // Ctor
        MethodSpec.Builder ctorBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC);
        ctorBuilder.addStatement("$T.out.printf($S, $L)", ClassName.get(System.class), "This is tiger: %s\n", "this");
        // Ctor - Containing top level injector.
        // TODO: remove this .
        String containingInjectorName = "containingInjector";
        if (componentTree.get(coreInjectorInfo) != null) {
            ClassName containingInjectorClassName = ClassName.get(topLevelPackageString, getTopLevelInjectorName(componentTree.get(coreInjectorInfo), topLevelInjectorPrefix, topLevelInjectorSuffix));
            injectorBuilder.addField(containingInjectorClassName, containingInjectorName, Modifier.PRIVATE);
            ctorBuilder.addParameter(containingInjectorClassName, containingInjectorName).addStatement("this.$L = $L", containingInjectorName, containingInjectorName);
        }
        // Ctor - ancester top level injectors.
        CoreInjectorInfo tmp = coreInjectorInfo;
        while (componentTree.get(tmp) != null) {
            tmp = componentTree.get(tmp);
            ClassName className = ClassName.get(topLevelPackageString, getTopLevelInjectorName(tmp, topLevelInjectorPrefix, topLevelInjectorSuffix));
            String sourceCodeName = utils.getSourceCodeName(className);
            injectorBuilder.addField(className, sourceCodeName);
            if (tmp.equals(componentTree.get(coreInjectorInfo))) {
                ctorBuilder.addStatement("this.$L = $L", sourceCodeName, containingInjectorName);
            } else {
                ctorBuilder.addStatement("this.$L = $L.$L", sourceCodeName, containingInjectorName, sourceCodeName);
            }
        }
        // Ctor - Component dependencies
        for (TypeElement dep : utils.sortByFullName(coreInjectorToComponentDependencyMap.get(coreInjectorInfo))) {
            if (utils.isEitherComponent(dep)) {
                continue;
            }
            ClassName className = ClassName.get(dep);
            String sourceCodeName = utils.getSourceCodeName(className);
            injectorBuilder.addField(className, sourceCodeName, Modifier.PUBLIC);
            ctorBuilder.addParameter(className, sourceCodeName).addStatement("this.$L = $L", sourceCodeName, sourceCodeName);
        }
        // Ctor - @BindsInstance
        for (BindingKey key : utils.sortBindingKeys(coreInjectorToBindsInstanceMap.get(coreInjectorInfo))) {
            String sourceCodeName = utils.getSourceCodeNameHandlingBox(key, dependencies);
            injectorBuilder.addField(key.getTypeName(), sourceCodeName, Modifier.PUBLIC);
            ctorBuilder.addParameter(key.getTypeName(), sourceCodeName).addStatement("this.$L = $L", sourceCodeName, sourceCodeName);
        }
        // Ctor - Passed modules.
        Set<TypeElement> allPassedModules = new HashSet<>();
        allPassedModules.addAll(nonNullaryCtorModules.get(coreInjectorInfo));
        allPassedModules.addAll(nonNullaryCtorUnscopedModules);
        for (TypeElement passedModule : utils.sortByFullName(allPassedModules)) {
            String moduleName = utils.getSourceCodeName(passedModule);
            ClassName moduleTypeName = (ClassName) TypeName.get(passedModule.asType());
            ctorBuilder.addParameter(moduleTypeName, moduleName).addStatement("this.$N = $N", moduleName, moduleName);
            injectorBuilder.addField(moduleTypeName, moduleName, Modifier.PRIVATE).addMethod(MethodSpec.methodBuilder(utils.getGetMethodName(moduleTypeName)).addModifiers(Modifier.PUBLIC).returns(moduleTypeName).addStatement("return $N", moduleName).build());
        }
        injectorBuilder.addMethod(ctorBuilder.build());
        // Injection methods and non-injection methods.
        Set<String> miscMethodNames = new HashSet<>();
        Set<TypeElement> allMembersInjectors = Sets.newHashSet(coreInjectorToComponentMap.get(coreInjectorInfo));
        for (TypeElement injector : allMembersInjectors) {
            for (Element element : processingEnv.getElementUtils().getAllMembers(injector)) {
                messager.printMessage(Kind.NOTE, "method: " + element);
                if (!element.getKind().equals(ElementKind.METHOD)) {
                    continue;
                }
                ExecutableElement method = (ExecutableElement) element;
                ExecutableType methodType = (ExecutableType) processingEnv.getTypeUtils().asMemberOf((DeclaredType) injector.asType(), method);
                // Injection methods.
                if (utils.isInjectionMethod(element)) {
                    // TODO: add duplicate check for provision method also.
                    if (injectionMethodsDone.add(Pair.of(method.getSimpleName().toString(), TypeName.get(Iterables.getOnlyElement(methodType.getParameterTypes())))) == false) {
                        messager.printMessage(Kind.WARNING, "duplicate injection method: " + method);
                        continue;
                    }
                    TypeMirror typeMirror = Iterables.getOnlyElement(methodType.getParameterTypes());
                    TypeElement cls = (TypeElement) ((DeclaredType) typeMirror).asElement();
                    messager.printMessage(Kind.NOTE, TAG + ".generateTopLevelInjector-injection method : " + methodType);
                    ClassName packagedInjectorClassName = getPackagedInjectorNameOfScope(utils.getPackageString(cls), coreInjectorInfo.getScope());
                    injectorBuilder.addMethod(MethodSpec.methodBuilder(method.getSimpleName().toString()).addModifiers(Modifier.PUBLIC).addParameter(ClassName.get(cls), "arg").addStatement("$L().inject(arg)", utils.getGetMethodName(packagedInjectorClassName)).build());
                } else if (utils.isComponentProvisionMethod(element)) {
                    messager.printMessage(Kind.ERROR, "Injecting components is not supported: " + element);
                } else if (utils.isSubcomponentProvisionMethod(element)) {
                    generateGetSubcomponentMethod((ExecutableElement) element, injectorBuilder);
                } else if (utils.isProvisionMethodInInjector(element)) {
                    if (!miscMethodNames.add(method.getSimpleName().toString())) {
                        continue;
                    }
                    MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder(method.getSimpleName().toString()).addModifiers(Modifier.PUBLIC).returns(TypeName.get(method.getReturnType()));
                    BindingKey providedKey = utils.getKeyProvidedByMethod(method);
                    ClassName packagedInjectorClassName = null;
                    for (ClassName className : keyToPackagedInjectorMap.get(providedKey)) {
                        if (isInjectorOfScope(className, coreInjectorInfo.getScope())) {
                            packagedInjectorClassName = className;
                            break;
                        }
                    }
                    if (packagedInjectorClassName == null) {
                        messager.printMessage(Kind.WARNING, String.format("PackagedInjector or multiBindingInjector not found for key: %s " + "from provisionMethod: %s. Probably it is not used.", providedKey, method));
                        // Create a dumb method
                        String statement = "return ";
                        TypeKind typeKind = method.getReturnType().getKind();
                        if (typeKind.equals(TypeKind.BOOLEAN)) {
                            statement += "false";
                        } else if (typeKind.equals(TypeKind.CHAR)) {
                            statement += "\'0\'";
                        } else if (typeKind.isPrimitive()) {
                            statement += "0";
                        } else {
                            statement += "null";
                        }
                        methodBuilder.addStatement(statement);
                    } else {
                        String statement = "return $L().$L()";
                        methodBuilder.addStatement(statement, utils.getGetMethodName(packagedInjectorClassName), utils.getProvisionMethodName(dependencies, providedKey));
                    }
                    // messager.printMessage(Kind.NOTE, "provision method added: " + methodBuilder.build());
                    injectorBuilder.addMethod(methodBuilder.build());
                // } else if (utils.isEitherComponentProvisionMethod(element)) {
                // // TODO: support get component method.
                // if(utils.isComponentProvisionMethod(element)) {
                // throw new RuntimeException("component provision method is not suported yet.");
                // }
                // generateGetSubcomponentMethod((ExecutableElement) element, injectorBuilder);
                // } else if (utils.isEitherComponentBuilderProvisionMethod(element)) {
                // /**
                // * TODO: handle it in the way consistent with other {@link DependencySourceType} in
                // * {@link #generateProvisionMethodIfNeeded(BindingKey, TypeElement)}
                // */
                // generateExplicitProvisionMethodForEitherComponentBuilder(
                // (ExecutableElement) element, injectorBuilder);
                } else if (isIrrelevantMethodInInjector(element)) {
                // do nothing
                } else {
                    messager.printMessage(Kind.WARNING, String.format("Element %s ignored from injector %s.", element, injector));
                }
            }
        }
        // Methods to get packaged injectors.
        for (Map.Entry<ClassName, TypeSpec.Builder> entry : packagedInjectorBuilders.entrySet()) {
            ClassName injectorClassName = entry.getKey();
            if (!coreInjectorInfo.equals(getComponentFromPackagedInjectorClassName(injectorClassName))) {
                continue;
            }
            String packagedInjectorSourceCodeName = utils.getSourceCodeName(injectorClassName);
            injectorBuilder.addField(injectorClassName, packagedInjectorSourceCodeName, Modifier.PRIVATE);
            MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(utils.getGetMethodName(injectorClassName)).addModifiers(Modifier.PUBLIC).returns(injectorClassName).addStatement("$T result = $N", injectorClassName, packagedInjectorSourceCodeName).beginControlFlow("if (result == null)");
            StringBuilder stringBuilder = new StringBuilder("result = $N = new $T(this");
            if (componentTree.get(coreInjectorInfo) != null) {
                ClassName containingPackageInjectorClassName = getInjectorNameOfScope(injectorClassName, componentTree.get(coreInjectorInfo).getScope());
                stringBuilder.append(", ").append(containingInjectorName).append(".").append(utils.getGetMethodName(containingPackageInjectorClassName)).append("()");
            }
            stringBuilder.append(")");
            methodSpecBuilder.addStatement(stringBuilder.toString(), packagedInjectorSourceCodeName, injectorClassName);
            methodSpecBuilder.endControlFlow().addStatement("return result");
            injectorBuilder.addMethod(methodSpecBuilder.build());
        }
        // Builder and builder().
        generateInjectorBuilder(coreInjectorInfo, injectorBuilder);
        ClassName builderClassName = getTopLevelInjectorBuilderClassName(coreInjectorInfo);
        MethodSpec.Builder methodSpecBuilder = // "Dagger compatible component will have "builder()", we need a different name.
        MethodSpec.methodBuilder("getBuilder").addModifiers(Modifier.PUBLIC, Modifier.STATIC).returns(builderClassName).addStatement("return new $T()", builderClassName);
        injectorBuilder.addMethod(methodSpecBuilder.build());
        // provision methods for (sub)component builders that can be provided by this core injector.
        for (TypeElement b : coreInjectorToBothBuilderMap.get(coreInjectorInfo)) {
            generateImplicitProvisionMethodForEitherComponentBuilderInTopLevelInjector(injectorBuilder, b);
        }
        // Write
        JavaFile javaFile = JavaFile.builder(topLevelPackageString, injectorBuilder.build()).build();
        try {
            javaFile.writeTo(processingEnv.getFiler());
        } catch (IOException e) {
            messager.printMessage(Kind.ERROR, e.toString());
        }
    }
}
Also used : ExecutableType(javax.lang.model.type.ExecutableType) 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) ExecutableElement(javax.lang.model.element.ExecutableElement) Builder(com.squareup.javapoet.TypeSpec.Builder) TypeKind(javax.lang.model.type.TypeKind) TypeMirror(javax.lang.model.type.TypeMirror) Builder(com.squareup.javapoet.TypeSpec.Builder) ClassName(com.squareup.javapoet.ClassName) Pair(com.google.common.base.Pair) HashSet(java.util.HashSet) MethodSpec(com.squareup.javapoet.MethodSpec) TypeElement(javax.lang.model.element.TypeElement) IOException(java.io.IOException) JavaFile(com.squareup.javapoet.JavaFile) Map(java.util.Map) HashMap(java.util.HashMap) TypeSpec(com.squareup.javapoet.TypeSpec) DeclaredType(javax.lang.model.type.DeclaredType)

Aggregations

Pair (com.google.common.base.Pair)1 ClassName (com.squareup.javapoet.ClassName)1 JavaFile (com.squareup.javapoet.JavaFile)1 MethodSpec (com.squareup.javapoet.MethodSpec)1 TypeSpec (com.squareup.javapoet.TypeSpec)1 Builder (com.squareup.javapoet.TypeSpec.Builder)1 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Element (javax.lang.model.element.Element)1 ExecutableElement (javax.lang.model.element.ExecutableElement)1 PackageElement (javax.lang.model.element.PackageElement)1 TypeElement (javax.lang.model.element.TypeElement)1 VariableElement (javax.lang.model.element.VariableElement)1 DeclaredType (javax.lang.model.type.DeclaredType)1 ExecutableType (javax.lang.model.type.ExecutableType)1 TypeKind (javax.lang.model.type.TypeKind)1 TypeMirror (javax.lang.model.type.TypeMirror)1