From 6da2e7ea898bb7d62ae634d7d3ff0d2d4dfdd82f Mon Sep 17 00:00:00 2001 From: Brad Corso Date: Wed, 26 May 2021 09:32:12 -0700 Subject: [PATCH] Remove dagger-android-processor's dependency on dagger-android-jarimpl artifact. Due mainly to BasicAnnotationProcessor.ProcessingStep, the dagger-android-processor required a dependency on the dagger-android annotation classes. However, due to restrictions on java_plugin depending on an android_library, mentioned in https://github.com/bazelbuild/bazel/issues/2517, we had to create a java_import to work around this issue. However, soon even the java_import workaround will no longer work. This CL fixes the above issues by switching to the new BasicAnnotaitonProcessor.Step, which allows processing annotations via String instead of Class, which allows us to remove the processors dependency on the dagger-android API altogether. RELNOTES=the Dagger artifact, "dagger-android-jarimpl", has been removed. This was an internal-only artifact, so its removal shouldn't affect users. PiperOrigin-RevId: 375962581 --- java/dagger/android/BUILD | 8 -- .../processor/AndroidInjectorDescriptor.java | 25 ++-- .../processor/AndroidMapKeyValidator.java | 54 ++++----- .../android/processor/AndroidMapKeys.java | 3 +- .../android/processor/AndroidProcessor.java | 2 +- java/dagger/android/processor/BUILD | 26 +--- .../ContributesAndroidInjectorGenerator.java | 55 +++------ .../DuplicateAndroidInjectorsChecker.java | 11 +- .../android/processor/MoreDaggerElements.java | 61 ++++++++++ .../android/processor/MoreDaggerTypes.java | 114 ++++++++++++++++++ java/dagger/android/processor/TypeNames.java | 52 ++++++++ util/deploy-dagger.sh | 7 -- 12 files changed, 294 insertions(+), 124 deletions(-) create mode 100644 java/dagger/android/processor/MoreDaggerElements.java create mode 100644 java/dagger/android/processor/MoreDaggerTypes.java create mode 100644 java/dagger/android/processor/TypeNames.java diff --git a/java/dagger/android/BUILD b/java/dagger/android/BUILD index f0cea4149dd..64c4014028f 100644 --- a/java/dagger/android/BUILD +++ b/java/dagger/android/BUILD @@ -68,14 +68,6 @@ pom_file( targets = [":android"], ) -# b/37741866 and https://github.com/google/dagger/issues/715 -pom_file( - name = "jarimpl-pom", - artifact_id = "dagger-android-jarimpl", - artifact_name = "Dagger Android", - targets = [":android"], -) - dejetified_library( name = "dejetified-android", input = ":android.aar", diff --git a/java/dagger/android/processor/AndroidInjectorDescriptor.java b/java/dagger/android/processor/AndroidInjectorDescriptor.java index 3ec66139e91..2e21233c758 100644 --- a/java/dagger/android/processor/AndroidInjectorDescriptor.java +++ b/java/dagger/android/processor/AndroidInjectorDescriptor.java @@ -18,8 +18,6 @@ import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations; import static com.google.auto.common.AnnotationMirrors.getAnnotationValue; -import static com.google.auto.common.MoreElements.getAnnotationMirror; -import static com.google.auto.common.MoreElements.isAnnotationPresent; import static java.util.stream.Collectors.toList; import static javax.lang.model.element.Modifier.ABSTRACT; @@ -30,8 +28,6 @@ import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; -import dagger.Module; -import dagger.android.ContributesAndroidInjector; import java.util.List; import java.util.Optional; import javax.annotation.processing.Messager; @@ -47,24 +43,24 @@ import javax.tools.Diagnostic.Kind; /** - * A descriptor of a generated {@link Module} and {@link dagger.Subcomponent} to be generated from a - * {@link ContributesAndroidInjector} method. + * A descriptor of a generated {@link dagger.Module} and {@link dagger.Subcomponent} to be generated + * from a {@code ContributesAndroidInjector} method. */ @AutoValue abstract class AndroidInjectorDescriptor { - /** The type to be injected; the return type of the {@link ContributesAndroidInjector} method. */ + /** The type to be injected; the return type of the {@code ContributesAndroidInjector} method. */ abstract ClassName injectedType(); /** Scopes to apply to the generated {@link dagger.Subcomponent}. */ abstract ImmutableSet scopes(); - /** @see ContributesAndroidInjector#modules() */ + /** See {@code ContributesAndroidInjector#modules()} */ abstract ImmutableSet modules(); - /** The {@link Module} that contains the {@link ContributesAndroidInjector} method. */ + /** The {@link dagger.Module} that contains the {@code ContributesAndroidInjector} method. */ abstract ClassName enclosingModule(); - /** The method annotated with {@link ContributesAndroidInjector}. */ + /** The method annotated with {@code ContributesAndroidInjector}. */ abstract ExecutableElement method(); @AutoValue.Builder @@ -90,7 +86,7 @@ static final class Validator { } /** - * Validates a {@link ContributesAndroidInjector} method, returning an {@link + * Validates a {@code ContributesAndroidInjector} method, returning an {@link * AndroidInjectorDescriptor} if it is valid, or {@link Optional#empty()} otherwise. */ Optional createIfValid(ExecutableElement method) { @@ -107,7 +103,7 @@ Optional createIfValid(ExecutableElement method) { AndroidInjectorDescriptor.Builder builder = new AutoValue_AndroidInjectorDescriptor.Builder().method(method); TypeElement enclosingElement = MoreElements.asType(method.getEnclosingElement()); - if (!isAnnotationPresent(enclosingElement, Module.class)) { + if (!MoreDaggerElements.isAnnotationPresent(enclosingElement, TypeNames.MODULE)) { reporter.reportError("@ContributesAndroidInjector methods must be in a @Module"); } builder.enclosingModule(ClassName.get(enclosingElement)); @@ -121,10 +117,11 @@ Optional createIfValid(ExecutableElement method) { } AnnotationMirror annotation = - getAnnotationMirror(method, ContributesAndroidInjector.class).get(); + MoreDaggerElements.getAnnotationMirror(method, TypeNames.CONTRIBUTES_ANDROID_INJECTOR) + .get(); for (TypeMirror module : getAnnotationValue(annotation, "modules").accept(new AllTypesVisitor(), null)) { - if (isAnnotationPresent(MoreTypes.asElement(module), Module.class)) { + if (MoreDaggerElements.isAnnotationPresent(MoreTypes.asElement(module), TypeNames.MODULE)) { builder.modulesBuilder().add((ClassName) TypeName.get(module)); } else { reporter.reportError(String.format("%s is not a @Module", module), annotation); diff --git a/java/dagger/android/processor/AndroidMapKeyValidator.java b/java/dagger/android/processor/AndroidMapKeyValidator.java index f6e808ac695..fe85a516d53 100644 --- a/java/dagger/android/processor/AndroidMapKeyValidator.java +++ b/java/dagger/android/processor/AndroidMapKeyValidator.java @@ -17,22 +17,16 @@ package dagger.android.processor; import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations; -import static com.google.auto.common.MoreElements.getAnnotationMirror; -import static com.google.auto.common.MoreElements.isAnnotationPresent; import static com.google.common.collect.Iterables.getOnlyElement; import static dagger.android.processor.AndroidMapKeys.injectedTypeFromMapKey; -import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; +import com.google.auto.common.BasicAnnotationProcessor.Step; import com.google.auto.common.MoreElements; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.SetMultimap; -import dagger.Binds; +import com.google.common.collect.ImmutableSetMultimap; +import com.squareup.javapoet.ClassName; import dagger.MapKey; -import dagger.android.AndroidInjectionKey; -import dagger.android.AndroidInjector; -import dagger.multibindings.ClassKey; -import java.lang.annotation.Annotation; -import java.util.Set; import javax.annotation.processing.Messager; import javax.inject.Qualifier; import javax.inject.Scope; @@ -46,8 +40,13 @@ import javax.lang.model.util.Types; import javax.tools.Diagnostic.Kind; -/** Validates the correctness of {@link MapKey}s used with {@code dagger.android}. */ -final class AndroidMapKeyValidator implements ProcessingStep { +/** Validates the correctness of {@link dagger.MapKey}s used with {@code dagger.android}. */ +final class AndroidMapKeyValidator implements Step { + private static final ImmutableMap SUPPORTED_ANNOTATIONS = + ImmutableMap.of( + TypeNames.ANDROID_INJECTION_KEY.toString(), TypeNames.ANDROID_INJECTION_KEY, + TypeNames.CLASS_KEY.toString(), TypeNames.CLASS_KEY); + private final Elements elements; private final Types types; private final Messager messager; @@ -59,16 +58,12 @@ final class AndroidMapKeyValidator implements ProcessingStep { } @Override - public Set> annotations() { - return ImmutableSet.>builder() - .add(AndroidInjectionKey.class) - .add(ClassKey.class) - .build(); + public ImmutableSet annotations() { + return SUPPORTED_ANNOTATIONS.keySet(); } @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { + public ImmutableSet process(ImmutableSetMultimap elementsByAnnotation) { ImmutableSet.Builder deferredElements = ImmutableSet.builder(); elementsByAnnotation .entries() @@ -83,7 +78,7 @@ public Set process( return deferredElements.build(); } - private void validateMethod(Class annotation, ExecutableElement method) { + private void validateMethod(String annotation, ExecutableElement method) { if (!getAnnotatedAnnotations(method, Qualifier.class).isEmpty()) { return; } @@ -107,7 +102,7 @@ private void validateMethod(Class annotation, ExecutableEl Kind.ERROR, String.format( "%s bindings should not be scoped. Scoping this method may leak instances of %s.", - AndroidInjector.Factory.class.getCanonicalName(), + TypeNames.ANDROID_INJECTOR_FACTORY.canonicalName(), mapKeyValueElement.getQualifiedName()), method); } @@ -117,7 +112,8 @@ private void validateMethod(Class annotation, ExecutableEl // @Binds methods should only have one parameter, but we can't guarantee the order of Processors // in javac, so do a basic check for valid form - if (isAnnotationPresent(method, Binds.class) && method.getParameters().size() == 1) { + if (MoreDaggerElements.isAnnotationPresent(method, TypeNames.BINDS) + && method.getParameters().size() == 1) { validateMapKeyMatchesBindsParameter(annotation, method); } } @@ -138,10 +134,10 @@ private void validateReturnType(ExecutableElement method) { } /** - * A valid @Binds method could bind an {@link AndroidInjector.Factory} for one type, while giving + * A valid @Binds method could bind an {@code AndroidInjector.Factory} for one type, while giving * it a map key of a different type. The return type and parameter type would pass typical @Binds - * validation, but the map lookup in {@link dagger.android.DispatchingAndroidInjector} would - * retrieve the wrong injector factory. + * validation, but the map lookup in {@code DispatchingAndroidInjector} would retrieve the wrong + * injector factory. * *
{@code
    * {@literal @Binds}
@@ -151,10 +147,10 @@ private void validateReturnType(ExecutableElement method) {
    *     BlueActivityComponent.Builder builder);
    * }
