Skip to content
This repository has been archived by the owner on Aug 26, 2021. It is now read-only.

Commit

Permalink
Revert "Remove static injection."
Browse files Browse the repository at this point in the history
This reverts commit 3e4632b.
  • Loading branch information
JakeWharton committed May 3, 2016
1 parent c8fdb3d commit 473529a
Show file tree
Hide file tree
Showing 15 changed files with 379 additions and 31 deletions.
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2013 Square, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.squareup.dagger.tests</groupId>
<artifactId>static-injected-binding-doesnt-fail-providers</artifactId>
<version>@dagger.version@</version>
<packaging>jar</packaging>
<name>Dagger Integration Test Basic</name>
<dependencies>
<dependency>
<groupId>@dagger.groupId@</groupId>
<artifactId>dagger</artifactId>
<version>@dagger.version@</version>
</dependency>
<dependency>
<groupId>@dagger.groupId@</groupId>
<artifactId>dagger-compiler</artifactId>
<version>@dagger.version@</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2013 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package test;

import dagger.Module;

import dagger.ObjectGraph;
import dagger.Provides;
import javax.inject.Inject;

import java.lang.Override;

public class Test {

public static class InjectsOneField {
@Inject static String staticallyInjectedString;
}

@Module(staticInjections = { InjectsOneField.class })
public static class TestModule {
@Provides String string() {
return "string";
}
}
}
Expand Up @@ -164,6 +164,8 @@ private Map<String, Binding<?>> processCompleteModule(TypeElement rootModule,
boolean ignoreCompletenessErrors) {
Map<String, TypeElement> allModules = new LinkedHashMap<String, TypeElement>();
collectIncludesRecursively(rootModule, allModules, new LinkedList<String>());
ArrayList<GraphAnalysisStaticInjection> staticInjections =
new ArrayList<GraphAnalysisStaticInjection>();

Linker.ErrorHandler errorHandler = ignoreCompletenessErrors ? Linker.ErrorHandler.NULL
: new GraphAnalysisErrorHandler(processingEnv, rootModule.getQualifiedName().toString());
Expand Down Expand Up @@ -201,6 +203,13 @@ private Map<String, Binding<?>> processCompleteModule(TypeElement rootModule,
getClass().getClassLoader(), false, true);
}

// Gather the static injections.
for (Object staticInjection : (Object[]) annotation.get("staticInjections")) {
TypeMirror staticInjectionTypeMirror = (TypeMirror) staticInjection;
Element element = processingEnv.getTypeUtils().asElement(staticInjectionTypeMirror);
staticInjections.add(new GraphAnalysisStaticInjection(element));
}

