Copy annotations from type parameters of an `@AutoValue` class to the subclass generated by the `@Memoized` extension.
We already do this for the main `@AutoValue` subclass but until now we did not do it for this standard extension.
Also add some streamy goodness to the `MemoizedExtension` code.
RELNOTES=AutoValue now copies annotations from type parameters of an `@AutoValue` class to the subclass generated by the `@Memoized` extension.
PiperOrigin-RevId: 354373702
diff --git a/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java b/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java
index 0ca46bd..9b0c863 100644
--- a/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java
+++ b/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java
@@ -31,6 +31,7 @@
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.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static javax.lang.model.element.Modifier.ABSTRACT;
@@ -50,7 +51,6 @@
import com.google.auto.service.AutoService;
import com.google.auto.value.extension.AutoValueExtension;
import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.FormatMethod;
@@ -65,9 +65,7 @@
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeVariableName;
import java.lang.annotation.Inherited;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.processing.Messager;
@@ -80,7 +78,6 @@
import javax.lang.model.element.Modifier;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
@@ -126,13 +123,9 @@
}
private static ImmutableSet<ExecutableElement> memoizedMethods(Context context) {
- ImmutableSet.Builder<ExecutableElement> memoizedMethods = ImmutableSet.builder();
- for (ExecutableElement method : methodsIn(context.autoValueClass().getEnclosedElements())) {
- if (getAnnotationMirror(method, MEMOIZED_NAME).isPresent()) {
- memoizedMethods.add(method);
- }
- }
- return memoizedMethods.build();
+ return methodsIn(context.autoValueClass().getEnclosedElements()).stream()
+ .filter(m -> getAnnotationMirror(m, MEMOIZED_NAME).isPresent())
+ .collect(toImmutableSet());
}
static final class Generator {
@@ -164,7 +157,7 @@
classBuilder(className)
.superclass(superType())
.addAnnotations(copiedClassAnnotations(context.autoValueClass()))
- .addTypeVariables(typeVariableNames())
+ .addTypeVariables(annotatedTypeVariableNames())
.addModifiers(isFinal ? FINAL : ABSTRACT)
.addMethod(constructor());
generatedAnnotationSpec(elements, sourceVersion, MemoizeExtension.class)
@@ -193,23 +186,31 @@
}
private ImmutableList<TypeVariableName> typeVariableNames() {
- ImmutableList.Builder<TypeVariableName> typeVariableNamesBuilder = ImmutableList.builder();
- for (TypeParameterElement typeParameter : context.autoValueClass().getTypeParameters()) {
- typeVariableNamesBuilder.add(TypeVariableName.get(typeParameter));
- }
- return typeVariableNamesBuilder.build();
+ return context.autoValueClass().getTypeParameters().stream()
+ .map(TypeVariableName::get)
+ .collect(toImmutableList());
+ }
+
+ private ImmutableList<TypeVariableName> annotatedTypeVariableNames() {
+ return context.autoValueClass().getTypeParameters().stream()
+ .map(
+ p ->
+ TypeVariableName.get(p)
+ .annotated(
+ p.getAnnotationMirrors().stream()
+ .map(AnnotationSpec::get)
+ .collect(toImmutableList())))
+ .collect(toImmutableList());
}
private MethodSpec constructor() {
MethodSpec.Builder constructor = constructorBuilder();
- for (Map.Entry<String, TypeMirror> property : context.propertyTypes().entrySet()) {
- constructor.addParameter(annotatedType(property.getValue()), property.getKey() + "$");
- }
- List<String> namesWithDollars = new ArrayList<String>();
- for (String property : context.properties().keySet()) {
- namesWithDollars.add(property + "$");
- }
- constructor.addStatement("super($L)", Joiner.on(", ").join(namesWithDollars));
+ context
+ .propertyTypes()
+ .forEach((name, type) -> constructor.addParameter(annotatedType(type), name + "$"));
+ String superParams =
+ context.properties().keySet().stream().map(n -> n + "$").collect(joining(", "));
+ constructor.addStatement("super($L)", superParams);
return constructor.build();
}
@@ -478,15 +479,15 @@
return elements.overrides(method, objectMethod(methodName), context.autoValueClass());
}
- private ExecutableElement objectMethod(final String methodName) {
+ private ExecutableElement objectMethod(String methodName) {
TypeElement object = elements.getTypeElement(Object.class.getName());
- for (ExecutableElement method : methodsIn(object.getEnclosedElements())) {
- if (method.getSimpleName().contentEquals(methodName)) {
- return method;
- }
- }
- throw new IllegalArgumentException(
- String.format("No method in Object named \"%s\"", methodName));
+ return methodsIn(object.getEnclosedElements()).stream()
+ .filter(m -> m.getSimpleName().contentEquals(methodName))
+ .findFirst()
+ .orElseThrow(
+ () ->
+ new IllegalArgumentException(
+ String.format("No method in Object named \"%s\"", methodName)));
}
private boolean pullDownMethodAnnotation(AnnotationMirror annotation) {
diff --git a/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java b/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java
index 7bd61ac..0bedcf8 100644
--- a/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java
+++ b/value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java
@@ -22,6 +22,8 @@
import com.google.auto.value.AutoValue.CopyAnnotations;
import com.google.auto.value.extension.memoized.MemoizedTest.HashCodeEqualsOptimization.EqualsCounter;
import com.google.common.collect.ImmutableList;
+import com.google.errorprone.annotations.Immutable;
+import com.google.errorprone.annotations.ImmutableTypeParameter;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -482,4 +484,27 @@
ResourceUriPath.create(new TypeEdgeIterable<String, ResourceUri>() {});
assertThat(path.edges()).isNotNull();
}
+
+ @Immutable
+ @AutoValue
+ abstract static class Unchanging<@ImmutableTypeParameter T> {
+ abstract T value();
+
+ @Override
+ @Memoized
+ public abstract int hashCode();
+
+ static <@ImmutableTypeParameter T> Unchanging<T> of(T value) {
+ return new AutoValue_MemoizedTest_Unchanging<T>(value);
+ }
+ }
+
+ @Test
+ public void copiedTypeAnnotations() {
+ for (Class<?> c = Unchanging.of("foo").getClass(); c != Object.class; c = c.getSuperclass()) {
+ assertThat(c.getTypeParameters()).hasLength(1);
+ assertThat(c.getTypeParameters()[0].isAnnotationPresent(ImmutableTypeParameter.class))
+ .isTrue();
+ }
+ }
}