*/ - private void validateMapKeyMatchesBindsParameter( - Class annotation, ExecutableElement method) { + private void validateMapKeyMatchesBindsParameter(String annotation, ExecutableElement method) { TypeMirror parameterType = getOnlyElement(method.getParameters()).asType(); - AnnotationMirror annotationMirror = getAnnotationMirror(method, annotation).get(); + AnnotationMirror annotationMirror = + MoreDaggerElements.getAnnotationMirror(method, SUPPORTED_ANNOTATIONS.get(annotation)).get(); TypeMirror mapKeyType = elements.getTypeElement(injectedTypeFromMapKey(annotationMirror).get()).asType(); if (!types.isAssignable(parameterType, injectorFactoryOf(mapKeyType))) { @@ -172,6 +168,6 @@ private DeclaredType injectorFactoryOf(TypeMirror implementationType) { } private TypeElement factoryElement() { - return elements.getTypeElement(AndroidInjector.Factory.class.getCanonicalName()); + return elements.getTypeElement(TypeNames.ANDROID_INJECTOR_FACTORY.canonicalName()); } } diff --git a/java/dagger/android/processor/AndroidMapKeys.java b/java/dagger/android/processor/AndroidMapKeys.java index fb1fc3853cb..28da2715afd 100644 --- a/java/dagger/android/processor/AndroidMapKeys.java +++ b/java/dagger/android/processor/AndroidMapKeys.java @@ -19,7 +19,6 @@ import static com.google.auto.common.AnnotationMirrors.getAnnotationValue; import com.google.auto.common.MoreTypes; -import dagger.android.AndroidInjectionKey; import java.util.Optional; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.TypeElement; @@ -27,7 +26,7 @@ final class AndroidMapKeys { /** - * If {@code mapKey} is {@link AndroidInjectionKey}, returns the string value for the map key. If + * If {@code mapKey} is {@code AndroidInjectionKey}, returns the string value for the map key. If * it's {@link dagger.multibindings.ClassKey}, returns the fully-qualified class name of the * annotation value. Otherwise returns {@link Optional#empty()}. */ diff --git a/java/dagger/android/processor/AndroidProcessor.java b/java/dagger/android/processor/AndroidProcessor.java index ad7f08ef0c8..357f7dea4e1 100644 --- a/java/dagger/android/processor/AndroidProcessor.java +++ b/java/dagger/android/processor/AndroidProcessor.java @@ -55,7 +55,7 @@ public final class AndroidProcessor extends BasicAnnotationProcessor { "dagger.android.experimentalUseStringKeys"; @Override - protected Iterable initSteps() { + protected Iterable steps() { Filer filer = new FormattingFiler(processingEnv.getFiler()); Messager messager = processingEnv.getMessager(); Elements elements = processingEnv.getElementUtils(); diff --git a/java/dagger/android/processor/BUILD b/java/dagger/android/processor/BUILD index 7e63c763383..f89d104a65d 100644 --- a/java/dagger/android/processor/BUILD +++ b/java/dagger/android/processor/BUILD @@ -15,7 +15,7 @@ # Description: # Public Dagger API for Android -load("@rules_java//java:defs.bzl", "java_import", "java_library", "java_plugin") +load("@rules_java//java:defs.bzl", "java_library", "java_plugin") load( "//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", @@ -38,35 +38,19 @@ java_library( javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES, tags = ["maven_coordinates=com.google.dagger:dagger-android-processor:" + POM_VERSION], deps = [ + "//java/dagger:core", "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", + "//java/dagger/spi", "@google_bazel_common//third_party/java/auto:service", "@google_bazel_common//third_party/java/auto:value", - "@maven//:com_google_auto_auto_common", + "@google_bazel_common//third_party/java/google_java_format", "@google_bazel_common//third_party/java/incap", "@google_bazel_common//third_party/java/javapoet", - "@google_bazel_common//third_party/java/google_java_format", - "//java/dagger:core", - "//java/dagger/spi", - # https://github.com/bazelbuild/bazel/issues/2517 - ":dagger-android-jar", + "@maven//:com_google_auto_auto_common", ], ) -# https://github.com/bazelbuild/bazel/issues/2517 -# This target serves two (related) purposes: -# 1. Bazel does not allow a java_library to depend on an android_library, even if that java_library -# will be used in a java_plugin. -# 2. It stores the metadata for the "jarimpl" target that we use to work-around Gradle not loading -# aar artifacts that are declared as deps of an annotation processor. Our pom.xml generator reads -# the tags and includes them apppropriately. -java_import( - name = "dagger-android-jar", - jars = ["//java/dagger/android:libandroid.jar"], - tags = ["maven_coordinates=com.google.dagger:dagger-android-jarimpl:" + POM_VERSION], - visibility = ["//visibility:private"], -) - pom_file( name = "pom", artifact_id = "dagger-android-processor", diff --git a/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java b/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java index 5c99fd41343..f3f4d18abd8 100644 --- a/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java +++ b/java/dagger/android/processor/ContributesAndroidInjectorGenerator.java @@ -29,10 +29,10 @@ import static javax.lang.model.element.Modifier.STATIC; import static javax.lang.model.util.ElementFilter.methodsIn; -import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; +import com.google.auto.common.BasicAnnotationProcessor.Step; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.SetMultimap; +import com.google.common.collect.ImmutableSetMultimap; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; @@ -41,26 +41,16 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.WildcardTypeName; -import dagger.Binds; -import dagger.Module; -import dagger.Subcomponent; -import dagger.android.AndroidInjectionKey; -import dagger.android.AndroidInjector; -import dagger.android.ContributesAndroidInjector; import dagger.android.processor.AndroidInjectorDescriptor.Validator; -import dagger.multibindings.ClassKey; -import dagger.multibindings.IntoMap; import java.io.IOException; -import java.lang.annotation.Annotation; -import java.util.Set; import javax.annotation.processing.Filer; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.util.Elements; -/** Generates the implementation specified in {@link ContributesAndroidInjector}. */ -final class ContributesAndroidInjectorGenerator implements ProcessingStep { +/** Generates the implementation specified in {@code ContributesAndroidInjector}. */ +final class ContributesAndroidInjectorGenerator implements Step { private final AndroidInjectorDescriptor.Validator validator; private final Filer filer; @@ -82,13 +72,12 @@ final class ContributesAndroidInjectorGenerator implements ProcessingStep { } @Override - public Set> annotations() { - return ImmutableSet.of(ContributesAndroidInjector.class); + public ImmutableSet annotations() { + return ImmutableSet.of(TypeNames.CONTRIBUTES_ANDROID_INJECTOR.toString()); } @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { + public ImmutableSet process(ImmutableSetMultimap elementsByAnnotation) { ImmutableSet.Builder deferredElements = ImmutableSet.builder(); for (ExecutableElement method : methodsIn(elementsByAnnotation.values())) { try { @@ -118,7 +107,7 @@ private void generate(AndroidInjectorDescriptor descriptor) { classBuilder(moduleName) .addOriginatingElement(descriptor.method()) .addAnnotation( - AnnotationSpec.builder(Module.class) + AnnotationSpec.builder(TypeNames.MODULE) .addMember("subcomponents", "$T.class", subcomponentName) .build()) .addModifiers(PUBLIC, ABSTRACT) @@ -141,25 +130,24 @@ private void generate(AndroidInjectorDescriptor descriptor) { private MethodSpec bindAndroidInjectorFactory( AndroidInjectorDescriptor descriptor, ClassName subcomponentBuilderName) { return methodBuilder("bindAndroidInjectorFactory") - .addAnnotation(Binds.class) - .addAnnotation(IntoMap.class) + .addAnnotation(TypeNames.BINDS) + .addAnnotation(TypeNames.INTO_MAP) .addAnnotation(androidInjectorMapKey(descriptor)) .addModifiers(ABSTRACT) .returns( - parameterizedTypeName( - AndroidInjector.Factory.class, - WildcardTypeName.subtypeOf(TypeName.OBJECT))) + ParameterizedTypeName.get( + TypeNames.ANDROID_INJECTOR_FACTORY, WildcardTypeName.subtypeOf(TypeName.OBJECT))) .addParameter(subcomponentBuilderName, "builder") .build(); } private AnnotationSpec androidInjectorMapKey(AndroidInjectorDescriptor descriptor) { if (useStringKeys) { - return AnnotationSpec.builder(AndroidInjectionKey.class) + return AnnotationSpec.builder(TypeNames.ANDROID_INJECTION_KEY) .addMember("value", "$S", descriptor.injectedType().toString()) .build(); } - return AnnotationSpec.builder(ClassKey.class) + return AnnotationSpec.builder(TypeNames.CLASS_KEY) .addMember("value", "$T.class", descriptor.injectedType()) .build(); } @@ -168,7 +156,7 @@ private TypeSpec subcomponent( AndroidInjectorDescriptor descriptor, ClassName subcomponentName, ClassName subcomponentFactoryName) { - AnnotationSpec.Builder subcomponentAnnotation = AnnotationSpec.builder(Subcomponent.class); + AnnotationSpec.Builder subcomponentAnnotation = AnnotationSpec.builder(TypeNames.SUBCOMPONENT); for (ClassName module : descriptor.modules()) { subcomponentAnnotation.addMember("modules", "$T.class", module); } @@ -177,7 +165,8 @@ private TypeSpec subcomponent( .addModifiers(PUBLIC) .addAnnotation(subcomponentAnnotation.build()) .addAnnotations(descriptor.scopes()) - .addSuperinterface(parameterizedTypeName(AndroidInjector.class, descriptor.injectedType())) + .addSuperinterface( + ParameterizedTypeName.get(TypeNames.ANDROID_INJECTOR, descriptor.injectedType())) .addType(subcomponentFactory(descriptor, subcomponentFactoryName)) .build(); } @@ -185,15 +174,11 @@ private TypeSpec subcomponent( private TypeSpec subcomponentFactory( AndroidInjectorDescriptor descriptor, ClassName subcomponentFactoryName) { return interfaceBuilder(subcomponentFactoryName) - .addAnnotation(Subcomponent.Factory.class) + .addAnnotation(TypeNames.SUBCOMPONENT_FACTORY) .addModifiers(PUBLIC, STATIC) .addSuperinterface( - parameterizedTypeName(AndroidInjector.Factory.class, descriptor.injectedType())) + ParameterizedTypeName.get( + TypeNames.ANDROID_INJECTOR_FACTORY, descriptor.injectedType())) .build(); } - - private static ParameterizedTypeName parameterizedTypeName( - Class clazz, TypeName... typeArguments) { - return ParameterizedTypeName.get(ClassName.get(clazz), typeArguments); - } } diff --git a/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java b/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java index a19c5efaa15..bcc8e5a1e68 100644 --- a/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java +++ b/java/dagger/android/processor/DuplicateAndroidInjectorsChecker.java @@ -30,8 +30,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimaps; import dagger.MapKey; -import dagger.android.AndroidInjector; -import dagger.android.DispatchingAndroidInjector; import dagger.model.Binding; import dagger.model.BindingGraph; import dagger.model.BindingKind; @@ -43,13 +41,12 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Stream; -import javax.inject.Provider; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; /** - * Validates that the two maps that {@link DispatchingAndroidInjector} injects have logically + * Validates that the two maps that {@code DispatchingAndroidInjector} injects have logically * different keys. If a contribution exists for the same {@code FooActivity} with * {@code @ActivityKey(FooActivity.class)} and * {@code @AndroidInjectionKey("com.example.FooActivity")}, report an error. @@ -67,7 +64,7 @@ public void visitGraph(BindingGraph graph, DiagnosticReporter diagnosticReporter private boolean isDispatchingAndroidInjector(Binding binding) { Key key = binding.key(); - return MoreTypes.isTypeOf(DispatchingAndroidInjector.class, key.type()) + return MoreDaggerTypes.isTypeOf(TypeNames.DISPATCHING_ANDROID_INJECTOR, key.type()) && !key.qualifier().isPresent(); } @@ -118,12 +115,12 @@ private Stream injectorMapDependencies(Binding binding, BindingGraph gr requestedBinding -> { TypeMirror valueType = MoreTypes.asDeclared(requestedBinding.key().type()).getTypeArguments().get(1); - if (!MoreTypes.isTypeOf(Provider.class, valueType) + if (!MoreDaggerTypes.isTypeOf(TypeNames.PROVIDER, valueType) || !valueType.getKind().equals(TypeKind.DECLARED)) { return false; } TypeMirror providedType = MoreTypes.asDeclared(valueType).getTypeArguments().get(0); - return MoreTypes.isTypeOf(AndroidInjector.Factory.class, providedType); + return MoreDaggerTypes.isTypeOf(TypeNames.ANDROID_INJECTOR_FACTORY, providedType); }); } diff --git a/java/dagger/android/processor/MoreDaggerElements.java b/java/dagger/android/processor/MoreDaggerElements.java new file mode 100644 index 00000000000..06dea38caa0 --- /dev/null +++ b/java/dagger/android/processor/MoreDaggerElements.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 The Dagger Authors. + * + * 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 dagger.android.processor; + +import com.google.auto.common.MoreElements; +import com.squareup.javapoet.ClassName; +import java.util.Optional; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +// TODO(bcorso): Dedupe with dagger/internal/codegen/langmodel/DaggerElements.java? +// TODO(bcorso): Contribute upstream to auto common? +/** Similar to auto common, but uses {@link ClassName} rather than {@link Class}. */ +final class MoreDaggerElements { + /** + * Returns {@code true} iff the given element has an {@link AnnotationMirror} whose {@linkplain + * AnnotationMirror#getAnnotationType() annotation type} has the same canonical name as that of + * {@code annotationClass}. This method is a safer alternative to calling {@link + * Element#getAnnotation} and checking for {@code null} as it avoids any interaction with + * annotation proxies. + */ + public static boolean isAnnotationPresent(Element element, ClassName annotationName) { + return getAnnotationMirror(element, annotationName).isPresent(); + } + + /** + * Returns an {@link AnnotationMirror} for the annotation of type {@code annotationClass} on + * {@code element}, or {@link Optional#empty()} if no such annotation exists. This method is a + * safer alternative to calling {@link Element#getAnnotation} as it avoids any interaction with + * annotation proxies. + */ + public static Optional getAnnotationMirror( + Element element, ClassName annotationName) { + String annotationClassName = annotationName.canonicalName(); + for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { + TypeElement annotationTypeElement = + MoreElements.asType(annotationMirror.getAnnotationType().asElement()); + if (annotationTypeElement.getQualifiedName().contentEquals(annotationClassName)) { + return Optional.of(annotationMirror); + } + } + return Optional.empty(); + } + + private MoreDaggerElements() {} +} diff --git a/java/dagger/android/processor/MoreDaggerTypes.java b/java/dagger/android/processor/MoreDaggerTypes.java new file mode 100644 index 00000000000..4bde405e1d9 --- /dev/null +++ b/java/dagger/android/processor/MoreDaggerTypes.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2021 The Dagger Authors. + * + * 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 dagger.android.processor; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.auto.common.MoreElements; +import com.squareup.javapoet.ArrayTypeName; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.TypeName; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ErrorType; +import javax.lang.model.type.NoType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.SimpleTypeVisitor8; + +// TODO(bcorso): Dedupe with dagger/internal/codegen/langmodel/DaggerTypes.java? +// TODO(bcorso): Contribute upstream to auto common? +/** Similar to auto common, but uses {@link ClassName} rather than {@link Class}. */ +final class MoreDaggerTypes { + + /** + * Returns true if the raw type underlying the given {@link TypeMirror} represents the same raw + * type as the given {@link Class} and throws an IllegalArgumentException if the {@link + * TypeMirror} does not represent a type that can be referenced by a {@link Class} + */ + public static boolean isTypeOf(final TypeName typeName, TypeMirror type) { + checkNotNull(typeName); + return type.accept(new IsTypeOf(typeName), null); + } + + private static final class IsTypeOf extends SimpleTypeVisitor8 { + private final TypeName typeName; + + IsTypeOf(TypeName typeName) { + this.typeName = typeName; + } + + @Override + protected Boolean defaultAction(TypeMirror type, Void ignored) { + throw new IllegalArgumentException(type + " cannot be represented as a Class."); + } + + @Override + public Boolean visitNoType(NoType noType, Void p) { + if (noType.getKind().equals(TypeKind.VOID)) { + return typeName.equals(TypeName.VOID); + } + throw new IllegalArgumentException(noType + " cannot be represented as a Class."); + } + + @Override + public Boolean visitError(ErrorType errorType, Void p) { + return false; + } + + @Override + public Boolean visitPrimitive(PrimitiveType type, Void p) { + switch (type.getKind()) { + case BOOLEAN: + return typeName.equals(TypeName.BOOLEAN); + case BYTE: + return typeName.equals(TypeName.BYTE); + case CHAR: + return typeName.equals(TypeName.CHAR); + case DOUBLE: + return typeName.equals(TypeName.DOUBLE); + case FLOAT: + return typeName.equals(TypeName.FLOAT); + case INT: + return typeName.equals(TypeName.INT); + case LONG: + return typeName.equals(TypeName.LONG); + case SHORT: + return typeName.equals(TypeName.SHORT); + default: + throw new IllegalArgumentException(type + " cannot be represented as a Class."); + } + } + + @Override + public Boolean visitArray(ArrayType array, Void p) { + return (typeName instanceof ArrayTypeName) + && isTypeOf(((ArrayTypeName) typeName).componentType, array.getComponentType()); + } + + @Override + public Boolean visitDeclared(DeclaredType type, Void ignored) { + TypeElement typeElement = MoreElements.asType(type.asElement()); + return (typeName instanceof ClassName) + && typeElement.getQualifiedName().contentEquals(((ClassName) typeName).canonicalName()); + } + } + + private MoreDaggerTypes() {} +} diff --git a/java/dagger/android/processor/TypeNames.java b/java/dagger/android/processor/TypeNames.java new file mode 100644 index 00000000000..3b42b459dc0 --- /dev/null +++ b/java/dagger/android/processor/TypeNames.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Dagger Authors. + * + * 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 dagger.android.processor; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.TypeName; + +// TODO(bcorso): Dedupe with dagger/internal/codegen/javapoet/TypeNames.java? +/** Common names and methods for JavaPoet {@link TypeName} and {@link ClassName} usage. */ +public final class TypeNames { + + // Core Dagger classnames + public static final ClassName BINDS = ClassName.get("dagger", "Binds"); + public static final ClassName CLASS_KEY = ClassName.get("dagger.multibindings", "ClassKey"); + public static final ClassName INTO_MAP = ClassName.get("dagger.multibindings", "IntoMap"); + public static final ClassName MAP_KEY = ClassName.get("dagger", "MapKey"); + public static final ClassName MODULE = ClassName.get("dagger", "Module"); + public static final ClassName SUBCOMPONENT = ClassName.get("dagger", "Subcomponent"); + public static final ClassName SUBCOMPONENT_FACTORY = SUBCOMPONENT.nestedClass("Factory"); + + // Dagger.android classnames + public static final ClassName ANDROID_INJECTION_KEY = + ClassName.get("dagger.android", "AndroidInjectionKey"); + public static final ClassName ANDROID_INJECTOR = + ClassName.get("dagger.android", "AndroidInjector"); + public static final ClassName DISPATCHING_ANDROID_INJECTOR = + ClassName.get("dagger.android", "DispatchingAndroidInjector"); + public static final ClassName ANDROID_INJECTOR_FACTORY = ANDROID_INJECTOR.nestedClass("Factory"); + public static final ClassName CONTRIBUTES_ANDROID_INJECTOR = + ClassName.get("dagger.android", "ContributesAndroidInjector"); + + // Other classnames + public static final ClassName PROVIDER = ClassName.get("javax.inject", "Provider"); + public static final ClassName QUALIFIER = ClassName.get("javax.inject", "Qualifier"); + public static final ClassName SCOPE = ClassName.get("javax.inject", "Scope"); + + private TypeNames() {} +} diff --git a/util/deploy-dagger.sh b/util/deploy-dagger.sh index ddf492659d6..071cd9917de 100755 --- a/util/deploy-dagger.sh +++ b/util/deploy-dagger.sh @@ -71,13 +71,6 @@ _deploy \ "" \ "" -# b/37741866 and https://github.com/google/dagger/issues/715 -_deploy \ - java/dagger/android/libandroid.jar \ - java/dagger/android/jarimpl-pom.xml \ - java/dagger/android/libandroid-src.jar \ - java/dagger/android/android-javadoc.jar - _deploy \ java/dagger/android/support/support.aar \ java/dagger/android/support/pom.xml \