001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.core;
018:
019: import java.lang.reflect.Constructor;
020: import java.lang.reflect.Method;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: import org.springframework.util.Assert;
025:
026: /**
027: * Helper class that encapsulates the specification of a method parameter, i.e.
028: * a Method or Constructor plus a parameter index and a nested type index for
029: * a declared generic type. Useful as a specification object to pass along.
030: *
031: * <p>Used by {@link GenericCollectionTypeResolver},
032: * {@link org.springframework.beans.BeanWrapperImpl} and
033: * {@link org.springframework.beans.factory.support.AbstractBeanFactory}.
034: *
035: * <p>Note that this class does not depend on JDK 1.5 API artifacts, in order
036: * to remain compatible with JDK 1.3/1.4. Concrete generic type resolution
037: * via JDK 1.5 API happens in {@link GenericCollectionTypeResolver} only.
038: *
039: * @author Juergen Hoeller
040: * @author Rob Harrop
041: * @since 2.0
042: * @see GenericCollectionTypeResolver
043: */
044: public class MethodParameter {
045:
046: private Method method;
047:
048: private Constructor constructor;
049:
050: private final int parameterIndex;
051:
052: private int nestingLevel;
053:
054: /** Map from Integer level to Integer type index */
055: private Map typeIndexesPerLevel;
056:
057: /**
058: * Create a new MethodParameter for the given method, with nesting level 1.
059: * @param method the Method to specify a parameter for
060: * @param parameterIndex the index of the parameter
061: */
062: public MethodParameter(Method method, int parameterIndex) {
063: this (method, parameterIndex, 1);
064: }
065:
066: /**
067: * Create a new MethodParameter for the given method.
068: * @param method the Method to specify a parameter for
069: * @param parameterIndex the index of the parameter
070: * (-1 for the method return type; 0 for the first method parameter,
071: * 1 for the second method parameter, etc)
072: * @param nestingLevel the nesting level of the target type
073: * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
074: * nested List, whereas 2 would indicate the element of the nested List)
075: */
076: public MethodParameter(Method method, int parameterIndex,
077: int nestingLevel) {
078: Assert.notNull(method, "Method must not be null");
079: this .method = method;
080: this .parameterIndex = parameterIndex;
081: this .nestingLevel = nestingLevel;
082: }
083:
084: /**
085: * Create a new MethodParameter for the given constructor, with nesting level 1.
086: * @param constructor the Constructor to specify a parameter for
087: * @param parameterIndex the index of the parameter
088: */
089: public MethodParameter(Constructor constructor, int parameterIndex) {
090: this (constructor, parameterIndex, 1);
091: }
092:
093: /**
094: * Create a new MethodParameter for the given constructor.
095: * @param constructor the Constructor to specify a parameter for
096: * @param parameterIndex the index of the parameter
097: * @param nestingLevel the nesting level of the target type
098: * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
099: * nested List, whereas 2 would indicate the element of the nested List)
100: */
101: public MethodParameter(Constructor constructor, int parameterIndex,
102: int nestingLevel) {
103: Assert.notNull(constructor, "Constructor must not be null");
104: this .constructor = constructor;
105: this .parameterIndex = parameterIndex;
106: this .nestingLevel = nestingLevel;
107: }
108:
109: /**
110: * Return the Method held, if any.
111: * <p>Note: Either Method or Constructor is available.
112: * @return the Method, or <code>null</code> if none
113: */
114: public Method getMethod() {
115: return this .method;
116: }
117:
118: /**
119: * Return the Constructor held, if any.
120: * <p>Note: Either Method or Constructor is available.
121: * @return the Constructor, or <code>null</code> if none
122: */
123: public Constructor getConstructor() {
124: return this .constructor;
125: }
126:
127: /**
128: * Return the index of the method/constructor parameter.
129: * @return the parameter index (never negative)
130: */
131: public int getParameterIndex() {
132: return this .parameterIndex;
133: }
134:
135: /**
136: * Increase this parameter's nesting level.
137: * @see #getNestingLevel()
138: */
139: public void increaseNestingLevel() {
140: this .nestingLevel++;
141: }
142:
143: /**
144: * Decrease this parameter's nesting level.
145: * @see #getNestingLevel()
146: */
147: public void decreaseNestingLevel() {
148: getTypeIndexesPerLevel().remove(new Integer(this .nestingLevel));
149: this .nestingLevel--;
150: }
151:
152: /**
153: * Return the nesting level of the target type
154: * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
155: * nested List, whereas 2 would indicate the element of the nested List).
156: */
157: public int getNestingLevel() {
158: return this .nestingLevel;
159: }
160:
161: /**
162: * Set the type index for the current nesting level.
163: * @param typeIndex the corresponding type index
164: * (or <code>null</code> for the default type index)
165: * @see #getNestingLevel()
166: */
167: public void setTypeIndexForCurrentLevel(int typeIndex) {
168: getTypeIndexesPerLevel().put(new Integer(this .nestingLevel),
169: new Integer(typeIndex));
170: }
171:
172: /**
173: * Return the type index for the current nesting level.
174: * @return the corresponding type index, or <code>null</code>
175: * if none specified (indicating the default type index)
176: * @see #getNestingLevel()
177: */
178: public Integer getTypeIndexForCurrentLevel() {
179: return getTypeIndexForLevel(this .nestingLevel);
180: }
181:
182: /**
183: * Return the type index for the specified nesting level.
184: * @param nestingLevel the nesting level to check
185: * @return the corresponding type index, or <code>null</code>
186: * if none specified (indicating the default type index)
187: */
188: public Integer getTypeIndexForLevel(int nestingLevel) {
189: return (Integer) getTypeIndexesPerLevel().get(
190: new Integer(nestingLevel));
191: }
192:
193: /**
194: * Obtain the (lazily constructed) type-indexes-per-level Map.
195: */
196: private Map getTypeIndexesPerLevel() {
197: if (this .typeIndexesPerLevel == null) {
198: this .typeIndexesPerLevel = new HashMap(4);
199: }
200: return this .typeIndexesPerLevel;
201: }
202:
203: /**
204: * Create a new MethodParameter for the given method or constructor.
205: * <p>This is a convenience constructor for scenarios where a
206: * Method or Constructor reference is treated in a generic fashion.
207: * @param methodOrConstructor the Method or Constructor to specify a parameter for
208: * @param parameterIndex the index of the parameter
209: * @return the corresponding MethodParameter instance
210: */
211: public static MethodParameter forMethodOrConstructor(
212: Object methodOrConstructor, int parameterIndex) {
213: if (methodOrConstructor instanceof Method) {
214: return new MethodParameter((Method) methodOrConstructor,
215: parameterIndex);
216: } else if (methodOrConstructor instanceof Constructor) {
217: return new MethodParameter(
218: (Constructor) methodOrConstructor, parameterIndex);
219: } else {
220: throw new IllegalArgumentException("Given object ["
221: + methodOrConstructor
222: + "] is neither a Method nor a Constructor");
223: }
224: }
225:
226: }
|