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
20 changes: 20 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ subprojects {
}

tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'

options.errorprone {
disableWarningsInGeneratedCode = true
excludedPaths = ".*/build/generated/.*"
Expand All @@ -118,6 +120,24 @@ subprojects {
assertsEnabled = true
}
}

options.compilerArgs += [
// 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',
// hide warning: auxiliary class C in full/path/to/C.java should not be accessed from outside its own source file
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What triggers all of these? I'm less interested in the description since that can be Googled but more interested in what causes them and why it's safe to ignore. Similar to an @Ignore for a test. The 'processing' one has a good justification but not these last two.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All 3 are the warning messages, not explanation. I'll research and explain them in the context of this project.

'-Xlint:-auxiliaryclass'
]

if (project.findProperty("strict.compilation") == "true") {
options.compilerArgs += [
// strict compilation, treat all warnings as errors, including errorprone
'-Werror'
]
}
}

plugins.withId('java-library') {
Expand Down
1 change: 1 addition & 0 deletions integration-tests/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ android {

versionCode 1
versionName '1'
javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = false
}

compileOptions {
Expand Down
4 changes: 4 additions & 0 deletions integration-tests/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example"
>

<application
android:name=".ExampleApp"
android:label="Dagger Reflect"
android:icon="@android:drawable/sym_def_app_icon"
android:allowBackup="false"
tools:ignore="GoogleAppIndexingWarning"
>
<activity android:name=".ExampleActivity">
<intent-filter>
Expand Down
4 changes: 4 additions & 0 deletions integration-tests/upstream/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,7 @@ def ensureDaggerSubmodule = tasks.create('ensureDaggerSubmodule') {
}
}
compileTestJava.dependsOn(ensureDaggerSubmodule)

tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
Comment thread
JakeWharton marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private static String getQualifiedNameForValueKotlin(
@NotNull JavaContext context, @Nullable UExpression annotationValue) {
final Object evaluatedAnnotationValue = ConstantEvaluator.evaluate(context, annotationValue);
if (evaluatedAnnotationValue instanceof kotlin.Pair) {
final kotlin.Pair value = (kotlin.Pair) evaluatedAnnotationValue;
final kotlin.Pair<?, ?> value = (kotlin.Pair<?, ?>) evaluatedAnnotationValue;
final String qualifiedName = (value.getFirst() + "." + value.getSecond());
return qualifiedName.replace("/", ".");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,27 @@ final class ReflectiveJustInTimeLookupFactory implements JustInTimeLookup.Factor
}

Type type = key.type();
Class<Object> cls;
return getJustInTimeLookup(type);
}

private @Nullable <T> JustInTimeLookup getJustInTimeLookup(Type type) {
Class<T> cls;
Type[] typeArguments = null;
if (type instanceof ParameterizedType) {
cls = (Class<Object>) ((ParameterizedType) type).getRawType();
// Assume that "representing the class or interface that declared this type" is a Class<?>.
@SuppressWarnings("unchecked")
Class<T> rawType = (Class<T>) ((ParameterizedType) type).getRawType();
cls = rawType;
typeArguments = ((ParameterizedType) type).getActualTypeArguments();
} else if (type instanceof Class<?>) {
cls = (Class<Object>) type;
@SuppressWarnings("unchecked")
Class<T> directClass = (Class<T>) type;
cls = directClass;
} else {
return null; // Array types can't be just-in-time satisfied.
}

Constructor<?>[] constructors = cls.getDeclaredConstructors();
Constructor<Object> target = null;
for (Constructor<?> 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;
}
}
Constructor<T> target = findSingleInjectConstructor(cls);
if (target == null) {
return null; // Types without an @Inject constructor cannot be just-in-time satisfied.
}
Expand All @@ -47,4 +46,21 @@ final class ReflectiveJustInTimeLookupFactory implements JustInTimeLookup.Factor
Binding binding = new UnlinkedJustInTimeBinding<>(cls, target, typeArguments);
return new JustInTimeLookup(scope, binding);
}

