001/*
002 * Copyright (C) 2012 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.reflect;
016
017import static com.google.common.base.Preconditions.checkNotNull;
018import static java.util.Objects.requireNonNull;
019
020import com.google.common.collect.FluentIterable;
021import com.google.common.collect.ImmutableList;
022import java.lang.annotation.Annotation;
023import java.lang.reflect.AnnotatedElement;
024import java.lang.reflect.AnnotatedType;
025import javax.annotation.CheckForNull;
026import org.checkerframework.checker.nullness.qual.Nullable;
027
028/**
029 * Represents a method or constructor parameter.
030 *
031 * @author Ben Yu
032 * @since 14.0
033 */
034public final class Parameter implements AnnotatedElement {
035
036  private final Invokable<?, ?> declaration;
037  private final int position;
038  private final TypeToken<?> type;
039  private final ImmutableList<Annotation> annotations;
040
041  /**
042   * An {@code AnnotatedType} instance, or {@code null} under Android VMs (possible only when using
043   * the Android flavor of Guava). The field is declared with a type of {@code Object} to avoid
044   * compatibility problems on Android VMs. The corresponding accessor method, however, can have the
045   * more specific return type as long as users are careful to guard calls to it with version checks
046   * or reflection: Android VMs ignore the types of elements that aren't used.
047   */
048  private final @Nullable Object annotatedType;
049
050  Parameter(
051      Invokable<?, ?> declaration,
052      int position,
053      TypeToken<?> type,
054      Annotation[] annotations,
055      @Nullable Object annotatedType) {
056    this.declaration = declaration;
057    this.position = position;
058    this.type = type;
059    this.annotations = ImmutableList.copyOf(annotations);
060    this.annotatedType = annotatedType;
061  }
062
063  /** Returns the type of the parameter. */
064  public TypeToken<?> getType() {
065    return type;
066  }
067
068  /** Returns the {@link Invokable} that declares this parameter. */
069  public Invokable<?, ?> getDeclaringInvokable() {
070    return declaration;
071  }
072
073  @Override
074  public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
075    return getAnnotation(annotationType) != null;
076  }
077
078  @Override
079  @CheckForNull
080  public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
081    checkNotNull(annotationType);
082    for (Annotation annotation : annotations) {
083      if (annotationType.isInstance(annotation)) {
084        return annotationType.cast(annotation);
085      }
086    }
087    return null;
088  }
089
090  @Override
091  public Annotation[] getAnnotations() {
092    return getDeclaredAnnotations();
093  }
094
095  /**
096   * @since 18.0
097   */
098  @Override
099  public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
100    return getDeclaredAnnotationsByType(annotationType);
101  }
102
103  /** @since 18.0 */
104  @Override
105  public Annotation[] getDeclaredAnnotations() {
106    return annotations.toArray(new Annotation[0]);
107  }
108
109  /**
110   * @since 18.0
111   */
112  @Override
113  @CheckForNull
114  public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationType) {
115    checkNotNull(annotationType);
116    return FluentIterable.from(annotations).filter(annotationType).first().orNull();
117  }
118
119  /**
120   * @since 18.0
121   */
122  @Override
123  public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationType) {
124    @Nullable
125    A[] result = FluentIterable.from(annotations).filter(annotationType).toArray(annotationType);
126    @SuppressWarnings("nullness") // safe because the input list contains no nulls
127    A[] cast = (A[]) result;
128    return cast;
129  }
130
131  /**
132   * Returns the {@link AnnotatedType} of the parameter.
133   *
134   * @since 25.1 for guava-jre
135   */
136  @SuppressWarnings("Java7ApiChecker")
137  public AnnotatedType getAnnotatedType() {
138    return requireNonNull((AnnotatedType) annotatedType);
139  }
140
141  @Override
142  public boolean equals(@CheckForNull Object obj) {
143    if (obj instanceof Parameter) {
144      Parameter that = (Parameter) obj;
145      return position == that.position && declaration.equals(that.declaration);
146    }
147    return false;
148  }
149
150  @Override
151  public int hashCode() {
152    return position;
153  }
154
155  @Override
156  public String toString() {
157    return type + " arg" + position;
158  }
159}