| /* |
| * Copyright 2014 Google LLC |
| * |
| * 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 com.google.auto.common; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static com.google.common.collect.ImmutableList.toImmutableList; |
| |
| import com.google.common.base.Equivalence; |
| import com.google.common.collect.ImmutableList; |
| import java.util.List; |
| import java.util.function.Function; |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.element.AnnotationValue; |
| import javax.lang.model.element.VariableElement; |
| import javax.lang.model.type.DeclaredType; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.util.SimpleAnnotationValueVisitor8; |
| |
| /** |
| * A utility class for working with {@link AnnotationValue} instances. |
| * |
| * @author Christian Gruber |
| */ |
| public final class AnnotationValues { |
| private static final Equivalence<AnnotationValue> ANNOTATION_VALUE_EQUIVALENCE = |
| new Equivalence<AnnotationValue>() { |
| @Override protected boolean doEquivalent(AnnotationValue left, AnnotationValue right) { |
| return left.accept(new SimpleAnnotationValueVisitor8<Boolean, AnnotationValue>() { |
| // LHS is not an annotation or array of annotation values, so just test equality. |
| @Override protected Boolean defaultAction(Object left, AnnotationValue right) { |
| return left.equals(right.accept( |
| new SimpleAnnotationValueVisitor8<Object, Void>() { |
| @Override protected Object defaultAction(Object object, Void unused) { |
| return object; |
| } |
| }, null)); |
| } |
| |
| // LHS is an annotation mirror so test equivalence for RHS annotation mirrors |
| // and false for other types. |
| @Override public Boolean visitAnnotation(AnnotationMirror left, AnnotationValue right) { |
| return right.accept( |
| new SimpleAnnotationValueVisitor8<Boolean, AnnotationMirror>() { |
| @Override protected Boolean defaultAction(Object right, AnnotationMirror left) { |
| return false; // Not an annotation mirror, so can't be equal to such. |
| } |
| @Override |
| public Boolean visitAnnotation(AnnotationMirror right, AnnotationMirror left) { |
| return AnnotationMirrors.equivalence().equivalent(left, right); |
| } |
| }, left); |
| } |
| |
| // LHS is a list of annotation values have to collect-test equivalences, or false |
| // for any other types. |
| @Override |
| public Boolean visitArray(List<? extends AnnotationValue> left, AnnotationValue right) { |
| return right.accept( |
| new SimpleAnnotationValueVisitor8<Boolean, List<? extends AnnotationValue>>() { |
| @Override protected Boolean defaultAction( |
| Object ignored, List<? extends AnnotationValue> alsoIgnored) { |
| return false; // Not an array, so can't be equal to such. |
| } |
| |
| @SuppressWarnings("unchecked") // safe covariant cast |
| @Override public Boolean visitArray( |
| List<? extends AnnotationValue> right , |
| List<? extends AnnotationValue> left) { |
| return AnnotationValues.equivalence().pairwise().equivalent( |
| (List<AnnotationValue>) left, (List<AnnotationValue>) right); |
| } |
| }, left); |
| } |
| |
| @Override |
| public Boolean visitType(TypeMirror left, AnnotationValue right) { |
| return right.accept( |
| new SimpleAnnotationValueVisitor8<Boolean, TypeMirror>() { |
| @Override protected Boolean defaultAction( |
| Object ignored, TypeMirror alsoIgnored) { |
| return false; // Not an annotation mirror, so can't be equal to such. |
| } |
| |
| @Override public Boolean visitType(TypeMirror right, TypeMirror left) { |
| return MoreTypes.equivalence().equivalent(left, right); |
| } |
| }, left); |
| } |
| }, right); |
| } |
| |
| @Override protected int doHash(AnnotationValue value) { |
| return value.accept(new SimpleAnnotationValueVisitor8<Integer, Void>() { |
| @Override public Integer visitAnnotation(AnnotationMirror value, Void ignore) { |
| return AnnotationMirrors.equivalence().hash(value); |
| } |
| |
| @SuppressWarnings("unchecked") // safe covariant cast |
| @Override public Integer visitArray( |
| List<? extends AnnotationValue> values, Void ignore) { |
| return AnnotationValues.equivalence().pairwise().hash((List<AnnotationValue>) values); |
| } |
| |
| @Override public Integer visitType(TypeMirror value, Void ignore) { |
| return MoreTypes.equivalence().hash(value); |
| } |
| |
| @Override protected Integer defaultAction(Object value, Void ignored) { |
| return value.hashCode(); |
| } |
| }, null); |
| } |
| }; |
| |
| /** |
| * Returns an {@link Equivalence} for {@link AnnotationValue} as annotation values may |
| * contain {@link AnnotationMirror} instances some of whose implementations delegate |
| * equality tests to {@link Object#equals} whereas the documentation explicitly states |
| * that instance/reference equality is not the proper test. |
| * |
| * @see AnnotationMirrors#equivalence() |
| */ |
| public static Equivalence<AnnotationValue> equivalence() { |
| return ANNOTATION_VALUE_EQUIVALENCE; |
| } |
| |
| private static class DefaultVisitor<T> extends SimpleAnnotationValueVisitor8<T, Void> { |
| final Class<T> clazz; |
| |
| DefaultVisitor(Class<T> clazz) { |
| this.clazz = checkNotNull(clazz); |
| } |
| |
| @Override |
| public T defaultAction(Object o, Void unused) { |
| throw new IllegalArgumentException( |
| "Expected a " + clazz.getSimpleName() + ", got instead: " + o); |
| } |
| } |
| |
| private static final class TypeMirrorVisitor extends DefaultVisitor<DeclaredType> { |
| static final TypeMirrorVisitor INSTANCE = new TypeMirrorVisitor(); |
| |
| TypeMirrorVisitor() { |
| super(DeclaredType.class); |
| } |
| |
| @Override |
| public DeclaredType visitType(TypeMirror value, Void unused) { |
| return MoreTypes.asDeclared(value); |
| } |
| } |
| ; |
| |
| /** |
| * Returns the value as a class. |
| * |
| * @throws IllegalArgumentException if the value is not a class. |
| */ |
| public static DeclaredType getTypeMirror(AnnotationValue value) { |
| return TypeMirrorVisitor.INSTANCE.visit(value); |
| } |
| |
| private static final class AnnotationMirrorVisitor extends DefaultVisitor<AnnotationMirror> { |
| static final AnnotationMirrorVisitor INSTANCE = new AnnotationMirrorVisitor(); |
| |
| AnnotationMirrorVisitor() { |
| super(AnnotationMirror.class); |
| } |
| |
| @Override |
| public AnnotationMirror visitAnnotation(AnnotationMirror value, Void unused) { |
| return value; |
| } |
| } |
| ; |
| |
| /** |
| * Returns the value as an AnnotationMirror. |
| * |
| * @throws IllegalArgumentException if the value is not an annotation. |
| */ |
| public static AnnotationMirror getAnnotationMirror(AnnotationValue value) { |
| return AnnotationMirrorVisitor.INSTANCE.visit(value); |
| } |
| |
| private static final class EnumVisitor extends DefaultVisitor<VariableElement> { |
| static final EnumVisitor INSTANCE = new EnumVisitor(); |
| |
| EnumVisitor() { |
| super(VariableElement.class); |
| } |
| |
| @Override |
| public VariableElement visitEnumConstant(VariableElement value, Void unused) { |
| return value; |
| } |
| } |
| ; |
| |
| /** |
| * Returns the value as a VariableElement. |
| * |
| * @throws IllegalArgumentException if the value is not an enum. |
| */ |
| public static VariableElement getEnum(AnnotationValue value) { |
| return EnumVisitor.INSTANCE.visit(value); |
| } |
| |
| private static <T> T valueOfType(AnnotationValue annotationValue, Class<T> type) { |
| Object value = annotationValue.getValue(); |
| if (!type.isInstance(value)) { |
| throw new IllegalArgumentException( |
| "Expected " + type.getSimpleName() + ", got instead: " + value); |
| } |
| return type.cast(value); |
| } |
| |
| /** |
| * Returns the value as a string. |
| * |
| * @throws IllegalArgumentException if the value is not a string. |
| */ |
| public static String getString(AnnotationValue value) { |
| return valueOfType(value, String.class); |
| } |
| |
| /** |
| * Returns the value as an int. |
| * |
| * @throws IllegalArgumentException if the value is not an int. |
| */ |
| public static int getInt(AnnotationValue value) { |
| return valueOfType(value, Integer.class); |
| } |
| |
| /** |
| * Returns the value as a long. |
| * |
| * @throws IllegalArgumentException if the value is not a long. |
| */ |
| public static long getLong(AnnotationValue value) { |
| return valueOfType(value, Long.class); |
| } |
| |
| /** |
| * Returns the value as a byte. |
| * |
| * @throws IllegalArgumentException if the value is not a byte. |
| */ |
| public static byte getByte(AnnotationValue value) { |
| return valueOfType(value, Byte.class); |
| } |
| |
| /** |
| * Returns the value as a short. |
| * |
| * @throws IllegalArgumentException if the value is not a short. |
| */ |
| public static short getShort(AnnotationValue value) { |
| return valueOfType(value, Short.class); |
| } |
| |
| /** |
| * Returns the value as a float. |
| * |
| * @throws IllegalArgumentException if the value is not a float. |
| */ |
| public static float getFloat(AnnotationValue value) { |
| return valueOfType(value, Float.class); |
| } |
| |
| /** |
| * Returns the value as a double. |
| * |
| * @throws IllegalArgumentException if the value is not a double. |
| */ |
| public static double getDouble(AnnotationValue value) { |
| return valueOfType(value, Double.class); |
| } |
| |
| /** |
| * Returns the value as a boolean. |
| * |
| * @throws IllegalArgumentException if the value is not a boolean. |
| */ |
| public static boolean getBoolean(AnnotationValue value) { |
| return valueOfType(value, Boolean.class); |
| } |
| |
| /** |
| * Returns the value as a char. |
| * |
| * @throws IllegalArgumentException if the value is not a char. |
| */ |
| public static char getChar(AnnotationValue value) { |
| return valueOfType(value, Character.class); |
| } |
| |
| private static final class ArrayVisitor<T> |
| extends SimpleAnnotationValueVisitor8<ImmutableList<T>, Void> { |
| final Function<AnnotationValue, T> visitT; |
| |
| ArrayVisitor(Function<AnnotationValue, T> visitT) { |
| this.visitT = checkNotNull(visitT); |
| } |
| |
| @Override |
| public ImmutableList<T> defaultAction(Object o, Void unused) { |
| throw new IllegalStateException("Expected an array, got instead: " + o); |
| } |
| |
| @Override |
| public ImmutableList<T> visitArray(List<? extends AnnotationValue> values, Void unused) { |
| return values.stream().map(visitT).collect(toImmutableList()); |
| } |
| } |
| |
| private static final ArrayVisitor<DeclaredType> TYPE_MIRRORS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getTypeMirror); |
| |
| /** |
| * Returns the value as a list of classes. |
| * |
| * @throws IllegalArgumentException if the value is not an array of classes. |
| */ |
| public static ImmutableList<DeclaredType> getTypeMirrors(AnnotationValue value) { |
| return TYPE_MIRRORS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<AnnotationMirror> ANNOTATION_MIRRORS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getAnnotationMirror); |
| |
| /** |
| * Returns the value as a list of annotations. |
| * |
| * @throws IllegalArgumentException if the value if not an array of annotations. |
| */ |
| public static ImmutableList<AnnotationMirror> getAnnotationMirrors(AnnotationValue value) { |
| return ANNOTATION_MIRRORS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<VariableElement> ENUMS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getEnum); |
| |
| /** |
| * Returns the value as a list of enums. |
| * |
| * @throws IllegalArgumentException if the value is not an array of enums. |
| */ |
| public static ImmutableList<VariableElement> getEnums(AnnotationValue value) { |
| return ENUMS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<String> STRINGS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getString); |
| |
| /** |
| * Returns the value as a list of strings. |
| * |
| * @throws IllegalArgumentException if the value is not an array of strings. |
| */ |
| public static ImmutableList<String> getStrings(AnnotationValue value) { |
| return STRINGS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Integer> INTS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getInt); |
| |
| /** |
| * Returns the value as a list of integers. |
| * |
| * @throws IllegalArgumentException if the value is not an array of ints. |
| */ |
| public static ImmutableList<Integer> getInts(AnnotationValue value) { |
| return INTS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Long> LONGS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getLong); |
| |
| /** |
| * Returns the value as a list of longs. |
| * |
| * @throws IllegalArgumentException if the value is not an array of longs. |
| */ |
| public static ImmutableList<Long> getLongs(AnnotationValue value) { |
| return LONGS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Byte> BYTES_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getByte); |
| |
| /** |
| * Returns the value as a list of bytes. |
| * |
| * @throws IllegalArgumentException if the value is not an array of bytes. |
| */ |
| public static ImmutableList<Byte> getBytes(AnnotationValue value) { |
| return BYTES_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Short> SHORTS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getShort); |
| /** |
| * Returns the value as a list of shorts. |
| * |
| * @throws IllegalArgumentException if the value is not an array of shorts. |
| */ |
| public static ImmutableList<Short> getShorts(AnnotationValue value) { |
| return SHORTS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Float> FLOATS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getFloat); |
| |
| /** |
| * Returns the value as a list of floats. |
| * |
| * @throws IllegalArgumentException if the value is not an array of floats. |
| */ |
| public static ImmutableList<Float> getFloats(AnnotationValue value) { |
| return FLOATS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Double> DOUBLES_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getDouble); |
| |
| /** |
| * Returns the value as a list of doubles. |
| * |
| * @throws IllegalArgumentException if the value is not an array of doubles. |
| */ |
| public static ImmutableList<Double> getDoubles(AnnotationValue value) { |
| return DOUBLES_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Boolean> BOOLEANS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getBoolean); |
| |
| /** |
| * Returns the value as a list of booleans. |
| * |
| * @throws IllegalArgumentException if the value is not an array of booleans. |
| */ |
| public static ImmutableList<Boolean> getBooleans(AnnotationValue value) { |
| return BOOLEANS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<Character> CHARS_VISITOR = |
| new ArrayVisitor<>(AnnotationValues::getChar); |
| |
| /** |
| * Returns the value as a list of characters. |
| * |
| * @throws IllegalArgumentException if the value is not an array of chars. |
| */ |
| public static ImmutableList<Character> getChars(AnnotationValue value) { |
| return CHARS_VISITOR.visit(value); |
| } |
| |
| private static final ArrayVisitor<AnnotationValue> ANNOTATION_VALUES_VISITOR = |
| new ArrayVisitor<>(x -> x); |
| |
| /** |
| * Returns the value as a list of {@link AnnotationValue}s. |
| * |
| * @throws IllegalArgumentException if the value is not an array. |
| */ |
| public static ImmutableList<AnnotationValue> getAnnotationValues(AnnotationValue value) { |
| return ANNOTATION_VALUES_VISITOR.visit(value); |
| } |
| |
| private AnnotationValues() {} |
| } |
| |