private void writeProvidesAdapter( JavaWriter writer, ExecutableElement providerMethod, Map<ExecutableElement, String> methodToClassName, Map<String, AtomicInteger> methodNameToNextId) throws IOException { String methodName = providerMethod.getSimpleName().toString(); String moduleType = CodeGen.typeToString(providerMethod.getEnclosingElement().asType()); String className = bindingClassName(providerMethod, methodToClassName, methodNameToNextId); String returnType = CodeGen.typeToString(providerMethod.getReturnType()); List<? extends VariableElement> parameters = providerMethod.getParameters(); boolean dependent = !parameters.isEmpty(); writer.emitEmptyLine(); writer.emitJavadoc(binderTypeDocs(returnType, false, false, dependent)); writer.beginType( className, "class", PUBLIC | FINAL | STATIC, JavaWriter.type(Binding.class, returnType), JavaWriter.type(Provider.class, returnType)); writer.emitField(moduleType, "module", PRIVATE | FINAL); for (Element parameter : parameters) { TypeMirror parameterType = parameter.asType(); writer.emitField( JavaWriter.type(Binding.class, CodeGen.typeToString(parameterType)), parameterName(parameter), PRIVATE); } writer.emitEmptyLine(); writer.beginMethod(null, className, PUBLIC, moduleType, "module"); boolean singleton = providerMethod.getAnnotation(Singleton.class) != null; String key = JavaWriter.stringLiteral(GeneratorKeys.get(providerMethod)); String membersKey = null; writer.emitStatement( "super(%s, %s, %s, %s.class)", key, membersKey, (singleton ? "IS_SINGLETON" : "NOT_SINGLETON"), moduleType); writer.emitStatement("this.module = module"); writer.endMethod(); if (dependent) { writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.ATTACH_METHOD); writer.emitAnnotation(Override.class); writer.emitAnnotation(SuppressWarnings.class, JavaWriter.stringLiteral("unchecked")); writer.beginMethod("void", "attach", PUBLIC, Linker.class.getCanonicalName(), "linker"); for (VariableElement parameter : parameters) { String parameterKey = GeneratorKeys.get(parameter); writer.emitStatement( "%s = (%s) linker.requestBinding(%s, %s.class)", parameterName(parameter), writer.compressType( JavaWriter.type(Binding.class, CodeGen.typeToString(parameter.asType()))), JavaWriter.stringLiteral(parameterKey), writer.compressType(moduleType)); } writer.endMethod(); writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.GET_DEPENDENCIES_METHOD); writer.emitAnnotation(Override.class); String setOfBindings = JavaWriter.type(Set.class, "Binding<?>"); writer.beginMethod( "void", "getDependencies", PUBLIC, setOfBindings, "getBindings", setOfBindings, "injectMembersBindings"); for (Element parameter : parameters) { writer.emitStatement("getBindings.add(%s)", parameter.getSimpleName().toString()); } writer.endMethod(); } writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.GET_METHOD, returnType); writer.emitAnnotation(Override.class); writer.beginMethod(returnType, "get", PUBLIC); StringBuilder args = new StringBuilder(); boolean first = true; for (Element parameter : parameters) { if (!first) args.append(", "); else first = false; args.append(String.format("%s.get()", parameter.getSimpleName().toString())); } writer.emitStatement("return module.%s(%s)", methodName, args.toString()); writer.endMethod(); writer.endType(); }
/** * Write a companion class for {@code type} that implements {@link ModuleAdapter} to expose its * provider methods. */ private void writeModuleAdapter( TypeElement type, Map<String, Object> module, List<ExecutableElement> providerMethods) throws IOException { if (module == null) { error(type + " has @Provides methods but no @Module annotation", type); return; } Object[] staticInjections = (Object[]) module.get("staticInjections"); Object[] entryPoints = (Object[]) module.get("entryPoints"); Object[] includes = (Object[]) module.get("includes"); boolean overrides = (Boolean) module.get("overrides"); boolean complete = (Boolean) module.get("complete"); String adapterName = CodeGen.adapterName(type, MODULE_ADAPTER_SUFFIX); JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(adapterName, type); JavaWriter writer = new JavaWriter(sourceFile.openWriter()); boolean multibindings = checkForMultibindings(providerMethods); boolean providerMethodDependencies = checkForDependencies(providerMethods); writer.emitEndOfLineComment(ProcessorJavadocs.GENERATED_BY_DAGGER); writer.emitPackage(CodeGen.getPackage(type).getQualifiedName().toString()); writer.emitEmptyLine(); writer.emitImports( getImports(multibindings, !providerMethods.isEmpty(), providerMethodDependencies)); String typeName = type.getQualifiedName().toString(); writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.MODULE_TYPE); writer.beginType( adapterName, "class", PUBLIC | FINAL, JavaWriter.type(ModuleAdapter.class, typeName)); StringBuilder entryPointsField = new StringBuilder().append("{ "); for (Object entryPoint : entryPoints) { TypeMirror typeMirror = (TypeMirror) entryPoint; String key = GeneratorKeys.rawMembersKey(typeMirror); entryPointsField.append(JavaWriter.stringLiteral(key)).append(", "); } entryPointsField.append("}"); writer.emitField( "String[]", "ENTRY_POINTS", PRIVATE | STATIC | FINAL, entryPointsField.toString()); StringBuilder staticInjectionsField = new StringBuilder().append("{ "); for (Object staticInjection : staticInjections) { TypeMirror typeMirror = (TypeMirror) staticInjection; staticInjectionsField.append(CodeGen.typeToString(typeMirror)).append(".class, "); } staticInjectionsField.append("}"); writer.emitField( "Class<?>[]", "STATIC_INJECTIONS", PRIVATE | STATIC | FINAL, staticInjectionsField.toString()); StringBuilder includesField = new StringBuilder().append("{ "); for (Object include : includes) { if (!(include instanceof TypeMirror)) { // TODO(tbroyer): pass annotation information processingEnv .getMessager() .printMessage( Diagnostic.Kind.WARNING, "Unexpected value: " + include + " in includes of " + type, type); continue; } TypeMirror typeMirror = (TypeMirror) include; includesField.append(CodeGen.typeToString(typeMirror)).append(".class, "); } includesField.append("}"); writer.emitField("Class<?>[]", "INCLUDES", PRIVATE | STATIC | FINAL, includesField.toString()); writer.emitEmptyLine(); writer.beginMethod(null, adapterName, PUBLIC); writer.emitStatement( "super(ENTRY_POINTS, STATIC_INJECTIONS, %s /*overrides*/, " + "INCLUDES, %s /*complete*/)", overrides, complete); writer.endMethod(); ExecutableElement noArgsConstructor = CodeGen.getNoArgsConstructor(type); if (noArgsConstructor != null && CodeGen.isCallableConstructor(noArgsConstructor)) { writer.emitEmptyLine(); writer.emitAnnotation(Override.class); writer.beginMethod(typeName, "newModule", PROTECTED); writer.emitStatement("return new %s()", typeName); writer.endMethod(); } // caches Map<ExecutableElement, String> methodToClassName = new LinkedHashMap<ExecutableElement, String>(); Map<String, AtomicInteger> methodNameToNextId = new LinkedHashMap<String, AtomicInteger>(); if (!providerMethods.isEmpty()) { writer.emitEmptyLine(); writer.emitJavadoc(ProcessorJavadocs.GET_DEPENDENCIES_METHOD); writer.emitAnnotation(Override.class); writer.beginMethod("void", "getBindings", PUBLIC, BINDINGS_MAP, "map"); for (ExecutableElement providerMethod : providerMethods) { Provides provides = providerMethod.getAnnotation(Provides.class); switch (provides.type()) { case UNIQUE: { String key = GeneratorKeys.get(providerMethod); writer.emitStatement( "map.put(%s, new %s(module))", JavaWriter.stringLiteral(key), bindingClassName(providerMethod, methodToClassName, methodNameToNextId)); break; } case SET: { String key = GeneratorKeys.getElementKey(providerMethod); writer.emitStatement( "SetBinding.add(map, %s, new %s(module))", JavaWriter.stringLiteral(key), bindingClassName(providerMethod, methodToClassName, methodNameToNextId)); break; } default: throw new AssertionError("Unknown @Provides type " + provides.type()); } } writer.endMethod(); } for (ExecutableElement providerMethod : providerMethods) { writeProvidesAdapter(writer, providerMethod, methodToClassName, methodNameToNextId); } writer.endType(); writer.close(); }