001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *  http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.xbean.finder;
020
021import java.lang.annotation.Annotation;
022import java.lang.reflect.AnnotatedElement;
023import java.lang.reflect.Constructor;
024import java.lang.reflect.Method;
025
026public abstract class Parameter<E extends java.lang.reflect.Member> implements AnnotatedElement {
027    private final E declaringExecutable;
028    private final int index;
029
030    private Parameter(E declaringExecutable, int index) {
031        super();
032        if (declaringExecutable == null) {
033            throw new NullPointerException("declaringExecutable");
034        }
035        this.declaringExecutable = declaringExecutable;
036        if (index < 0) {
037            throw new IndexOutOfBoundsException(Integer.toString(index));
038        }
039        this.index = index;
040    }
041
042    public E getDeclaringExecutable() {
043        return declaringExecutable;
044    }
045
046    public int getIndex() {
047        return index;
048    }
049
050    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
051        for (Annotation annotation : getAnnotations()) {
052            if (annotationClass.equals(annotation.annotationType())) {
053                @SuppressWarnings("unchecked")
054                final T result = (T) annotation;
055                return result;
056            }
057        }
058        return null;
059    }
060
061    public Annotation[] getAnnotations() {
062        return getDeclaredAnnotations();
063    }
064
065    public Annotation[] getDeclaredAnnotations() {
066        return getParameterAnnotations()[index];
067    }
068
069    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
070        return getAnnotation(annotationClass) != null;
071    }
072
073    @Override
074    public boolean equals(Object o) {
075        if (o == this) {
076            return true;
077        }
078        if (o instanceof Parameter == false) {
079            return false;
080        }
081        Parameter<?> p = (Parameter<?>) o;
082        return declaringExecutable.equals(p.declaringExecutable) && index == p.index;
083    }
084
085    @Override
086    public int hashCode() {
087        int result = declaringExecutable.hashCode() << 4;
088        result |= index;
089        return result;
090    }
091
092    @Override
093    public String toString() {
094        return String.format("Parameter[index %s of %s]", index, declaringExecutable);
095    }
096
097    protected abstract Annotation[][] getParameterAnnotations();
098
099    public static <T> Parameter<Constructor<T>> declaredBy(Constructor<T> ctor, int index) {
100        return new Parameter<Constructor<T>>(ctor, index) {
101
102            @Override
103            protected Annotation[][] getParameterAnnotations() {
104                return getDeclaringExecutable().getParameterAnnotations();
105            }
106        };
107    }
108
109    public static Parameter<Method> declaredBy(Method method, int index) {
110        return new Parameter<Method>(method, index) {
111
112            @Override
113            protected Annotation[][] getParameterAnnotations() {
114                return getDeclaringExecutable().getParameterAnnotations();
115            }
116        };
117    }
118}