• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.auto.common;
17 
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.collect.ImmutableList.toImmutableList;
20 
21 import com.google.common.base.Equivalence;
22 import com.google.common.collect.ImmutableList;
23 import java.util.List;
24 import java.util.function.Function;
25 import javax.lang.model.element.AnnotationMirror;
26 import javax.lang.model.element.AnnotationValue;
27 import javax.lang.model.element.VariableElement;
28 import javax.lang.model.type.DeclaredType;
29 import javax.lang.model.type.TypeMirror;
30 import javax.lang.model.util.SimpleAnnotationValueVisitor8;
31 
32 /**
33  * A utility class for working with {@link AnnotationValue} instances.
34  *
35  * @author Christian Gruber
36  */
37 public final class AnnotationValues {
38   private static final Equivalence<AnnotationValue> ANNOTATION_VALUE_EQUIVALENCE =
39       new Equivalence<AnnotationValue>() {
40         @Override protected boolean doEquivalent(AnnotationValue left, AnnotationValue right) {
41           return left.accept(new SimpleAnnotationValueVisitor8<Boolean, AnnotationValue>() {
42             // LHS is not an annotation or array of annotation values, so just test equality.
43             @Override protected Boolean defaultAction(Object left, AnnotationValue right) {
44               return left.equals(right.accept(
45                   new SimpleAnnotationValueVisitor8<Object, Void>() {
46                     @Override protected Object defaultAction(Object object, Void unused) {
47                       return object;
48                     }
49                   }, null));
50             }
51 
52             // LHS is an annotation mirror so test equivalence for RHS annotation mirrors
53             // and false for other types.
54             @Override public Boolean visitAnnotation(AnnotationMirror left, AnnotationValue right) {
55               return right.accept(
56                   new SimpleAnnotationValueVisitor8<Boolean, AnnotationMirror>() {
57                     @Override protected Boolean defaultAction(Object right, AnnotationMirror left) {
58                       return false; // Not an annotation mirror, so can't be equal to such.
59                     }
60                     @Override
61                     public Boolean visitAnnotation(AnnotationMirror right, AnnotationMirror left) {
62                       return AnnotationMirrors.equivalence().equivalent(left, right);
63                     }
64                   }, left);
65             }
66 
67             // LHS is a list of annotation values have to collect-test equivalences, or false
68             // for any other types.
69             @Override
70             public Boolean visitArray(List<? extends AnnotationValue> left, AnnotationValue right) {
71               return right.accept(
72                   new SimpleAnnotationValueVisitor8<Boolean, List<? extends AnnotationValue>>() {
73                     @Override protected Boolean defaultAction(
74                         Object ignored, List<? extends AnnotationValue> alsoIgnored) {
75                       return false; // Not an array, so can't be equal to such.
76                     }
77 
78                     @SuppressWarnings("unchecked") // safe covariant cast
79                     @Override public Boolean visitArray(
80                         List<? extends AnnotationValue> right ,
81                         List<? extends AnnotationValue> left) {
82                       return AnnotationValues.equivalence().pairwise().equivalent(
83                           (List<AnnotationValue>) left, (List<AnnotationValue>) right);
84                     }
85                   }, left);
86             }
87 
88             @Override
89             public Boolean visitType(TypeMirror left, AnnotationValue right) {
90               return right.accept(
91                   new SimpleAnnotationValueVisitor8<Boolean, TypeMirror>() {
92                     @Override protected Boolean defaultAction(
93                         Object ignored, TypeMirror alsoIgnored) {
94                       return false; // Not an annotation mirror, so can't be equal to such.
95                     }
96 
97                     @Override public Boolean visitType(TypeMirror right, TypeMirror left) {
98                       return MoreTypes.equivalence().equivalent(left, right);
99                     }
100                   }, left);
101             }
102           }, right);
103         }
104 
105         @Override protected int doHash(AnnotationValue value) {
106           return value.accept(new SimpleAnnotationValueVisitor8<Integer, Void>() {
107             @Override public Integer visitAnnotation(AnnotationMirror value, Void ignore) {
108               return AnnotationMirrors.equivalence().hash(value);
109             }
110 
111             @SuppressWarnings("unchecked") // safe covariant cast
112             @Override public Integer visitArray(
113                 List<? extends AnnotationValue> values, Void ignore) {
114               return AnnotationValues.equivalence().pairwise().hash((List<AnnotationValue>) values);
115             }
116 
117             @Override public Integer visitType(TypeMirror value, Void ignore) {
118               return MoreTypes.equivalence().hash(value);
119             }
120 
121             @Override protected Integer defaultAction(Object value, Void ignored) {
122               return value.hashCode();
123             }
124           }, null);
125         }
126       };
127 
128   /**
129    * Returns an {@link Equivalence} for {@link AnnotationValue} as annotation values may
130    * contain {@link AnnotationMirror} instances some of whose implementations delegate
131    * equality tests to {@link Object#equals} whereas the documentation explicitly states
132    * that instance/reference equality is not the proper test.
133    *
134    * @see AnnotationMirrors#equivalence()
135    */
equivalence()136   public static Equivalence<AnnotationValue> equivalence() {
137     return ANNOTATION_VALUE_EQUIVALENCE;
138   }
139 
140   private static class DefaultVisitor<T> extends SimpleAnnotationValueVisitor8<T, Void> {
141     final Class<T> clazz;
142 
DefaultVisitor(Class<T> clazz)143     DefaultVisitor(Class<T> clazz) {
144       this.clazz = checkNotNull(clazz);
145     }
146 
147     @Override
defaultAction(Object o, Void unused)148     public T defaultAction(Object o, Void unused) {
149       throw new IllegalArgumentException(
150           "Expected a " + clazz.getSimpleName() + ", got instead: " + o);
151     }
152   }
153 
154   private static final class TypeMirrorVisitor extends DefaultVisitor<DeclaredType> {
155     static final TypeMirrorVisitor INSTANCE = new TypeMirrorVisitor();
156 
TypeMirrorVisitor()157     TypeMirrorVisitor() {
158       super(DeclaredType.class);
159     }
160 
161     @Override
visitType(TypeMirror value, Void unused)162     public DeclaredType visitType(TypeMirror value, Void unused) {
163       return MoreTypes.asDeclared(value);
164     }
165   }
166   ;
167 
168   /**
169    * Returns the value as a class.
170    *
171    * @throws IllegalArgumentException if the value is not a class.
172    */
getTypeMirror(AnnotationValue value)173   public static DeclaredType getTypeMirror(AnnotationValue value) {
174     return TypeMirrorVisitor.INSTANCE.visit(value);
175   }
176 
177   private static final class AnnotationMirrorVisitor extends DefaultVisitor<AnnotationMirror> {
178     static final AnnotationMirrorVisitor INSTANCE = new AnnotationMirrorVisitor();
179 
AnnotationMirrorVisitor()180     AnnotationMirrorVisitor() {
181       super(AnnotationMirror.class);
182     }
183 
184     @Override
visitAnnotation(AnnotationMirror value, Void unused)185     public AnnotationMirror visitAnnotation(AnnotationMirror value, Void unused) {
186       return value;
187     }
188   }
189   ;
190 
191   /**
192    * Returns the value as an AnnotationMirror.
193    *
194    * @throws IllegalArgumentException if the value is not an annotation.
195    */
getAnnotationMirror(AnnotationValue value)196   public static AnnotationMirror getAnnotationMirror(AnnotationValue value) {
197     return AnnotationMirrorVisitor.INSTANCE.visit(value);
198   }
199 
200   private static final class EnumVisitor extends DefaultVisitor<VariableElement> {
201     static final EnumVisitor INSTANCE = new EnumVisitor();
202 
EnumVisitor()203     EnumVisitor() {
204       super(VariableElement.class);
205     }
206 
207     @Override
visitEnumConstant(VariableElement value, Void unused)208     public VariableElement visitEnumConstant(VariableElement value, Void unused) {
209       return value;
210     }
211   }
212   ;
213 
214   /**
215    * Returns the value as a VariableElement.
216    *
217    * @throws IllegalArgumentException if the value is not an enum.
218    */
getEnum(AnnotationValue value)219   public static VariableElement getEnum(AnnotationValue value) {
220     return EnumVisitor.INSTANCE.visit(value);
221   }
222 
valueOfType(AnnotationValue annotationValue, Class<T> type)223   private static <T> T valueOfType(AnnotationValue annotationValue, Class<T> type) {
224     Object value = annotationValue.getValue();
225     if (!type.isInstance(value)) {
226       throw new IllegalArgumentException(
227           "Expected " + type.getSimpleName() + ", got instead: " + value);
228     }
229     return type.cast(value);
230   }
231 
232   /**
233    * Returns the value as a string.
234    *
235    * @throws IllegalArgumentException if the value is not a string.
236    */
getString(AnnotationValue value)237   public static String getString(AnnotationValue value) {
238     return valueOfType(value, String.class);
239   }
240 
241   /**
242    * Returns the value as an int.
243    *
244    * @throws IllegalArgumentException if the value is not an int.
245    */
getInt(AnnotationValue value)246   public static int getInt(AnnotationValue value) {
247     return valueOfType(value, Integer.class);
248   }
249 
250   /**
251    * Returns the value as a long.
252    *
253    * @throws IllegalArgumentException if the value is not a long.
254    */
getLong(AnnotationValue value)255   public static long getLong(AnnotationValue value) {
256     return valueOfType(value, Long.class);
257   }
258 
259   /**
260    * Returns the value as a byte.
261    *
262    * @throws IllegalArgumentException if the value is not a byte.
263    */
getByte(AnnotationValue value)264   public static byte getByte(AnnotationValue value) {
265     return valueOfType(value, Byte.class);
266   }
267 
268   /**
269    * Returns the value as a short.
270    *
271    * @throws IllegalArgumentException if the value is not a short.
272    */
getShort(AnnotationValue value)273   public static short getShort(AnnotationValue value) {
274     return valueOfType(value, Short.class);
275   }
276 
277   /**
278    * Returns the value as a float.
279    *
280    * @throws IllegalArgumentException if the value is not a float.
281    */
getFloat(AnnotationValue value)282   public static float getFloat(AnnotationValue value) {
283     return valueOfType(value, Float.class);
284   }
285 
286   /**
287    * Returns the value as a double.
288    *
289    * @throws IllegalArgumentException if the value is not a double.
290    */
getDouble(AnnotationValue value)291   public static double getDouble(AnnotationValue value) {
292     return valueOfType(value, Double.class);
293   }
294 
295   /**
296    * Returns the value as a boolean.
297    *
298    * @throws IllegalArgumentException if the value is not a boolean.
299    */
getBoolean(AnnotationValue value)300   public static boolean getBoolean(AnnotationValue value) {
301     return valueOfType(value, Boolean.class);
302   }
303 
304   /**
305    * Returns the value as a char.
306    *
307    * @throws IllegalArgumentException if the value is not a char.
308    */
getChar(AnnotationValue value)309   public static char getChar(AnnotationValue value) {
310     return valueOfType(value, Character.class);
311   }
312 
313   private static final class ArrayVisitor<T>
314       extends SimpleAnnotationValueVisitor8<ImmutableList<T>, Void> {
315     final Function<AnnotationValue, T> visitT;
316 
ArrayVisitor(Function<AnnotationValue, T> visitT)317     ArrayVisitor(Function<AnnotationValue, T> visitT) {
318       this.visitT = checkNotNull(visitT);
319     }
320 
321     @Override
defaultAction(Object o, Void unused)322     public ImmutableList<T> defaultAction(Object o, Void unused) {
323       throw new IllegalStateException("Expected an array, got instead: " + o);
324     }
325 
326     @Override
visitArray(List<? extends AnnotationValue> values, Void unused)327     public ImmutableList<T> visitArray(List<? extends AnnotationValue> values, Void unused) {
328       return values.stream().map(visitT).collect(toImmutableList());
329     }
330   }
331 
332   private static final ArrayVisitor<DeclaredType> TYPE_MIRRORS_VISITOR =
333       new ArrayVisitor<>(AnnotationValues::getTypeMirror);
334 
335   /**
336    * Returns the value as a list of classes.
337    *
338    * @throws IllegalArgumentException if the value is not an array of classes.
339    */
getTypeMirrors(AnnotationValue value)340   public static ImmutableList<DeclaredType> getTypeMirrors(AnnotationValue value) {
341     return TYPE_MIRRORS_VISITOR.visit(value);
342   }
343 
344   private static final ArrayVisitor<AnnotationMirror> ANNOTATION_MIRRORS_VISITOR =
345       new ArrayVisitor<>(AnnotationValues::getAnnotationMirror);
346 
347   /**
348    * Returns the value as a list of annotations.
349    *
350    * @throws IllegalArgumentException if the value if not an array of annotations.
351    */
getAnnotationMirrors(AnnotationValue value)352   public static ImmutableList<AnnotationMirror> getAnnotationMirrors(AnnotationValue value) {
353     return ANNOTATION_MIRRORS_VISITOR.visit(value);
354   }
355 
356   private static final ArrayVisitor<VariableElement> ENUMS_VISITOR =
357       new ArrayVisitor<>(AnnotationValues::getEnum);
358 
359   /**
360    * Returns the value as a list of enums.
361    *
362    * @throws IllegalArgumentException if the value is not an array of enums.
363    */
getEnums(AnnotationValue value)364   public static ImmutableList<VariableElement> getEnums(AnnotationValue value) {
365     return ENUMS_VISITOR.visit(value);
366   }
367 
368   private static final ArrayVisitor<String> STRINGS_VISITOR =
369       new ArrayVisitor<>(AnnotationValues::getString);
370 
371   /**
372    * Returns the value as a list of strings.
373    *
374    * @throws IllegalArgumentException if the value is not an array of strings.
375    */
getStrings(AnnotationValue value)376   public static ImmutableList<String> getStrings(AnnotationValue value) {
377     return STRINGS_VISITOR.visit(value);
378   }
379 
380   private static final ArrayVisitor<Integer> INTS_VISITOR =
381       new ArrayVisitor<>(AnnotationValues::getInt);
382 
383   /**
384    * Returns the value as a list of integers.
385    *
386    * @throws IllegalArgumentException if the value is not an array of ints.
387    */
getInts(AnnotationValue value)388   public static ImmutableList<Integer> getInts(AnnotationValue value) {
389     return INTS_VISITOR.visit(value);
390   }
391 
392   private static final ArrayVisitor<Long> LONGS_VISITOR =
393       new ArrayVisitor<>(AnnotationValues::getLong);
394 
395   /**
396    * Returns the value as a list of longs.
397    *
398    * @throws IllegalArgumentException if the value is not an array of longs.
399    */
getLongs(AnnotationValue value)400   public static ImmutableList<Long> getLongs(AnnotationValue value) {
401     return LONGS_VISITOR.visit(value);
402   }
403 
404   private static final ArrayVisitor<Byte> BYTES_VISITOR =
405       new ArrayVisitor<>(AnnotationValues::getByte);
406 
407   /**
408    * Returns the value as a list of bytes.
409    *
410    * @throws IllegalArgumentException if the value is not an array of bytes.
411    */
getBytes(AnnotationValue value)412   public static ImmutableList<Byte> getBytes(AnnotationValue value) {
413     return BYTES_VISITOR.visit(value);
414   }
415 
416   private static final ArrayVisitor<Short> SHORTS_VISITOR =
417       new ArrayVisitor<>(AnnotationValues::getShort);
418   /**
419    * Returns the value as a list of shorts.
420    *
421    * @throws IllegalArgumentException if the value is not an array of shorts.
422    */
getShorts(AnnotationValue value)423   public static ImmutableList<Short> getShorts(AnnotationValue value) {
424     return SHORTS_VISITOR.visit(value);
425   }
426 
427   private static final ArrayVisitor<Float> FLOATS_VISITOR =
428       new ArrayVisitor<>(AnnotationValues::getFloat);
429 
430   /**
431    * Returns the value as a list of floats.
432    *
433    * @throws IllegalArgumentException if the value is not an array of floats.
434    */
getFloats(AnnotationValue value)435   public static ImmutableList<Float> getFloats(AnnotationValue value) {
436     return FLOATS_VISITOR.visit(value);
437   }
438 
439   private static final ArrayVisitor<Double> DOUBLES_VISITOR =
440       new ArrayVisitor<>(AnnotationValues::getDouble);
441 
442   /**
443    * Returns the value as a list of doubles.
444    *
445    * @throws IllegalArgumentException if the value is not an array of doubles.
446    */
getDoubles(AnnotationValue value)447   public static ImmutableList<Double> getDoubles(AnnotationValue value) {
448     return DOUBLES_VISITOR.visit(value);
449   }
450 
451   private static final ArrayVisitor<Boolean> BOOLEANS_VISITOR =
452       new ArrayVisitor<>(AnnotationValues::getBoolean);
453 
454   /**
455    * Returns the value as a list of booleans.
456    *
457    * @throws IllegalArgumentException if the value is not an array of booleans.
458    */
getBooleans(AnnotationValue value)459   public static ImmutableList<Boolean> getBooleans(AnnotationValue value) {
460     return BOOLEANS_VISITOR.visit(value);
461   }
462 
463   private static final ArrayVisitor<Character> CHARS_VISITOR =
464       new ArrayVisitor<>(AnnotationValues::getChar);
465 
466   /**
467    * Returns the value as a list of characters.
468    *
469    * @throws IllegalArgumentException if the value is not an array of chars.
470    */
getChars(AnnotationValue value)471   public static ImmutableList<Character> getChars(AnnotationValue value) {
472     return CHARS_VISITOR.visit(value);
473   }
474 
475   private static final ArrayVisitor<AnnotationValue> ANNOTATION_VALUES_VISITOR =
476       new ArrayVisitor<>(x -> x);
477 
478   /**
479    * Returns the value as a list of {@link AnnotationValue}s.
480    *
481    * @throws IllegalArgumentException if the value is not an array.
482    */
getAnnotationValues(AnnotationValue value)483   public static ImmutableList<AnnotationValue> getAnnotationValues(AnnotationValue value) {
484     return ANNOTATION_VALUES_VISITOR.visit(value);
485   }
486 
AnnotationValues()487   private AnnotationValues() {}
488 }
489 
490