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