aboutsummaryrefslogtreecommitdiff
path: root/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
diff options
context:
space:
mode:
Diffstat (limited to 'factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java')
-rw-r--r--factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java103
1 files changed, 66 insertions, 37 deletions
diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
index 53b99cb5..b7f9c3e4 100644
--- a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
+++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java
@@ -19,19 +19,22 @@ import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotatio
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.FluentIterable;
+import com.google.auto.common.AnnotationMirrors;
+import com.google.auto.common.AnnotationValues;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+import com.google.common.collect.Streams;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -43,13 +46,19 @@ import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import java.io.IOException;
+import java.lang.annotation.Target;
import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
@@ -71,14 +80,10 @@ final class FactoryWriter {
this.factoriesBeingCreated = factoriesBeingCreated;
}
- private static final Joiner ARGUMENT_JOINER = Joiner.on(", ");
-
- void writeFactory(FactoryDescriptor descriptor)
- throws IOException {
+ void writeFactory(FactoryDescriptor descriptor) throws IOException {
String factoryName = descriptor.name().className();
TypeSpec.Builder factory =
- classBuilder(factoryName)
- .addOriginatingElement(descriptor.declaration().targetType());
+ classBuilder(factoryName).addOriginatingElement(descriptor.declaration().targetType());
generatedAnnotationSpec(
elements,
sourceVersion,
@@ -145,7 +150,7 @@ final class FactoryWriter {
ImmutableSet<TypeVariableName> factoryTypeVariables) {
for (FactoryMethodDescriptor methodDescriptor : descriptor.methodDescriptors()) {
MethodSpec.Builder method =
- MethodSpec.methodBuilder(methodDescriptor.name())
+ methodBuilder(methodDescriptor.name())
.addTypeVariables(getMethodTypeVariables(methodDescriptor, factoryTypeVariables))
.returns(TypeName.get(methodDescriptor.returnType()))
.varargs(methodDescriptor.isVarArgs());
@@ -155,6 +160,8 @@ final class FactoryWriter {
if (methodDescriptor.publicMethod()) {
method.addModifiers(PUBLIC);
}
+ method.addExceptions(
+ methodDescriptor.exceptions().stream().map(TypeName::get).collect(toList()));
CodeBlock.Builder args = CodeBlock.builder();
method.addParameters(parameters(methodDescriptor.passedParameters()));
Iterator<Parameter> parameters = methodDescriptor.creationParameters().iterator();
@@ -168,7 +175,7 @@ final class FactoryWriter {
checkNotNull = false;
}
} else {
- ProviderField provider = descriptor.providers().get(parameter.key());
+ ProviderField provider = requireNonNull(descriptor.providers().get(parameter.key()));
argument = CodeBlock.of(provider.name());
if (parameter.isProvider()) {
// Providers are checked for nullness in the Factory's constructor.
@@ -190,8 +197,7 @@ final class FactoryWriter {
}
}
- private void addImplementationMethods(
- TypeSpec.Builder factory, FactoryDescriptor descriptor) {
+ private void addImplementationMethods(TypeSpec.Builder factory, FactoryDescriptor descriptor) {
for (ImplementationMethodDescriptor methodDescriptor :
descriptor.implementationMethodDescriptors()) {
MethodSpec.Builder implementationMethod =
@@ -202,18 +208,12 @@ final class FactoryWriter {
if (methodDescriptor.publicMethod()) {
implementationMethod.addModifiers(PUBLIC);
}
+ implementationMethod.addExceptions(
+ methodDescriptor.exceptions().stream().map(TypeName::get).collect(toList()));
implementationMethod.addParameters(parameters(methodDescriptor.passedParameters()));
implementationMethod.addStatement(
"return create($L)",
- FluentIterable.from(methodDescriptor.passedParameters())
- .transform(
- new Function<Parameter, String>() {
- @Override
- public String apply(Parameter parameter) {
- return parameter.name();
- }
- })
- .join(ARGUMENT_JOINER));
+ methodDescriptor.passedParameters().stream().map(Parameter::name).collect(joining(", ")));
factory.addMethod(implementationMethod.build());
}
}
@@ -225,17 +225,43 @@ final class FactoryWriter {
private ImmutableList<ParameterSpec> parameters(Iterable<Parameter> parameters) {
ImmutableList.Builder<ParameterSpec> builder = ImmutableList.builder();
for (Parameter parameter : parameters) {
- ParameterSpec.Builder parameterBuilder =
- ParameterSpec.builder(resolveTypeName(parameter.type().get()), parameter.name());
- for (AnnotationMirror annotation :
- Iterables.concat(parameter.nullable().asSet(), parameter.key().qualifier().asSet())) {
- parameterBuilder.addAnnotation(AnnotationSpec.get(annotation));
- }
- builder.add(parameterBuilder.build());
+ TypeName type = resolveTypeName(parameter.type().get());
+ // Remove TYPE_USE annotations, since resolveTypeName will already have included those in
+ // the TypeName it returns.
+ List<AnnotationSpec> annotations =
+ Stream.of(parameter.nullable(), parameter.key().qualifier())
+ .flatMap(Streams::stream)
+ .filter(a -> !isTypeUseAnnotation(a))
+ .map(AnnotationSpec::get)
+ .collect(toList());
+ ParameterSpec parameterSpec =
+ ParameterSpec.builder(type, parameter.name()).addAnnotations(annotations).build();
+ builder.add(parameterSpec);
}
return builder.build();
}
+ private static boolean isTypeUseAnnotation(AnnotationMirror mirror) {
+ Element annotationElement = mirror.getAnnotationType().asElement();
+ // This is basically equivalent to:
+ // Target target = annotationElement.getAnnotation(Target.class);
+ // return target != null
+ // && Arrays.asList(annotationElement.getAnnotation(Target.class)).contains(TYPE_USE);
+ // but that might blow up if the annotation is being compiled at the same time and has an
+ // undefined identifier in its @Target values. The rigmarole below avoids that problem.
+ Optional<AnnotationMirror> maybeTargetMirror =
+ Mirrors.getAnnotationMirror(annotationElement, Target.class);
+ return maybeTargetMirror
+ .map(
+ targetMirror ->
+ AnnotationValues.getEnums(
+ AnnotationMirrors.getAnnotationValue(targetMirror, "value"))
+ .stream()
+ .map(VariableElement::getSimpleName)
+ .anyMatch(name -> name.contentEquals("TYPE_USE")))
+ .orElse(false);
+ }
+
private static void addCheckNotNullMethod(
TypeSpec.Builder factory, FactoryDescriptor descriptor) {
if (shouldGenerateCheckNotNull(descriptor)) {
@@ -290,17 +316,20 @@ final class FactoryWriter {
* {@code @AutoFactory class Foo} has a constructor parameter of type {@code BarFactory} and
* {@code @AutoFactory class Bar} has a constructor parameter of type {@code FooFactory}. We did
* in fact find instances of this in Google's source base.
+ *
+ * <p>If the type has type annotations then include those in the returned {@link TypeName}.
*/
private TypeName resolveTypeName(TypeMirror type) {
- if (type.getKind() != TypeKind.ERROR) {
- return TypeName.get(type);
- }
- ImmutableSet<PackageAndClass> factoryNames = factoriesBeingCreated.get(type.toString());
- if (factoryNames.size() == 1) {
- PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames);
- return ClassName.get(packageAndClass.packageName(), packageAndClass.className());
+ TypeName typeName = TypeName.get(type);
+ if (type.getKind() == TypeKind.ERROR) {
+ ImmutableSet<PackageAndClass> factoryNames = factoriesBeingCreated.get(type.toString());
+ if (factoryNames.size() == 1) {
+ PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames);
+ typeName = ClassName.get(packageAndClass.packageName(), packageAndClass.className());
+ }
}
- return TypeName.get(type);
+ return typeName.annotated(
+ type.getAnnotationMirrors().stream().map(AnnotationSpec::get).collect(toList()));
}
private static ImmutableSet<TypeVariableName> getFactoryTypeVariables(