private static <T> @Nullable Constructor<T> findSingleInjectConstructor(Class<T> cls) {
// Not modifying it, safe to use generics; see Class#getConstructors() for more info.
@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;
}
}
return target;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class UnlinkedJustInTimeBinding<T> extends UnlinkedBinding {
private final Class<T> cls;
private final Constructor<T> constructor;
// Type arguments might be used as types for this binding's parameterized constructor parameters.
@Nullable private Type[] concreteTypeArguments;
private @Nullable Type[] concreteTypeArguments;

UnlinkedJustInTimeBinding(
Class<T> cls, Constructor<T> constructor, @Nullable Type[] concreteTypeArguments) {
Expand Down Expand Up @@ -45,7 +45,7 @@ public LinkedBinding<?> link(Linker linker, Scope scope) {

private Type getTypeKeyForParameter(Type parameterType) {
if (isTypeVariable(parameterType)) {
return matchTypeToConcreteType((TypeVariable) parameterType);
return matchTypeToConcreteType((TypeVariable<?>) parameterType);
} else if (hasParameterizedTypeVariable(parameterType)) {
return findKeyForParameterizedType((ParameterizedType) parameterType);
}
Expand Down Expand Up @@ -87,7 +87,7 @@ private Type[] matchingParameterizedType(Type[] typeArguments) {
Type[] matchedTypeArguments = new Type[typeArguments.length];
for (int i = 0; i < typeArguments.length; i++) {
if (isTypeVariable(typeArguments[i])) {
matchedTypeArguments[i] = matchTypeToConcreteType((TypeVariable) typeArguments[i]);
matchedTypeArguments[i] = matchTypeToConcreteType((TypeVariable<?>) typeArguments[i]);
} else {
matchedTypeArguments[i] = typeArguments[i];
}
Expand All @@ -103,7 +103,7 @@ private Type[] matchingParameterizedType(Type[] typeArguments) {
* @param typeToLookup The parameterized type placeholder to lookup.
* @return The matching concrete type for the placeholder.
*/
private Type matchTypeToConcreteType(TypeVariable typeToLookup) {
private Type matchTypeToConcreteType(TypeVariable<?> typeToLookup) {
if (concreteTypeArguments == null) {
throw new IllegalStateException(
"No concrete type arguments for " + cls + " but needed for " + typeToLookup);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ final class UnlinkedMapOfProviderBinding extends UnlinkedBinding {
}

@Override
public LinkedBinding<Map<Object, Provider<Object>>> link(Linker linker, Scope scope) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfortunate. Not that I expect anyone to ever see these types, and they're erased anyway, but it at least forces a bit of safety into the method. Doing LinkedBinding<Map<?, Provider<?>>> doesn't work?

Map<Object, Provider<Object>> mapOfProviders = new LinkedHashMap<>(entryBindings.size());
public LinkedBinding<?> link(Linker linker, Scope scope) {
Map<Object, Provider<?>> mapOfProviders = new LinkedHashMap<>(entryBindings.size());
for (Map.Entry<Object, Binding> entryBinding : entryBindings.entrySet()) {
LinkedBinding<Object> binding =
(LinkedBinding<Object>) entryBinding.getValue().link(linker, scope);
LinkedBinding<?> binding = entryBinding.getValue().link(linker, scope);
mapOfProviders.put(entryBinding.getKey(), binding);
}
return new LinkedInstanceBinding<>(mapOfProviders);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ final class UnlinkedMapOfValueBinding extends UnlinkedBinding {

@Override
public LinkedBinding<?> link(Linker linker, Scope scope) {
// Assume that mapOfProviderKey is Map<K, Provider<V>> and linker returns the correct Binding.
@SuppressWarnings("unchecked")
LinkedBinding<Map<Object, Provider<Object>>> mapOfProviderBinding =
(LinkedBinding<Map<Object, Provider<Object>>>) linker.get(mapOfProviderKey);
return new LinkedMapOfValueBinding<>(mapOfProviderBinding);
Expand Down
13 changes: 11 additions & 2 deletions reflect/src/main/java/dagger/reflect/UnlinkedSetBinding.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@ final class UnlinkedSetBinding extends UnlinkedBinding {
public LinkedBinding<?> link(Linker linker, Scope scope) {
List<LinkedBinding<Object>> linkedElementBindings = new ArrayList<>(elementBindings.size());
for (Binding elementBinding : elementBindings) {
linkedElementBindings.add((LinkedBinding<Object>) elementBinding.link(linker, scope));
@SuppressWarnings("unchecked")
LinkedBinding<Object> binding = (LinkedBinding<Object>) elementBinding.link(linker, scope);
linkedElementBindings.add(binding);
}

List<LinkedBinding<Set<Object>>> linkedElementsBindings =
new ArrayList<>(elementsBindings.size());
for (Binding elementsBinding : elementsBindings) {
linkedElementsBindings.add((LinkedBinding<Set<Object>>) elementsBinding.link(linker, scope));
@SuppressWarnings("unchecked")
LinkedBinding<Set<Object>> bindings =
(LinkedBinding<Set<Object>>) elementsBinding.link(linker, scope);
linkedElementsBindings.add(bindings);
}

// `elementBinding` and `elementBindings` came from the same key so we can use Object as T;
// hence their types will match, this is why unchecked warnings are OK above.
return new LinkedSetBinding<>(linkedElementBindings, linkedElementsBindings);
}

Expand Down