Skip to content

Commit c63e003

Browse files
java-team-github-botDagger Team
authored andcommitted
Fix type use nullable annotations
RELNOTES=N/A PiperOrigin-RevId: 720277354
1 parent 466e220 commit c63e003

13 files changed

+454
-26
lines changed

java/dagger/internal/DaggerCollections.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public static <T> List<T> presizedList(int size) {
6161
* Creates a {@link HashSet} instance, with a high enough "intial capcity" that it <em>should</em>
6262
* hold {@code expectedSize} elements without growth.
6363
*/
64-
static <T> HashSet<T> newHashSetWithExpectedSize(int expectedSize) {
64+
static <T extends @Nullable Object> HashSet<T> newHashSetWithExpectedSize(int expectedSize) {
6565
return new HashSet<T>(calculateInitialCapacity(expectedSize));
6666
}
6767

java/dagger/internal/DoubleCheck.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ public T get() {
7777
}
7878

7979
/** Returns a {@link Provider} that caches the value from the given delegate provider. */
80-
public static <T> dagger.internal.Provider<T> provider(dagger.internal.Provider<T> delegate) {
80+
public static <T extends @Nullable Object> dagger.internal.Provider<T> provider(
81+
dagger.internal.Provider<T> delegate) {
8182
checkNotNull(delegate);
8283
if (delegate instanceof DoubleCheck) {
8384
/* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped
@@ -98,7 +99,7 @@ public static <P extends javax.inject.Provider<T>, T> javax.inject.Provider<T> p
9899
}
99100

100101
/** Returns a {@link Lazy} that caches the value from the given provider. */
101-
public static <T> Lazy<T> lazy(Provider<T> provider) {
102+
public static <T extends @Nullable Object> Lazy<T> lazy(Provider<T> provider) {
102103
if (provider instanceof Lazy) {
103104
@SuppressWarnings("unchecked")
104105
final Lazy<T> lazy = (Lazy<T>) provider;

java/dagger/internal/SetFactory.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@
2828
import java.util.Collection;
2929
import java.util.List;
3030
import java.util.Set;
31+
import org.jspecify.annotations.Nullable;
3132

3233
/**
3334
* A {@link Factory} implementation used to implement {@link Set} bindings. This factory always
3435
* returns a new {@link Set} instance for each call to {@link #get} (as required by {@link Factory})
3536
* whose elements are populated by subsequent calls to their {@link Provider#get} methods.
3637
*/
37-
public final class SetFactory<T> implements Factory<Set<T>> {
38+
public final class SetFactory<T extends @Nullable Object> implements Factory<Set<T>> {
3839
private static final Factory<Set<Object>> EMPTY_FACTORY = InstanceFactory.create(emptySet());
3940

4041
@SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
41-
public static <T> Factory<Set<T>> empty() {
42+
public static <T extends @Nullable Object> Factory<Set<T>> empty() {
4243
return (Factory) EMPTY_FACTORY;
4344
}
4445

@@ -47,7 +48,8 @@ public static <T> Factory<Set<T>> empty() {
4748
* individual {@code Provider<T>} and {@code collectionProviderSize} {@code
4849
* Provider<Collection<T>>} instances.
4950
*/
50-
public static <T> Builder<T> builder(int individualProviderSize, int collectionProviderSize) {
51+
public static <T extends @Nullable Object> Builder<T> builder(
52+
int individualProviderSize, int collectionProviderSize) {
5153
return new Builder<T>(individualProviderSize, collectionProviderSize);
5254
}
5355

@@ -56,7 +58,7 @@ public static <T> Builder<T> builder(int individualProviderSize, int collectionP
5658
* These are only intended to be single-use and from within generated code. Do <em>NOT</em> add
5759
* providers after calling {@link #build()}.
5860
*/
59-
public static final class Builder<T> {
61+
public static final class Builder<T extends @Nullable Object> {
6062
private final List<Provider<T>> individualProviders;
6163
private final List<Provider<Collection<T>>> collectionProviders;
6264

java/dagger/internal/codegen/binding/FrameworkField.java

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616

1717
package dagger.internal.codegen.binding;
1818

19+
import static androidx.room.compiler.codegen.XTypeNameKt.toJavaPoet;
20+
import static androidx.room.compiler.codegen.XTypeNameKt.toKotlinPoet;
21+
import static androidx.room.compiler.codegen.compat.XConverters.toXPoet;
1922
import static androidx.room.compiler.processing.XElementKt.isConstructor;
2023
import static androidx.room.compiler.processing.XElementKt.isMethod;
2124
import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
2225
import static androidx.room.compiler.processing.XElementKt.isTypeElement;
2326
import static com.google.common.collect.Iterables.getLast;
27+
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
2428
import static dagger.internal.codegen.model.BindingKind.MEMBERS_INJECTOR;
2529
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
2630

@@ -30,7 +34,9 @@
3034
import androidx.room.compiler.processing.XType;
3135
import com.google.auto.value.AutoValue;
3236
import com.google.common.base.CaseFormat;
37+
import com.squareup.javapoet.AnnotationSpec;
3338
import dagger.internal.codegen.base.MapType;
39+
import dagger.internal.codegen.xprocessing.Nullability;
3440
import java.util.Optional;
3541

3642
/**
@@ -56,7 +62,8 @@ public abstract class FrameworkField {
5662
* @param type the base type of the field (e.g., {@code Foo}).
5763
*/
5864
public static FrameworkField create(String fieldName, XClassName frameworkClassName, XType type) {
59-
return createInternal(fieldName, frameworkClassName, Optional.of(type));
65+
return createInternal(
66+
fieldName, frameworkClassName, Optional.of(type), Nullability.NOT_NULLABLE);
6067
}
6168

6269
/**
@@ -70,7 +77,8 @@ public static FrameworkField forBinding(
7077
return createInternal(
7178
bindingName(binding),
7279
frameworkClassName.orElse(binding.frameworkType().frameworkClassName()),
73-
bindingType(binding));
80+
bindingType(binding),
81+
binding.nullability());
7482
}
7583

7684
private static String bindingName(ContributionBinding binding) {
@@ -99,13 +107,28 @@ private static Optional<XType> bindingType(ContributionBinding binding) {
99107
}
100108

101109
private static FrameworkField createInternal(
102-
String fieldName, XClassName frameworkClassName, Optional<XType> type) {
110+
String fieldName,
111+
XClassName frameworkClassName,
112+
Optional<XType> type,
113+
Nullability nullability) {
114+
115+
XTypeName fieldType =
116+
type.map(XType::asTypeName)
117+
.map(
118+
typeName ->
119+
toXPoet(
120+
toJavaPoet(typeName)
121+
.annotated(
122+
nullability.typeUseNullableAnnotations().stream()
123+
.map(AnnotationSpec::builder)
124+
.map(AnnotationSpec.Builder::build)
125+
.collect(toImmutableList())),
126+
toKotlinPoet(typeName)))
127+
.map(frameworkClassName::parametrizedBy)
128+
.orElse(frameworkClassName);
129+
103130
return new AutoValue_FrameworkField(
104-
frameworkFieldName(fieldName, frameworkClassName),
105-
type.isPresent()
106-
? frameworkClassName.parametrizedBy(type.get().asTypeName())
107-
// Use a raw framework classname, e.g. Provider
108-
: frameworkClassName);
131+
frameworkFieldName(fieldName, frameworkClassName), fieldType);
109132
}
110133

111134
private static String frameworkFieldName(String fieldName, XClassName frameworkClassName) {

java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,12 @@ public CodeBlock creationExpression() {
127127
componentShard.addType(
128128
COMPONENT_PROVISION_FACTORY,
129129
classBuilder(factoryClassName)
130-
.addSuperinterface(daggerProviderOf(keyType))
130+
.addSuperinterface(
131+
daggerProviderOf(
132+
keyType.annotated(
133+
binding.nullability().typeUseNullableAnnotations().stream()
134+
.map(annotation -> AnnotationSpec.builder(annotation).build())
135+
.collect(toImmutableList()))))
131136
.addModifiers(PRIVATE, STATIC, FINAL)
132137
.addField(dependencyClassName, dependency().variableName(), PRIVATE, FINAL)
133138
.addMethod(

java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,10 @@ private FieldSpec getOrCreateField() {
144144
FrameworkField.forBinding(
145145
binding, frameworkInstanceCreationExpression.alternativeFrameworkClass());
146146

147-
XTypeName fieldType = useRawType
148-
? contributionBindingField.type().getRawTypeName()
149-
: contributionBindingField.type();
147+
XTypeName fieldType =
148+
useRawType
149+
? contributionBindingField.type().getRawTypeName()
150+
: contributionBindingField.type();
150151

151152
if (binding.kind() == BindingKind.ASSISTED_INJECTION) {
152153
// An assisted injection factory doesn't extend Provider, so we reference the generated

java/dagger/internal/codegen/writing/MembersInjectorGenerator.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,7 @@ private static ImmutableMap<DependencyRequest, FieldSpec> frameworkFields(
363363
// framework type for the field.
364364
boolean useRawFrameworkType =
365365
!isTypeAccessibleFrom(
366-
request.key().type().xprocessing(),
367-
membersInjectorTypeName.packageName());
366+
request.key().type().xprocessing(), membersInjectorTypeName.packageName());
368367
TypeName fieldType =
369368
useRawFrameworkType
370369
? toJavaPoet(bindingField.type().getRawTypeName())

java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,12 @@ static FactoryFields create(ProductionBinding binding) {
452452

453453
ImmutableMap.Builder<DependencyRequest, FieldSpec> builder =
454454
ImmutableMap.builder();
455-
generateBindingFieldsForDependencies(binding).forEach(
456-
(dependency, field) ->
457-
builder.put(
458-
dependency,
459-
createField(toJavaPoet(field.type()), nameSet.getUniqueName(field.name()))));
455+
generateBindingFieldsForDependencies(binding)
456+
.forEach(
457+
(dependency, field) ->
458+
builder.put(
459+
dependency,
460+
createField(toJavaPoet(field.type()), nameSet.getUniqueName(field.name()))));
460461
return new FactoryFields(binding, moduleField, builder.buildOrThrow());
461462
}
462463

javatests/dagger/internal/codegen/ComponentProcessorTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ public static Collection<Object[]> parameters() {
4646
return CompilerMode.TEST_PARAMETERS;
4747
}
4848

49+
private static final Source NULLABLE =
50+
CompilerTests.javaSource(
51+
"test.Nullable", // force one-string-per-line format
52+
"package test;",
53+
"",
54+
"public @interface Nullable {}");
55+
4956
private static final TypeSpec GENERATED_INJECT_TYPE =
5057
TypeSpec.classBuilder("GeneratedInjectType")
5158
.addMethod(
@@ -776,6 +783,48 @@ public void componentDependency() throws Exception {
776783
});
777784
}
778785

786+
@Test
787+
public void componentWithNullableDependency() throws Exception {
788+
Source bFile =
789+
CompilerTests.javaSource(
790+
"test.B",
791+
"package test;",
792+
"",
793+
"import javax.inject.Inject;",
794+
"import javax.inject.Provider;",
795+
"",
796+
"final class B {",
797+
" @Inject B(Provider<String> a) {}",
798+
"}");
799+
Source nullableStringComponentFile =
800+
CompilerTests.javaSource(
801+
"test.NullableStringComponent",
802+
"package test;",
803+
"",
804+
"interface NullableStringComponent {",
805+
" @Nullable String nullableString();",
806+
"}");
807+
Source bComponentFile =
808+
CompilerTests.javaSource(
809+
"test.BComponent",
810+
"package test;",
811+
"",
812+
"import dagger.Component;",
813+
"",
814+
"@Component(dependencies = NullableStringComponent.class)",
815+
"interface BComponent {",
816+
" B b();",
817+
"}");
818+
819+
CompilerTests.daggerCompiler(nullableStringComponentFile, bFile, bComponentFile, NULLABLE)
820+
.withProcessingOptions(compilerMode.processorOptions())
821+
.compile(
822+
subject -> {
823+
subject.hasErrorCount(0);
824+
subject.generatedSource(goldenFileRule.goldenSource("test/DaggerBComponent"));
825+
});
826+
}
827+
779828
@Test
780829
public void primitiveComponentDependency() throws Exception {
781830
Source bFile = CompilerTests.javaSource("test.B",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package test;
2+
3+
import dagger.internal.DaggerGenerated;
4+
import dagger.internal.Preconditions;
5+
import dagger.internal.Provider;
6+
import javax.annotation.processing.Generated;
7+
8+
@DaggerGenerated
9+
@Generated(
10+
value = "dagger.internal.codegen.ComponentProcessor",
11+
comments = "https://dagger.dev"
12+
)
13+
@SuppressWarnings({
14+
"unchecked",
15+
"rawtypes",
16+
"KotlinInternal",
17+
"KotlinInternalInJava",
18+
"cast",
19+
"deprecation",
20+
"nullness:initialization.field.uninitialized"
21+
})
22+
final class DaggerBComponent {
23+
private DaggerBComponent() {
24+
}
25+
26+
public static Builder builder() {
27+
return new Builder();
28+
}
29+
30+
static final class Builder {
31+
private NullableStringComponent nullableStringComponent;
32+
33+
private Builder() {
34+
}
35+
36+
public Builder nullableStringComponent(NullableStringComponent nullableStringComponent) {
37+
this.nullableStringComponent = Preconditions.checkNotNull(nullableStringComponent);
38+
return this;
39+
}
40+
41+
public BComponent build() {
42+
Preconditions.checkBuilderRequirement(nullableStringComponent, NullableStringComponent.class);
43+
return new BComponentImpl(nullableStringComponent);
44+
}
45+
}
46+
47+
private static final class BComponentImpl implements BComponent {
48+
private final BComponentImpl bComponentImpl = this;
49+
50+
private Provider<String> nullableStringProvider;
51+
52+
private BComponentImpl(NullableStringComponent nullableStringComponentParam) {
53+
54+
initialize(nullableStringComponentParam);
55+
56+
}
57+
58+
@SuppressWarnings("unchecked")
59+
private void initialize(final NullableStringComponent nullableStringComponentParam) {
60+
this.nullableStringProvider = new NullableStringProvider(nullableStringComponentParam);
61+
}
62+
63+
@Override
64+
public B b() {
65+
return new B(nullableStringProvider);
66+
}
67+
68+
private static final class NullableStringProvider implements Provider<String> {
69+
private final NullableStringComponent nullableStringComponent;
70+
71+
NullableStringProvider(NullableStringComponent nullableStringComponent) {
72+
this.nullableStringComponent = nullableStringComponent;
73+
}
74+
75+
@Override
76+
@Nullable
77+
public String get() {
78+
return nullableStringComponent.nullableString();
79+
}
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)