Skip to content
This repository was archived by the owner on Aug 20, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,15 @@ subprojects {
check("JavaxInjectOnAbstractMethod", CheckSeverity.OFF)
option("NullAway:AnnotatedPackages", "dagger.reflect")
}
options.setCompilerArgs(options.getCompilerArgs() + [
// strict compilation, treat all warnings as errors, including errorprone
'-Werror',
// enable all warnings
'-Xlint:all',
// hide warning: No processor claimed any of these annotations: dagger.*,org.junit.Test
'-Xlint:-processing',
// hide warning: MethodParameters attribute introduced in version 52.0 class files is ignored in version 51.0 class files
'-Xlint:-classfile'
])
}
}
3 changes: 2 additions & 1 deletion codegen/src/main/java/dagger/internal/DaggerCodegen.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static <C> C create(Class<C> componentClass) {
return invokeStatic(findImplementationClass(componentClass), "create", componentClass);
}

public static <C, B> B builder(Class<B> builderClass) {
public static <B> B builder(Class<B> builderClass) {
Class<?> componentClass = builderClass.getEnclosingClass();
if (componentClass == null) {
throw new IllegalArgumentException(builderClass.getCanonicalName()
Expand All @@ -32,6 +32,7 @@ public static <C, B> B builder(Class<B> builderClass) {
return invokeStatic(findImplementationClass(componentClass), "builder", builderClass);
}

@SuppressWarnings("unchecked")
private static <C> Class<? extends C> findImplementationClass(Class<C> componentClass) {
String implementationName =
componentClass.getPackage().getName() + ".Dagger" + componentClass.getSimpleName();
Expand Down
21 changes: 21 additions & 0 deletions integration-tests/src/main/java/com/example/BindsProviderNull.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example;

import dagger.Binds;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import org.jetbrains.annotations.Nullable;

@Component(modules = BindsProviderNull.Module1.class)
interface BindsProviderNull {

@Nullable CharSequence string();

@Module
abstract class Module1 {
@Provides static @Nullable String string() {
return null;
}
@Binds abstract CharSequence charSequence(@Nullable String foo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example;

import dagger.Component;
import dagger.Module;
import dagger.Provides;
import org.jetbrains.annotations.Nullable;

@Component(modules = ComponentProviderNull.Module1.class)
interface ComponentProviderNull {

@Nullable String string();

@Module
abstract class Module1 {
@Provides static @Nullable String string() {
return null;
}
}
}
22 changes: 16 additions & 6 deletions integration-tests/src/test/java/com/example/IntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public static Object[] parameters() {
assertThat(component.string()).isEqualTo("foo");
}

@Test public void componentProviderNull() {
ComponentProviderNull component = backend.create(ComponentProviderNull.class);
assertThat(component.string()).isNull();
}

@Test public void componentProviderQualified() {
ComponentProviderQualified component = backend.create(ComponentProviderQualified.class);
assertThat(component.string()).isEqualTo("foo");
Expand All @@ -40,7 +45,12 @@ public static Object[] parameters() {

@Test public void bindsProvider() {
BindsProvider component = backend.create(BindsProvider.class);
assertThat(component.string()).isEqualTo("foo");
assertThat((String) component.string()).isEqualTo("foo");
}

@Test public void bindsProviderNull() {
BindsProviderNull component = backend.create(BindsProviderNull.class);
assertThat(component.string()).isNull();
}

@Test public void bindIntoSet() {
Expand Down Expand Up @@ -347,18 +357,18 @@ public static Object[] parameters() {
@Test public void moduleClassAndInterfaceHierarchy() {
ModuleClassAndInterfaceHierarchy component =
backend.create(ModuleClassAndInterfaceHierarchy.class);
assertThat(component.string()).isEqualTo("foo");
assertThat((String) component.string()).isEqualTo("foo");
}

@Test public void moduleClassAndInterfaceDuplicatesHierarchy() {
ModuleClassAndInterfaceDuplicatesHierarchy component =
backend.create(ModuleClassAndInterfaceDuplicatesHierarchy.class);
assertThat(component.string()).isEqualTo("foo");
assertThat((String) component.string()).isEqualTo("foo");
}

@Test public void moduleClassHierarchy() {
ModuleClassHierarchy component = backend.create(ModuleClassHierarchy.class);
assertThat(component.string()).isEqualTo("foo");
assertThat((String) component.string()).isEqualTo("foo");
}

@Test public void moduleClassHierarchyStatics() {
Expand All @@ -368,12 +378,12 @@ public static Object[] parameters() {

@Test public void moduleInterface() {
ModuleInterface component = backend.create(ModuleInterface.class);
assertThat(component.string()).isEqualTo("foo");
assertThat((String) component.string()).isEqualTo("foo");
}

@Test public void moduleInterfaceHierarchy() {
ModuleInterface component = backend.create(ModuleInterface.class);
assertThat(component.string()).isEqualTo("foo");
assertThat((String) component.string()).isEqualTo("foo");
}

private void ignoreReflectionBackend() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
return false;
}

private static @Nullable TypeElement findBuilder(TypeElement component) {
private static @Nullable TypeElement findBuilder(Element component) {
for (Element enclosed : component.getEnclosedElements()) {
if (enclosed.getAnnotation(Component.Builder.class) != null) {
return (TypeElement) enclosed;
Expand Down
11 changes: 8 additions & 3 deletions reflect/src/main/java/dagger/reflect/Binding.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ final class UnlinkedBinds<T> extends UnlinkedBinding<T> {
return new Key[] { dependency };
}

@SuppressWarnings("unchecked")
@Override public Binding<T> link(Binding<?>[] dependencies) {
return (Binding<T>) dependencies[0];
}
Expand Down Expand Up @@ -137,7 +138,9 @@ public Optional<T> get() {
if (dependency == null) {
return Optional.empty();
}
return Optional.of((T) dependency.get());
@SuppressWarnings("unchecked")
T value = (T) dependency.get();
return Optional.of(value);
}
}

Expand Down Expand Up @@ -179,12 +182,14 @@ final class LinkedProvides<T> extends LinkedBinding<T> {
this.dependencies = dependencies;
}

@Override public T get() {
@Override public @Nullable T get() {
Object[] arguments = new Object[dependencies.length];
for (int i = 0; i < arguments.length; i++) {
arguments[i] = dependencies[i].get();
}
return (T) tryInvoke(instance, method, arguments);
@SuppressWarnings("unchecked") // the binding is associated with the return type of method as key
T value = (T) tryInvoke(instance, method, arguments);
return value;
}
}

Expand Down
19 changes: 12 additions & 7 deletions reflect/src/main/java/dagger/reflect/BindingGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ private BindingGraph(Map<Key, Binding<?>> bindings, JustInTimeProvider jitProvid

Binding<?> getBinding(Key key) {
Binding<?> binding = locateBinding(key);
if (binding == null) {
throw new IllegalArgumentException("Unable to locate binding for " + key);
}
return binding.isLinked()
? binding
: performLinking(key, binding, new LinkedHashMap<>());
Expand All @@ -41,14 +44,17 @@ private Binding<?> performLinking(Key key, Binding<?> unlinked, Map<Key, Binding
chain.put(key, unlinked);

Key[] dependencyKeys = unlinked.dependencies();
Binding<?>[] dependencies = new Binding[dependencyKeys.length];
Binding<?>[] dependencies = new Binding<?>[dependencyKeys.length];

for (int i = 0; i < dependencyKeys.length; i++) {
Key dependencyKey = dependencyKeys[i];
@Nullable Binding<?> dependency = locateBinding(dependencyKey);

if (dependency == null && Types.equals(Types.getRawType(key.type()), Optional.class)) {
continue;
if (dependency == null) {
if (Types.equals(Types.getRawType(key.type()), Optional.class)) {
continue;
}
throw new IllegalArgumentException("Unable to locate binding for " + key);
}

if (!dependency.isLinked()) {
Expand Down Expand Up @@ -94,7 +100,7 @@ private Binding<?> performLinking(Key key, Binding<?> unlinked, Map<Key, Binding
return race;
}

@Nullable private Binding<?> locateBinding(Key key) {
private @Nullable Binding<?> locateBinding(Key key) {
Binding<?> binding = bindings.get(key);
if (binding != null) {
return binding;
Expand All @@ -107,9 +113,8 @@ private Binding<?> performLinking(Key key, Binding<?> unlinked, Map<Key, Binding
? replaced // We raced another thread and lost.
: jitBinding;
}
else {
return null;
}

return null;
}

static final class Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static <T> T create(Class<?> componentClass, Class<T> builderClass, Set<Class<?>
+ " must be public in order to be reflectively created");
}
return builderClass.cast(
Proxy.newProxyInstance(builderClass.getClassLoader(), new Class[] { builderClass },
Proxy.newProxyInstance(builderClass.getClassLoader(), new Class<?>[] { builderClass },
new ComponentBuilderInvocationHandler(componentClass, builderClass, modules,
dependencies)));
}
Expand All @@ -52,7 +52,7 @@ static <T> T create(Class<?> componentClass, Class<T> builderClass, Set<Class<?>
private final Map<Class<?>, Object> dependencyInstances;

private ComponentBuilderInvocationHandler(Class<?> componentClass, Class<?> builderClass,
Set<Class<?>> componentModules, Set<Class<?>> componentDependencies) {
Iterable<Class<?>> componentModules, Iterable<Class<?>> componentDependencies) {
this.componentClass = componentClass;
this.builderClass = builderClass;
this.boundInstances = new LinkedHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

final class ComponentInvocationHandler implements InvocationHandler {
static <T> T create(Class<T> cls, BindingGraph graph) {
return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls },
return cls.cast(Proxy.newProxyInstance(cls.getClassLoader(), new Class<?>[] { cls },
new ComponentInvocationHandler(graph)));
}

Expand Down Expand Up @@ -74,6 +74,7 @@ private static ComponentInvocationHandler.MethodInvocationHandler createMethodIn
"Members injection methods may only return the injected type or void: " + method);
}

@SuppressWarnings({"unchecked", "RedundantCast"})
MembersInjector<Object> injector =
(MembersInjector<Object>) ReflectiveMembersInjector.create(parameterTypes[0], graph);
return new MembersInjectorMethodInvocationHandler(injector, returnInstance);
Expand Down
5 changes: 2 additions & 3 deletions reflect/src/main/java/dagger/reflect/Reflection.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ final class Reflection {
return scope;
}

static void trySet(@Nullable Object instance, Field field, Object value) {
static void trySet(@Nullable Object instance, Field field, @Nullable Object value) {
if ((field.getModifiers() & Modifier.PUBLIC) == 0) {
field.setAccessible(true);
}
Expand All @@ -65,8 +65,7 @@ static void trySet(@Nullable Object instance, Field field, Object value) {
}
}

@Nullable
static Object tryInvoke(@Nullable Object instance, Method method, Object... arguments) {
static @Nullable Object tryInvoke(@Nullable Object instance, Method method, Object... arguments) {
if ((method.getModifiers() & Modifier.PUBLIC) == 0) {
method.setAccessible(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,25 @@ final class ReflectiveJustInTimeProvider implements BindingGraph.JustInTimeProvi
if (!(type instanceof Class<?>)) {
return null; // Parameterized/array types can't be just-in-time satisfied.
}
Class<Object> cls = (Class<Object>) type;
return create((Class<?>) type);
}

private static <T> @Nullable Binding<T> create(Class<T> cls) {
Annotation scope = findScope(cls.getAnnotations());
if (scope != null) {
throw notImplemented("Just-in-time scoped bindings");
}

Constructor<?>[] constructors = cls.getDeclaredConstructors();
Constructor<Object> target = null;
for (Constructor<?> constructor : constructors) {
@SuppressWarnings("unchecked")
Constructor<T>[] constructors = (Constructor<T>[]) cls.getDeclaredConstructors();
Constructor<T> target = null;
for (Constructor<T> constructor : constructors) {
if (constructor.getAnnotation(Inject.class) != null) {
if (target != null) {
throw new IllegalStateException(
cls.getCanonicalName() + " defines multiple @Inject-annotations constructors");
}
target = (Constructor<Object>) constructor;
target = constructor;
}
}
if (target == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ static <T> MembersInjector<T> create(Class<T> cls, BindingGraph graph) {

Type[] parameterTypes = method.getGenericParameterTypes();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
@SuppressWarnings("rawtypes")
Binding<?>[] bindings = new Binding[parameterTypes.length];
Binding<?>[] bindings = new Binding<?>[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
Key key = Key.of(findQualifier(parameterAnnotations[i]), parameterTypes[i]);
bindings[i] = graph.getBinding(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ static void parse(Class<?> moduleClass, @Nullable Object instance,
TypeWrapper wrapper = TypeWrapper.NONE;
if ((method.getModifiers() & ABSTRACT) != 0) {
if (method.getAnnotation(Binds.class) != null) {
binding = new Binding.UnlinkedBinds(method);
binding = new Binding.UnlinkedBinds<>(method);
} else if (method.getAnnotation(BindsOptionalOf.class) != null) {
wrapper = TypeWrapper.OPTIONAL;
binding = new Binding.UnlinkedOptionalBinding(method);
binding = new Binding.UnlinkedOptionalBinding<>(method);
} else {
continue;
}
Expand All @@ -59,7 +59,7 @@ static void parse(Class<?> moduleClass, @Nullable Object instance,
}

if (method.getAnnotation(Provides.class) != null) {
binding = new Binding.UnlinkedProvides(instance, method);
binding = new Binding.UnlinkedProvides<>(instance, method);
} else {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;

@SuppressWarnings("ALL") // Unused fields/parameters and over-specified visibility for testing.
@SuppressWarnings("unused") // Unused fields/parameters and over-specified visibility for testing.
public final class ReflectiveMembersInjectorTest {
private static class PrivateField {
// [dagger-compiler] error: Dagger does not support injection into private fields
Expand Down Expand Up @@ -95,7 +95,7 @@ private static class StaticMethod {
}
}

private static interface Interface {
private interface Interface {
// [dagger-compile] Methods with @Inject may not be abstract
@Inject void interfaceMethod(String one);
}
Expand Down