use of com.squareup.javapoet.TypeSpec.Builder in project tiger by google.
the class NewInjectorGenerator method generateInjectorBuilder.
private void generateInjectorBuilder(ComponentInfo componentInfo, TypeSpec.Builder injectorBuilder) {
TypeSpec.Builder builderBuilder = TypeSpec.classBuilder("Builder").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
ClassName injectorClassName = ClassName.get(topLevelPackageString, getTopLevelInjectorName(componentInfo));
boolean hasParent = componentTree.get(componentInfo) != null;
ClassName parentClassName = null;
// set parent inject methods.
if (hasParent) {
parentClassName = ClassName.get(topLevelPackageString, getTopLevelInjectorName(componentTree.get(componentInfo)));
Utils.addSetMethod(injectorClassName, builderBuilder, parentClassName);
}
/**
* Set module methods. Theoretically, is a passed module is needed by a injector should be
* decided by whether it is needed. Here is just a simpler way. All scoped modules go to
* injector of the same scope. All unscoped modules go to every injector. It is not possible to
* have modules of different scope in a injector. This way the modules created is a superset of
* what are required. But that's fine because null can be passed in for modules not needed. This
* is even unnoticeable when using builder to create injector. The null module is just never
* referenced. Otherwise it is a bug, sadly it is not caught until runtime. This makes it easier
* to create wrapper component defined dagger around core injectors. Anyway, passed module is
* not a good idea and could/should be removed.
*/
List<TypeElement> allNonNullaryCtorModules = new ArrayList<>();
allNonNullaryCtorModules.addAll(nonNullaryCtorModules.get(componentInfo));
allNonNullaryCtorModules.addAll(nonNullaryCtorUnscopedModules);
for (TypeElement m : allNonNullaryCtorModules) {
Utils.addSetMethod(injectorClassName, builderBuilder, (ClassName) ClassName.get(m.asType()));
}
// build() method.
MethodSpec.Builder buildMethodBuilder = MethodSpec.methodBuilder("build").addModifiers(Modifier.PUBLIC).returns(injectorClassName);
StringBuilder returnCodeBuilder = new StringBuilder("return new $T(");
if (hasParent) {
String parentInjectorFieldName = Utils.getSourceCodeName(parentClassName);
returnCodeBuilder.append(parentInjectorFieldName);
if (!allNonNullaryCtorModules.isEmpty()) {
returnCodeBuilder.append(", ");
}
}
if (!allNonNullaryCtorModules.isEmpty()) {
for (TypeElement module : Utils.sortByFullName(allNonNullaryCtorModules)) {
String moduleFiledName = Utils.getSourceCodeName(TypeName.get(module.asType()));
returnCodeBuilder.append(moduleFiledName).append(", ");
}
int size = returnCodeBuilder.length();
returnCodeBuilder.delete(size - 2, size);
}
returnCodeBuilder.append(");");
buildMethodBuilder.addCode(returnCodeBuilder.toString(), injectorClassName);
builderBuilder.addMethod(buildMethodBuilder.build());
injectorBuilder.addType(builderBuilder.build());
}
use of com.squareup.javapoet.TypeSpec.Builder in project tiger by google.
the class GeneralInjectorGenerator method createInjectorBuilder.
protected final Builder createInjectorBuilder() {
String injectorSimpleName = getInjectorSimpleName();
logger.n("generated component " + injectorSimpleName);
Builder result = TypeSpec.classBuilder(injectorSimpleName).addModifiers(Modifier.PUBLIC).addAnnotation(AnnotationSpec.builder(Generated.class).addMember("value", "$S", GENERATOR_NAME).build());
for (TypeName typeName : getSuperInterfaces()) {
result.addSuperinterface(typeName);
}
return result;
}
use of com.squareup.javapoet.TypeSpec.Builder 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());
}
}
}
use of com.squareup.javapoet.TypeSpec.Builder in project tiger by google.
the class CoreInjectorGenerator method generatePackagedInjectors.
private void generatePackagedInjectors() {
for (CoreInjectorInfo coreInjectorInfo : orderedCoreinjectors) {
Set<ClassName> injected = new HashSet<>();
Set<TypeElement> components = Sets.newHashSet(coreInjectorToComponentMap.get(coreInjectorInfo));
for (TypeElement c : components) {
for (Element e : elements.getAllMembers(c)) {
messager.printMessage(Kind.NOTE, "generatePackagedInjectors: element: " + e);
if (!utils.isMethod(e)) {
continue;
}
ExecutableElement method = (ExecutableElement) e;
ExecutableType methodType = ((ExecutableType) types.asMemberOf(((DeclaredType) c.asType()), e));
if (utils.isInjectionMethod(method)) {
TypeElement injectedTypeElement = (TypeElement) ((DeclaredType) Iterables.getOnlyElement(methodType.getParameterTypes())).asElement();
if (!injected.add(ClassName.get(injectedTypeElement))) {
continue;
}
messager.printMessage(Kind.NOTE, TAG + ".generatePackagedInjectors: injection method for: " + injectedTypeElement);
generateInjectionMethod(injectedTypeElement, coreInjectorInfo.getScope());
} else if (utils.isProvisionMethodInInjector(method)) {
generateProvisionMethodIfNeeded(utils.getKeyProvidedByMethod((ExecutableElement) method), c);
} else {
// TODO: ignore known elements like builders.
messager.printMessage(Kind.WARNING, String.format("Unknown element %s from injector %s.", method, c));
}
}
}
}
messager.printMessage(Kind.NOTE, TAG + ".generatePackagedInjectors. packagedInjectorBuilders: " + packagedInjectorBuilders);
// Inherited provision methods.
for (CoreInjectorInfo component : orderedCoreinjectors) {
if (componentTree.get(component) == null) {
continue;
}
for (Map.Entry<ClassName, TypeSpec.Builder> entry : packagedInjectorBuilders.entrySet()) {
ClassName packagedInjectorClassName = entry.getKey();
if (!component.equals(getComponentFromPackagedInjectorClassName(packagedInjectorClassName))) {
continue;
}
generateInheritedProvisionMethods(packagedInjectorClassName);
}
}
// Inherited injection methods.
for (CoreInjectorInfo component : orderedCoreinjectors) {
if (componentTree.get(component) == null) {
continue;
}
for (Map.Entry<ClassName, TypeSpec.Builder> entry : packagedInjectorBuilders.entrySet()) {
ClassName packagedInjectorClassName = entry.getKey();
if (!component.equals(getComponentFromPackagedInjectorClassName(packagedInjectorClassName))) {
continue;
}
generateInheritedInjectionMethods(packagedInjectorClassName);
}
}
for (Map.Entry<ClassName, TypeSpec.Builder> entry : packagedInjectorBuilders.entrySet()) {
String packageString = entry.getKey().packageName();
TypeSpec.Builder builder = entry.getValue();
JavaFile javaFile = JavaFile.builder(packageString, builder.build()).build();
// messager.printMessage(Kind.NOTE, String.format("java file: %s", javaFile));
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
Throwables.propagate(e);
}
}
}
use of com.squareup.javapoet.TypeSpec.Builder in project tiger by google.
the class CoreInjectorGenerator method generateInjectorBuilder.
private void generateInjectorBuilder(CoreInjectorInfo coreInjectorInfo, TypeSpec.Builder injectorBuilder) {
TypeSpec.Builder builderBuilder = TypeSpec.classBuilder("Builder").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
ClassName injectorClassName = ClassName.get(topLevelPackageString, getTopLevelInjectorName(coreInjectorInfo, topLevelInjectorPrefix, topLevelInjectorSuffix));
boolean hasParent = componentTree.get(coreInjectorInfo) != null;
ClassName parentClassName = null;
// set parent inject methods.
if (hasParent) {
parentClassName = ClassName.get(topLevelPackageString, getTopLevelInjectorName(componentTree.get(coreInjectorInfo), topLevelInjectorPrefix, topLevelInjectorSuffix));
utils.addSetMethod(types, elements, injectorClassName, builderBuilder, parentClassName, getParentComponentSetterName(componentTree.get(coreInjectorInfo)));
}
for (TypeElement dep : coreInjectorToComponentDependencyMap.get(coreInjectorInfo)) {
utils.addSetMethod(types, elements, injectorClassName, builderBuilder, (ClassName) ClassName.get(dep.asType()));
}
for (BindingKey key : coreInjectorToBindsInstanceMap.get(coreInjectorInfo)) {
utils.addSetMethod(types, elements, injectorClassName, builderBuilder, key.getTypeName(), utils.getSourceCodeNameHandlingBox(key, dependencies));
}
/**
* Set module methods. Theoretically, is a passed module is needed by a injector should be
* decided by whether it is needed. Here is just a simpler way. All scoped modules go to
* injector of the same scope. All unscoped modules go to every injector. It is not possible to
* have modules of different scope in a injector. This way the modules created is a superset of
* what are required. But that's fine because null can be passed in for modules not needed. This
* is even unnoticeable when using builder to create injector. The null module is just never
* referenced. Otherwise it is a bug, sadly it is not caught until runtime. This makes it easier
* to create wrapper component defined dagger around core injectors. Anyway, passed module is
* not a good idea and could/should be removed.
*/
List<TypeElement> allNonNullaryCtorModules = new ArrayList<>();
allNonNullaryCtorModules.addAll(nonNullaryCtorModules.get(coreInjectorInfo));
allNonNullaryCtorModules.addAll(nonNullaryCtorUnscopedModules);
for (TypeElement m : allNonNullaryCtorModules) {
utils.addSetMethod(types, elements, injectorClassName, builderBuilder, (ClassName) ClassName.get(m.asType()));
}
// build() method.
MethodSpec.Builder buildMethodBuilder = MethodSpec.methodBuilder("build").addModifiers(Modifier.PUBLIC).returns(injectorClassName);
StringBuilder returnCodeBuilder = new StringBuilder("return new $T(");
boolean needLeadingComma = false;
if (hasParent) {
needLeadingComma = true;
String parentInjectorFieldName = utils.getSourceCodeName(parentClassName);
returnCodeBuilder.append(parentInjectorFieldName);
}
Set<TypeElement> deps = coreInjectorToComponentDependencyMap.get(coreInjectorInfo);
if (!deps.isEmpty()) {
if (needLeadingComma) {
returnCodeBuilder.append(", ");
}
needLeadingComma = true;
for (TypeElement dep : utils.sortByFullName(deps)) {
String parameterName = utils.getSourceCodeName(TypeName.get(dep.asType()));
returnCodeBuilder.append(parameterName).append(", ");
}
int size = returnCodeBuilder.length();
returnCodeBuilder.delete(size - 2, size);
}
Set<BindingKey> keys = coreInjectorToBindsInstanceMap.get(coreInjectorInfo);
if (!keys.isEmpty()) {
if (needLeadingComma) {
returnCodeBuilder.append(", ");
}
needLeadingComma = true;
for (BindingKey key : utils.sortBindingKeys(keys)) {
String parameterName = utils.getSourceCodeNameHandlingBox(key, dependencies);
returnCodeBuilder.append(parameterName).append(", ");
}
int size = returnCodeBuilder.length();
returnCodeBuilder.delete(size - 2, size);
}
if (!allNonNullaryCtorModules.isEmpty()) {
if (needLeadingComma) {
returnCodeBuilder.append(", ");
}
needLeadingComma = true;
for (TypeElement module : utils.sortByFullName(allNonNullaryCtorModules)) {
String parameterName = utils.getSourceCodeName(TypeName.get(module.asType()));
returnCodeBuilder.append(parameterName).append(", ");
}
int size = returnCodeBuilder.length();
returnCodeBuilder.delete(size - 2, size);
}
returnCodeBuilder.append(");");
buildMethodBuilder.addCode(returnCodeBuilder.toString(), injectorClassName);
builderBuilder.addMethod(buildMethodBuilder.build());
injectorBuilder.addType(builderBuilder.build());
}
Aggregations