Skip to content

Commit a3f218d

Browse files
java-team-github-botGoogle Java Core Libraries
authored andcommitted
Make it easier to support @CopyAnnotations in AutoValueExtensions
AutoValueExtension.Context now provides methods to lookup the annotations that should be copied to the class or methods. RELNOTES=Make it easier to support @CopyAnnotations in AutoValueExtensions PiperOrigin-RevId: 495638296
1 parent 0436f53 commit a3f218d

File tree

7 files changed

+188
-353
lines changed

7 files changed

+188
-353
lines changed

value/src/main/java/com/google/auto/value/extension/AutoValueExtension.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
*/
1616
package com.google.auto.value.extension;
1717

18+
import com.google.common.collect.ImmutableList;
1819
import com.google.common.collect.ImmutableSet;
20+
import java.util.List;
1921
import java.util.Map;
2022
import java.util.Optional;
2123
import java.util.Set;
2224
import javax.annotation.processing.ProcessingEnvironment;
2325
import javax.annotation.processing.Processor;
2426
import javax.annotation.processing.SupportedOptions;
27+
import javax.lang.model.element.AnnotationMirror;
2528
import javax.lang.model.element.ExecutableElement;
2629
import javax.lang.model.element.TypeElement;
2730
import javax.lang.model.type.TypeMirror;
@@ -156,6 +159,32 @@ default Map<String, TypeMirror> propertyTypes() {
156159
*/
157160
Set<ExecutableElement> abstractMethods();
158161

162+
/**
163+
* Returns the complete list of annotations defined on the {@code classToCopyFrom} that should
164+
* be added to any generated subclass. Only annotations visible to the {@code @AutoValue} will
165+
* be present. See {@link com.google.auto.value.AutoValue.CopyAnnotations
166+
* AutoValue.CopyAnnotations} for more information.
167+
*
168+
* <p>The default implementation of this method returns an empty list for compatibility with
169+
* extensions which may have implemented this interface themselves.
170+
*/
171+
default List<AnnotationMirror> classAnnotationsToCopy(TypeElement classToCopyFrom) {
172+
return ImmutableList.of();
173+
}
174+
175+
/**
176+
* Returns the complete list of annotations defined on the {@code method} that should be applied
177+
* to any override of that method. Only annotations visible to the {@code @AutoValue} will be
178+
* present. See {@link com.google.auto.value.AutoValue.CopyAnnotations
179+
* AutoValue.CopyAnnotations} for more information.
180+
*
181+
* <p>The default implementation of this method returns an empty list for compatibility with
182+
* extensions which may have implemented this interface themselves.
183+
*/
184+
default List<AnnotationMirror> methodAnnotationsToCopy(ExecutableElement method) {
185+
return ImmutableList.of();
186+
}
187+
159188
/**
160189
* Returns a representation of the {@code Builder} associated with the {@code @AutoValue} class,
161190
* if there is one.

value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java

Lines changed: 5 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
*/
1616
package com.google.auto.value.extension.memoized.processor;
1717

18-
import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
1918
import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
20-
import static com.google.auto.common.MoreElements.getPackage;
21-
import static com.google.auto.common.MoreElements.isAnnotationPresent;
2219
import static com.google.auto.common.MoreStreams.toImmutableList;
2320
import static com.google.auto.common.MoreStreams.toImmutableSet;
2421
import static com.google.auto.value.extension.memoized.processor.ClassNames.MEMOIZED_NAME;
@@ -27,13 +24,11 @@
2724
import static com.google.common.base.Predicates.not;
2825
import static com.google.common.collect.Iterables.filter;
2926
import static com.google.common.collect.Iterables.getOnlyElement;
30-
import static com.google.common.collect.Sets.union;
3127
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
3228
import static com.squareup.javapoet.MethodSpec.methodBuilder;
3329
import static com.squareup.javapoet.TypeSpec.classBuilder;
3430
import static java.util.stream.Collectors.joining;
3531
import static java.util.stream.Collectors.toList;
36-
import static java.util.stream.Collectors.toSet;
3732
import static javax.lang.model.element.Modifier.ABSTRACT;
3833
import static javax.lang.model.element.Modifier.FINAL;
3934
import static javax.lang.model.element.Modifier.PRIVATE;
@@ -46,11 +41,8 @@
4641
import static javax.tools.Diagnostic.Kind.ERROR;
4742

4843
import com.google.auto.common.MoreElements;
49-
import com.google.auto.common.MoreTypes;
50-
import com.google.auto.common.Visibility;
5144
import com.google.auto.service.AutoService;
5245
import com.google.auto.value.extension.AutoValueExtension;
53-
import com.google.common.base.Equivalence.Wrapper;
5446
import com.google.common.collect.ImmutableList;
5547
import com.google.common.collect.ImmutableSet;
5648
import com.google.errorprone.annotations.FormatMethod;
@@ -64,19 +56,14 @@
6456
import com.squareup.javapoet.TypeName;
6557
import com.squareup.javapoet.TypeSpec;
6658
import com.squareup.javapoet.TypeVariableName;
67-
import java.lang.annotation.Inherited;
6859
import java.util.List;
6960
import java.util.Optional;
70-
import java.util.Set;
7161
import javax.annotation.processing.Messager;
7262
import javax.annotation.processing.ProcessingEnvironment;
7363
import javax.lang.model.SourceVersion;
7464
import javax.lang.model.element.AnnotationMirror;
75-
import javax.lang.model.element.AnnotationValue;
76-
import javax.lang.model.element.Element;
7765
import javax.lang.model.element.ExecutableElement;
7866
import javax.lang.model.element.Modifier;
79-
import javax.lang.model.element.QualifiedNameable;
8067
import javax.lang.model.element.TypeElement;
8168
import javax.lang.model.type.TypeMirror;
8269
import javax.lang.model.util.Elements;
@@ -92,11 +79,6 @@ public final class MemoizeExtension extends AutoValueExtension {
9279
private static final ImmutableSet<String> DO_NOT_PULL_DOWN_ANNOTATIONS =
9380
ImmutableSet.of(Override.class.getCanonicalName(), MEMOIZED_NAME);
9481

95-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
96-
private static final String AUTO_VALUE_PACKAGE_NAME = "com.google.auto.value.";
97-
private static final String AUTO_VALUE_NAME = AUTO_VALUE_PACKAGE_NAME + "AutoValue";
98-
private static final String COPY_ANNOTATIONS_NAME = AUTO_VALUE_NAME + ".CopyAnnotations";
99-
10082
// Maven is configured to shade (rewrite) com.google packages to prevent dependency conflicts.
10183
// Split up the package here with a call to concat to prevent Maven from finding and rewriting it,
10284
// so that this will be able to find the LazyInit annotation if it's on the classpath.
@@ -156,7 +138,10 @@ String generate() {
156138
TypeSpec.Builder generated =
157139
classBuilder(className)
158140
.superclass(superType())
159-
.addAnnotations(copiedClassAnnotations(context.autoValueClass()))
141+
.addAnnotations(
142+
context.classAnnotationsToCopy(context.autoValueClass()).stream()
143+
.map(AnnotationSpec::get)
144+
.collect(toImmutableList()))
160145
.addTypeVariables(annotatedTypeVariableNames())
161146
.addModifiers(isFinal ? FINAL : ABSTRACT)
162147
.addMethod(constructor());
@@ -252,146 +237,6 @@ private MethodSpec equalsWithHashCodeCheck() {
252237
.build();
253238
}
254239

255-
// LINT.IfChange
256-
/**
257-
* True if the given class name is in the com.google.auto.value package or a subpackage. False
258-
* if the class name contains {@code Test}, since many AutoValue tests under
259-
* com.google.auto.value define their own annotations.
260-
*/
261-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
262-
private boolean isInAutoValuePackage(String className) {
263-
return className.startsWith(AUTO_VALUE_PACKAGE_NAME) && !className.contains("Test");
264-
}
265-
266-
/**
267-
* Returns the fully-qualified name of an annotation-mirror, e.g.
268-
* "com.google.auto.value.AutoValue".
269-
*/
270-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
271-
private static String getAnnotationFqName(AnnotationMirror annotation) {
272-
return ((QualifiedNameable) annotation.getAnnotationType().asElement())
273-
.getQualifiedName()
274-
.toString();
275-
}
276-
277-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
278-
private boolean annotationVisibleFrom(AnnotationMirror annotation, Element from) {
279-
Element annotationElement = annotation.getAnnotationType().asElement();
280-
Visibility visibility = Visibility.effectiveVisibilityOfElement(annotationElement);
281-
switch (visibility) {
282-
case PUBLIC:
283-
return true;
284-
case PROTECTED:
285-
// If the annotation is protected, it must be inside another class, call it C. If our
286-
// @AutoValue class is Foo then, for the annotation to be visible, either Foo must be in
287-
// the same package as C or Foo must be a subclass of C. If the annotation is visible from
288-
// Foo then it is also visible from our generated subclass AutoValue_Foo.
289-
// The protected case only applies to method annotations. An annotation on the
290-
// AutoValue_Foo class itself can't be protected, even if AutoValue_Foo ultimately
291-
// inherits from the class that defines the annotation. The JLS says "Access is permitted
292-
// only within the body of a subclass":
293-
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.1
294-
// AutoValue_Foo is a top-level class, so an annotation on it cannot be in the body of a
295-
// subclass of anything.
296-
return getPackage(annotationElement).equals(getPackage(from))
297-
|| types.isSubtype(from.asType(), annotationElement.getEnclosingElement().asType());
298-
case DEFAULT:
299-
return getPackage(annotationElement).equals(getPackage(from));
300-
default:
301-
return false;
302-
}
303-
}
304-
305-
/** Implements the semantics of {@code AutoValue.CopyAnnotations}; see its javadoc. */
306-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
307-
private ImmutableList<AnnotationMirror> annotationsToCopy(
308-
Element autoValueType, Element typeOrMethod, Set<String> excludedAnnotations) {
309-
ImmutableList.Builder<AnnotationMirror> result = ImmutableList.builder();
310-
for (AnnotationMirror annotation : typeOrMethod.getAnnotationMirrors()) {
311-
String annotationFqName = getAnnotationFqName(annotation);
312-
// To be included, the annotation should not be in com.google.auto.value,
313-
// and it should not be in the excludedAnnotations set.
314-
if (!isInAutoValuePackage(annotationFqName)
315-
&& !excludedAnnotations.contains(annotationFqName)
316-
&& annotationVisibleFrom(annotation, autoValueType)) {
317-
result.add(annotation);
318-
}
319-
}
320-
321-
return result.build();
322-
}
323-
324-
/** Implements the semantics of {@code AutoValue.CopyAnnotations}; see its javadoc. */
325-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
326-
private ImmutableList<AnnotationSpec> copyAnnotations(
327-
Element autoValueType, Element typeOrMethod, Set<String> excludedAnnotations) {
328-
ImmutableList<AnnotationMirror> annotationsToCopy =
329-
annotationsToCopy(autoValueType, typeOrMethod, excludedAnnotations);
330-
return annotationsToCopy.stream().map(AnnotationSpec::get).collect(toImmutableList());
331-
}
332-
333-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
334-
private static boolean hasAnnotationMirror(Element element, String annotationName) {
335-
return getAnnotationMirror(element, annotationName).isPresent();
336-
}
337-
338-
/**
339-
* Returns the contents of the {@code AutoValue.CopyAnnotations.exclude} element, as a set of
340-
* {@code TypeMirror} where each type is an annotation type.
341-
*/
342-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
343-
private ImmutableSet<TypeMirror> getExcludedAnnotationTypes(Element element) {
344-
Optional<AnnotationMirror> maybeAnnotation =
345-
getAnnotationMirror(element, COPY_ANNOTATIONS_NAME);
346-
if (!maybeAnnotation.isPresent()) {
347-
return ImmutableSet.of();
348-
}
349-
350-
@SuppressWarnings("unchecked")
351-
List<AnnotationValue> excludedClasses =
352-
(List<AnnotationValue>) getAnnotationValue(maybeAnnotation.get(), "exclude").getValue();
353-
return excludedClasses.stream()
354-
.map(
355-
annotationValue ->
356-
MoreTypes.equivalence().wrap((TypeMirror) annotationValue.getValue()))
357-
// TODO(b/122509249): Move TypeMirrorSet to common package instead of doing this.
358-
.distinct()
359-
.map(Wrapper::get)
360-
.collect(toImmutableSet());
361-
}
362-
363-
/**
364-
* Returns the contents of the {@code AutoValue.CopyAnnotations.exclude} element, as a set of
365-
* strings that are fully-qualified class names.
366-
*/
367-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
368-
private Set<String> getExcludedAnnotationClassNames(Element element) {
369-
return getExcludedAnnotationTypes(element).stream()
370-
.map(MoreTypes::asTypeElement)
371-
.map(typeElement -> typeElement.getQualifiedName().toString())
372-
.collect(toSet());
373-
}
374-
375-
// TODO(b/122509249): Move code copied from com.google.auto.value.processor to auto-common.
376-
private static Set<String> getAnnotationsMarkedWithInherited(Element element) {
377-
return element.getAnnotationMirrors().stream()
378-
.filter(a -> isAnnotationPresent(a.getAnnotationType().asElement(), Inherited.class))
379-
.map(Generator::getAnnotationFqName)
380-
.collect(toSet());
381-
}
382-
383-
private ImmutableList<AnnotationSpec> copiedClassAnnotations(TypeElement type) {
384-
// Only copy annotations from a class if it has @AutoValue.CopyAnnotations.
385-
if (hasAnnotationMirror(type, COPY_ANNOTATIONS_NAME)) {
386-
Set<String> excludedAnnotations =
387-
union(getExcludedAnnotationClassNames(type), getAnnotationsMarkedWithInherited(type));
388-
389-
return copyAnnotations(type, type, excludedAnnotations);
390-
} else {
391-
return ImmutableList.of();
392-
}
393-
}
394-
395240
/**
396241
* Determines the required fields and overriding method for a {@link
397242
* com.google.auto.value.extension.memoized.Memoized @Memoized} method.
@@ -416,7 +261,7 @@ private final class MethodOverrider {
416261
.addExceptions(
417262
method.getThrownTypes().stream().map(TypeName::get).collect(toList()))
418263
.addModifiers(filter(method.getModifiers(), not(equalTo(ABSTRACT))));
419-
for (AnnotationMirror annotation : method.getAnnotationMirrors()) {
264+
for (AnnotationMirror annotation : context.methodAnnotationsToCopy(method)) {
420265
AnnotationSpec annotationSpec = AnnotationSpec.get(annotation);
421266
if (pullDownMethodAnnotation(annotation)) {
422267
override.addAnnotation(annotationSpec);

0 commit comments

Comments
 (0)