001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 The ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.reflect;
018
019import java.lang.annotation.Annotation;
020import java.lang.reflect.Method;
021import java.lang.reflect.Type;
022
023/**
024 * This class models formal method parameters to allow convenient reflective
025 * access as the Java Reflection API does not model them explicitly.
026 * 
027 * Instances of this class can be obtained via
028 * {@link ReflectionUtils#getFormalParameters(Method)}.
029 * 
030 * @author Florian Deissenboeck
031 * 
032 * @see ReflectionUtils#getFormalParameters(Method)
033 * @see ReflectionUtils#invoke(Method, Object, java.util.Map)
034 */
035public final class FormalParameter {
036
037        /** The method the parameter belongs to. */
038        private final Method method;
039
040        /**
041         * The position of the formal parameter within the methods parameter list.
042         */
043        private final int position;
044
045        /**
046         * Create new formal parameter. This is called from
047         * {@link ReflectionUtils#getFormalParameters(Method)}.
048         */
049        /* package */ FormalParameter(Method method, int position) {
050                this.method = method;
051                this.position = position;
052        }
053
054        /** Get the method that declares this formal parameter. */
055        public Method getMethod() {
056                return method;
057        }
058
059        /**
060         * Get parameter type.
061         */
062        public Class<?> getType() {
063                return method.getParameterTypes()[position];
064        }
065
066        /**
067         * Get generic parameter type.
068         */
069        public Type getGenericType() {
070                return method.getGenericParameterTypes()[position];
071        }
072
073        /**
074         * Get parameter annotations.
075         */
076        public Annotation[] getAnnotations() {
077                Annotation[][] annotations = method.getParameterAnnotations();
078                return annotations[position];
079        }
080
081        /**
082         * Get the position of the formal parameter within the methods parameter
083         * list.
084         */
085        public int getPosition() {
086                return position;
087        }
088
089        /**
090         * The hashcode is computed as the exclusive-or of the method's hashcode and
091         * (position+1).
092         */
093        @Override
094        public int hashCode() {
095                return method.hashCode() ^ (position + 1);
096        }
097
098        /**
099         * Returns this element's annotation for the specified type if such an
100         * annotation is present, else <code>null</code>.
101         */
102        @SuppressWarnings("unchecked")
103        public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
104                if (annotationClass == null) {
105                        throw new NullPointerException();
106                }
107
108                for (Annotation annotation : getAnnotations()) {
109                        if (annotation.annotationType().equals(annotationClass)) {
110                                return (A) annotation;
111                        }
112                }
113
114                return null;
115        }
116
117        /**
118         * Returns <code>true</code> if an annotation of the specified type is
119         * defined for this formal parameter.
120         */
121        public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
122                if (annotationClass == null) {
123                        throw new NullPointerException();
124                }
125
126                return getAnnotation(annotationClass) != null;
127        }
128
129        /**
130         * Two formal parameters are equal if their declaring methods and their
131         * position within the formal parameter list are equal.
132         */
133        @Override
134        public boolean equals(Object object) {
135                if (object == null || !(object instanceof FormalParameter)) {
136                        return false;
137                }
138
139                if (object == this) {
140                        return true;
141                }
142
143                FormalParameter otherFormalParameter = (FormalParameter) object;
144
145                return method.equals(otherFormalParameter.method) && (position == otherFormalParameter.position);
146        }
147
148        /**
149         * Returns method name, position and type.
150         */
151        @Override
152        public String toString() {
153                return "Formal parameter #" + position + " of method '" + method.getName() + "' (type: '" + getType().getName()
154                                + "')";
155        }
156}