// Gather the enclosed @Provides methods.
for (Element enclosed : module.getEnclosedElements()) {
Provides provides = enclosed.getAnnotation(Provides.class);
Expand Down Expand Up @@ -255,6 +264,9 @@ private Map<String, Binding<?>> processCompleteModule(TypeElement rootModule,

linker.installBindings(baseBindings);
linker.installBindings(overrideBindings);
for (GraphAnalysisStaticInjection staticInjection : staticInjections) {
staticInjection.attach(linker);
}

// Link the bindings. This will traverse the dependency graph, and report
// errors if any dependencies are missing.
Expand Down
Expand Up @@ -22,8 +22,10 @@
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import dagger.ObjectGraph;
import dagger.internal.Binding;
import dagger.internal.Linker;
import dagger.internal.StaticInjection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -58,6 +60,7 @@
import static dagger.internal.codegen.Util.isCallableConstructor;
import static dagger.internal.codegen.Util.rawTypeToString;
import static dagger.internal.loaders.GeneratedAdapters.INJECT_ADAPTER_SUFFIX;
import static dagger.internal.loaders.GeneratedAdapters.STATIC_INJECTION_SUFFIX;
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
Expand All @@ -84,7 +87,8 @@ public final class InjectAdapterProcessor extends AbstractProcessor {
boolean missingDependentClasses =
!allTypesExist(injectedClass.fields)
|| (injectedClass.constructor != null && !allTypesExist(injectedClass.constructor
.getParameters()));
.getParameters()))
|| !allTypesExist(injectedClass.staticFields);
if (!missingDependentClasses) {
try {
generateInjectionsForClass(injectedClass);
Expand All @@ -105,6 +109,9 @@ private void generateInjectionsForClass(InjectedClass injectedClass) throws IOEx
if (injectedClass.constructor != null || !injectedClass.fields.isEmpty()) {
generateInjectAdapter(injectedClass.type, injectedClass.constructor, injectedClass.fields);
}
if (!injectedClass.staticFields.isEmpty()) {
generateStaticInjection(injectedClass.type, injectedClass.staticFields);
}
}

/**
Expand Down Expand Up @@ -182,6 +189,7 @@ private boolean validateInjectable(Element injectable) {
private InjectedClass createInjectedClass(String injectedClassName) {
TypeElement type = processingEnv.getElementUtils().getTypeElement(injectedClassName);
boolean isAbstract = type.getModifiers().contains(ABSTRACT);
List<Element> staticFields = new ArrayList<Element>();
ExecutableElement constructor = null;
List<Element> fields = new ArrayList<Element>();
for (Element member : type.getEnclosedElements()) {
Expand All @@ -192,7 +200,7 @@ private InjectedClass createInjectedClass(String injectedClassName) {
switch (member.getKind()) {
case FIELD:
if (member.getModifiers().contains(STATIC)) {
error("@Inject not supported on static field " + type.getQualifiedName(), member);
staticFields.add(member);
} else {
fields.add(member);
}
Expand Down Expand Up @@ -222,7 +230,7 @@ private InjectedClass createInjectedClass(String injectedClassName) {
}
}

return new InjectedClass(type, constructor, fields);
return new InjectedClass(type, staticFields, constructor, fields);
}

/**
Expand Down Expand Up @@ -287,6 +295,31 @@ private void generateInjectAdapter(TypeElement type, ExecutableElement construct
javaFile.writeTo(processingEnv.getFiler());
}

/**
* Write a companion class for {@code type} that extends {@link StaticInjection}.
*/
private void generateStaticInjection(TypeElement type, List<Element> fields) throws IOException {
ClassName typeName = ClassName.get(type);
ClassName adapterClassName = adapterName(ClassName.get(type), STATIC_INJECTION_SUFFIX);

TypeSpec.Builder result = TypeSpec.classBuilder(adapterClassName.simpleName())
.addOriginatingElement(type)
.addJavadoc(AdapterJavadocs.STATIC_INJECTION_TYPE, type)
.addModifiers(PUBLIC, FINAL)
.superclass(StaticInjection.class);
for (Element field : fields) {
result.addField(memberBindingField(false, field));
}
result.addMethod(attachMethod(null, fields, false, typeName, null, true));
result.addMethod(staticInjectMethod(fields, typeName));

String packageName = getPackage(type).getQualifiedName().toString();
JavaFile javaFile = JavaFile.builder(packageName, result.build())
.addFileComment(AdapterJavadocs.GENERATED_BY_DAGGER)
.build();
javaFile.writeTo(processingEnv.getFiler());
}

private FieldSpec memberBindingField(boolean disambiguateFields, Element field) {
return FieldSpec.builder(bindingOf(field.asType()), fieldName(disambiguateFields, field),
PRIVATE).build();
Expand Down Expand Up @@ -420,6 +453,20 @@ private MethodSpec membersInjectMethod(List<Element> fields, boolean disambiguat
return result.build();
}

private MethodSpec staticInjectMethod(List<Element> fields, ClassName typeName) {
MethodSpec.Builder result = MethodSpec.methodBuilder("inject")
.addJavadoc(AdapterJavadocs.STATIC_INJECT_METHOD, ObjectGraph.class)
.addAnnotation(Override.class)
.addModifiers(PUBLIC);
for (Element field : fields) {
result.addStatement("$T.$N = $N.get()",
typeName,
field.getSimpleName().toString(),
fieldName(false, field));
}
return result.build();
}

private String fieldName(boolean disambiguateFields, Element field) {
return (disambiguateFields ? "field_" : "") + field.getSimpleName().toString();
}
Expand All @@ -434,11 +481,14 @@ private void error(String msg, Element element) {

static class InjectedClass {
final TypeElement type;
final List<Element> staticFields;
final ExecutableElement constructor;
final List<Element> fields;

InjectedClass(TypeElement type, ExecutableElement constructor, List<Element> fields) {
InjectedClass(TypeElement type, List<Element> staticFields, ExecutableElement constructor,
List<Element> fields) {
this.type = type;
this.staticFields = staticFields;
this.constructor = constructor;
this.fields = fields;
}
Expand Down
Expand Up @@ -232,6 +232,7 @@ private Set<? extends Element> findProvidesMethods(RoundEnvironment env) {
*/
private JavaFile generateModuleAdapter(TypeElement type,
Map<String, Object> module, List<ExecutableElement> providerMethods) {
Object[] staticInjections = (Object[]) module.get("staticInjections");
Object[] injects = (Object[]) module.get("injects");
Object[] includes = (Object[]) module.get("includes");
boolean overrides = (Boolean) module.get("overrides");
Expand Down Expand Up @@ -260,13 +261,17 @@ private JavaFile generateModuleAdapter(TypeElement type,
.addModifiers(PRIVATE, STATIC, FINAL)
.initializer("$L", injectsInitializer(injects))
.build());
adapterBuilder.addField(FieldSpec.builder(ARRAY_OF_CLASS, "STATIC_INJECTIONS")
.addModifiers(PRIVATE, STATIC, FINAL)
.initializer("$L", staticInjectionsInitializer(staticInjections))
.build());
adapterBuilder.addField(FieldSpec.builder(ARRAY_OF_CLASS, "INCLUDES")
.addModifiers(PRIVATE, STATIC, FINAL)
.initializer("$L", includesInitializer(type, includes))
.build());
adapterBuilder.addMethod(MethodSpec.constructorBuilder()
.addModifiers(PUBLIC)
.addStatement("super($T.class, INJECTS, $L /*overrides*/, "
.addStatement("super($T.class, INJECTS, STATIC_INJECTIONS, $L /*overrides*/, "
+ "INCLUDES, $L /*complete*/, $L /*library*/)",
type.asType(), overrides, complete, library)
.build());
Expand Down Expand Up @@ -360,6 +365,16 @@ private CodeBlock injectsInitializer(Object[] injects) {
return result.build();
}

private CodeBlock staticInjectionsInitializer(Object[] staticInjections) {
CodeBlock.Builder result = CodeBlock.builder()
.add("{ ");
for (Object staticInjection : staticInjections) {
result.add("$T.class, ", staticInjection);
}
result.add("}");
return result.build();
}

private CodeBlock includesInitializer(TypeElement type, Object[] includes) {
CodeBlock.Builder result = CodeBlock.builder();
result.add("{ ");
Expand Down
Expand Up @@ -53,9 +53,10 @@ public final class InjectAdapterGenerationTest {
+ " extends ModuleAdapter<Basic.AModule> {\n"
+ " private static final String[] INJECTS = {\n"
+ " \"members/Basic$A\", \"members/Basic$Foo$Bar\", \"members/Basic$Foo$Bar$Baz\"};\n"
+ " private static final Class<?>[] STATIC_INJECTIONS = {};\n"
+ " private static final Class<?>[] INCLUDES = {};\n"
+ " public Basic$AModule$$ModuleAdapter() {\n"
+ " super(Basic.AModule.class, INJECTS, false, INCLUDES,\n"
+ " super(Basic.AModule.class, INJECTS, STATIC_INJECTIONS, false, INCLUDES,\n"
+ " true, false);\n"
+ " }\n"
+ " @Override public Basic.AModule newModule() {\n"
Expand Down Expand Up @@ -123,24 +124,4 @@ public final class InjectAdapterGenerationTest {
expectedInjectAdapterFooBar, expectedInjectAdapterFooBarBaz);

}

@Test public void injectStaticFails() {
JavaFileObject sourceFile = JavaFileObjects.forSourceString("Basic", ""
+ "import dagger.Module;\n"
+ "import javax.inject.Inject;\n"
+ "class Basic {\n"
+ " static class A { @Inject A() { } }\n"
+ " static class B { @Inject static A a; }\n"
+ " @Module(injects = B.class)\n"
+ " static class AModule { }\n"
+ "}\n"
);

assertAbout(javaSource())
.that(sourceFile)
.processedWith(daggerProcessors())
.failsToCompile()
.withErrorContaining("@Inject not supported on static field Basic.B")
.in(sourceFile).onLine(5);
}
}
Expand Up @@ -69,9 +69,10 @@ public final class ModuleAdapterGenerationTest {
+ " extends ModuleAdapter<Field.AModule> {\n"
+ " private static final String[] INJECTS = \n"
+ " {\"members/Field$A\", \"members/java.lang.String\"};\n"
+ " private static final Class<?>[] STATIC_INJECTIONS = {};\n"
+ " private static final Class<?>[] INCLUDES = {};\n"
+ " public Field$AModule$$ModuleAdapter() {\n"
+ " super(Field.AModule.class, INJECTS, false, INCLUDES, true, false);\n"
+ " super(Field.AModule.class, INJECTS, STATIC_INJECTIONS, false, INCLUDES, true, false);\n"
+ " }\n"
+ " @Override public Field.AModule newModule() {\n"
+ " return new Field.AModule();\n"
Expand Down Expand Up @@ -158,9 +159,10 @@ public final class ModuleAdapterGenerationTest {
+ "public final class Field$AModule$$ModuleAdapter extends ModuleAdapter<Field.AModule> {\n"
+ " private static final String[] INJECTS = \n"
+ " {\"members/Field$A\", \"members/java.lang.String\", \"members/Field$B\"};\n"
+ " private static final Class<?>[] STATIC_INJECTIONS = {};\n"
+ " private static final Class<?>[] INCLUDES = {};\n"
+ " public Field$AModule$$ModuleAdapter() {\n"
+ " super(Field.AModule.class, INJECTS, false, INCLUDES, true, false);\n"
+ " super(Field.AModule.class, INJECTS, STATIC_INJECTIONS, false, INCLUDES, true, false);\n"
+ " }\n"
+ " @Override public Field.AModule newModule() {\n"
+ " return new Field.AModule();\n"
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/dagger/Module.java
Expand Up @@ -51,6 +51,7 @@
* </ul>
*/
Class<?>[] injects() default { };
Class<?>[] staticInjections() default { };

/**
* True if {@code @Provides} methods from this module are permitted to
Expand Down

0 comments on commit 473529a

Please sign in to comment.