/* * Copyright 2008 biaoping.yin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.frameworkset.util; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.frameworkset.util.ClassUtil.Var; import org.frameworkset.util.annotations.MapKey; import org.frameworkset.util.annotations.Scope; import org.frameworkset.util.annotations.wraper.AttributeWraper; import org.frameworkset.util.annotations.wraper.CookieValueWraper; import org.frameworkset.util.annotations.wraper.PagerParamWraper; import org.frameworkset.util.annotations.wraper.PathVariableWraper; import org.frameworkset.util.annotations.wraper.RequestBodyWraper; import org.frameworkset.util.annotations.wraper.RequestHeaderWraper; import org.frameworkset.util.annotations.wraper.RequestParamWraper; import com.frameworkset.util.EditorInf; /** * <p> * Title: MethodParameter.java * </p> * <p> * Description: * </p> * <p> * bboss workgroup * </p> * <p> * Copyright (c) 2007 * </p> * * @Date 2010-10-13 下午08:58:46 * @author biaoping.yin * @version 1.0 */ public class MethodParameter { private static final Method methodParameterAnnotationsMethod = ClassUtils .getMethodIfAvailable(Method.class, "getParameterAnnotations", new Class[0]); private static final Method constructorParameterAnnotationsMethod = ClassUtils .getMethodIfAvailable(Constructor.class, "getParameterAnnotations", new Class[0]); private Method method; private EditorInf editor; private Constructor constructor; private final int parameterIndex; private Class parameterType; private Object[] parameterAnnotations; private ParameterNameDiscoverer parameterNameDiscoverer; private boolean isrequestbody; /** * 请求参数名称 */ private String parameterName; private String origineRequestParamName; public void setOrigineRequestParamName(String origineRequestParamName) { this.origineRequestParamName = origineRequestParamName; } private boolean namevariabled = false; public void setNamevariabled(boolean namevariabled) { this.namevariabled = namevariabled; } public boolean isNamevariabled() { return namevariabled; } public String getOrigineRequestParamName() { return origineRequestParamName; } /** * 参数名称由常量和变量部分组成,变量var中包含了变量对应的request参数名称和变量在整个参数名称中所处的位置 */ private List<Var> requestParamNameToken; public List<Var> getRequestParamNameToken() { return requestParamNameToken; } public void setRequestParamNameToken(List<Var> requestParamNameToken) { this.requestParamNameToken = requestParamNameToken; } private boolean dataBeanBind; private Scope requestScope = null; private int nestingLevel = 1; /** Map from Integer level to Integer type index */ private Map typeIndexesPerLevel; private Map typeVariableMap; private String paramNamePrefix; private RequestParamWraper requestParam; private RequestHeaderWraper requestHeader; private AttributeWraper attribute; private PagerParamWraper pagerParam; private RequestBodyWraper requestBody; private MapKey mapKey; private boolean primaryType; /** * 标识参数是否被多个不同类型的注解所注解 */ private boolean multiAnnotations = false; private List<MethodParameter> multiAnnotationParams; /** * Create a new MethodParameter for the given method, with nesting level 1. * * @param method * the Method to specify a parameter for * @param parameterIndex * the index of the parameter */ public MethodParameter(Method method, int parameterIndex) { this(method, parameterIndex, 1); } /** * Create a new MethodParameter for the given method. * * @param method * the Method to specify a parameter for * @param parameterIndex * the index of the parameter (-1 for the method return type; 0 * for the first method parameter, 1 for the second method * parameter, etc) * @param nestingLevel * the nesting level of the target type (typically 1; e.g. in * case of a List of Lists, 1 would indicate the nested List, * whereas 2 would indicate the element of the nested List) */ public MethodParameter(Method method, int parameterIndex, int nestingLevel) { Assert.notNull(method, "Method must not be null"); this.method = method; this.parameterIndex = parameterIndex; this.nestingLevel = nestingLevel; } /** * Create a new MethodParameter for the given constructor, with nesting * level 1. * * @param constructor * the Constructor to specify a parameter for * @param parameterIndex * the index of the parameter */ public MethodParameter(Constructor constructor, int parameterIndex) { this(constructor, parameterIndex, 1); } /** * Create a new MethodParameter for the given constructor. * * @param constructor * the Constructor to specify a parameter for * @param parameterIndex * the index of the parameter * @param nestingLevel * the nesting level of the target type (typically 1; e.g. in * case of a List of Lists, 1 would indicate the nested List, * whereas 2 would indicate the element of the nested List) */ public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) { Assert.notNull(constructor, "Constructor must not be null"); this.constructor = constructor; this.parameterIndex = parameterIndex; this.nestingLevel = nestingLevel; } /** * Copy constructor, resulting in an independent MethodParameter object * based on the same metadata and cache state that the original object was * in. * * @param original * the original MethodParameter object to copy from */ public MethodParameter(MethodParameter original) { Assert.notNull(original, "Original must not be null"); this.method = original.method; this.constructor = original.constructor; this.parameterIndex = original.parameterIndex; this.parameterType = original.parameterType; this.parameterAnnotations = original.parameterAnnotations; this.typeVariableMap = original.typeVariableMap; } /** * Return the wrapped Method, if any. * <p> * Note: Either Method or Constructor is available. * * @return the Method, or <code>null</code> if none */ public Method getMethod() { return this.method; } /** * Return the wrapped Constructor, if any. * <p> * Note: Either Method or Constructor is available. * * @return the Constructor, or <code>null</code> if none */ public Constructor getConstructor() { return this.constructor; } /** * Return the index of the method/constructor parameter. * * @return the parameter index (never negative) */ public int getParameterIndex() { return this.parameterIndex; } /** * Set a resolved (generic) parameter type. */ void setParameterType(Class parameterType) { this.parameterType = parameterType; } /** * Return the type of the method/constructor parameter. * * @return the parameter type (never <code>null</code>) */ public Class getParameterType() { if (this.parameterType == null) { this.parameterType = (this.method != null ? this.method .getParameterTypes()[this.parameterIndex] : this.constructor.getParameterTypes()[this.parameterIndex]); } return this.parameterType; } /** * Return the annotations associated with the method/constructor parameter. * * @return the parameter annotations, or <code>null</code> if there is no * annotation support (on JDK < 1.5). The return value is an Object * array instead of an Annotation array simply for compatibility * with older JDKs; feel free to cast it to * <code>Annotation[]</code> on JDK 1.5 or higher. */ public Object[] getParameterAnnotations() { if (this.parameterAnnotations != null) { return this.parameterAnnotations; } if (methodParameterAnnotationsMethod == null) { return null; } Object[][] annotationArray = (this.method != null ? ((Object[][]) ReflectionUtils .invokeMethod(methodParameterAnnotationsMethod, this.method)) : ((Object[][]) ReflectionUtils .invokeMethod(constructorParameterAnnotationsMethod, this.constructor))); this.parameterAnnotations = annotationArray[this.parameterIndex]; return this.parameterAnnotations; } /** * Initialize parameter name discovery for this method parameter. * <p> * This method does not actually try to retrieve the parameter name at this * point; it just allows discovery to happen when the application calls * {@link #getParameterName()} (if ever). */ public void initParameterNameDiscovery( ParameterNameDiscoverer parameterNameDiscoverer) { this.parameterNameDiscoverer = parameterNameDiscoverer; } /** * Return the name of the method/constructor parameter. * * @return the parameter name (may be <code>null</code> if no parameter name * metadata is contained in the class file or no * {@link #initParameterNameDiscovery ParameterNameDiscoverer} has * been set to begin with) */ public String getMethodParameterName() { String parameterName = null; if (parameterName == null && this.parameterNameDiscoverer != null) { String[] parameterNames = (this.method != null ? this.parameterNameDiscoverer .getParameterNames(this.method) : this.parameterNameDiscoverer .getParameterNames(this.constructor)); if (parameterNames != null) { parameterName = parameterNames[this.parameterIndex]; } this.parameterNameDiscoverer = null; } return parameterName; } public String getRequestParameterName() { return this.parameterName; } /** * Increase this parameter's nesting level. * * @see #getNestingLevel() */ public void increaseNestingLevel() { this.nestingLevel++; } /** * Decrease this parameter's nesting level. * * @see #getNestingLevel() */ public void decreaseNestingLevel() { getTypeIndexesPerLevel().remove(new Integer(this.nestingLevel)); this.nestingLevel--; } /** * Return the nesting level of the target type (typically 1; e.g. in case of * a List of Lists, 1 would indicate the nested List, whereas 2 would * indicate the element of the nested List). */ public int getNestingLevel() { return this.nestingLevel; } /** * Set the type index for the current nesting level. * * @param typeIndex * the corresponding type index (or <code>null</code> for the * default type index) * @see #getNestingLevel() */ public void setTypeIndexForCurrentLevel(int typeIndex) { getTypeIndexesPerLevel().put(new Integer(this.nestingLevel), new Integer(typeIndex)); } /** * Return the type index for the current nesting level. * * @return the corresponding type index, or <code>null</code> if none * specified (indicating the default type index) * @see #getNestingLevel() */ public Integer getTypeIndexForCurrentLevel() { return getTypeIndexForLevel(this.nestingLevel); } /** * Return the type index for the specified nesting level. * * @param nestingLevel * the nesting level to check * @return the corresponding type index, or <code>null</code> if none * specified (indicating the default type index) */ public Integer getTypeIndexForLevel(int nestingLevel) { return (Integer) getTypeIndexesPerLevel() .get(new Integer(nestingLevel)); } /** * Obtain the (lazily constructed) type-indexes-per-level Map. */ private Map getTypeIndexesPerLevel() { if (this.typeIndexesPerLevel == null) { this.typeIndexesPerLevel = new HashMap(4); } return this.typeIndexesPerLevel; } /** * Create a new MethodParameter for the given method or constructor. * <p> * This is a convenience constructor for scenarios where a Method or * Constructor reference is treated in a generic fashion. * * @param methodOrConstructor * the Method or Constructor to specify a parameter for * @param parameterIndex * the index of the parameter * @return the corresponding MethodParameter instance */ public static MethodParameter forMethodOrConstructor( Object methodOrConstructor, int parameterIndex) { if (methodOrConstructor instanceof Method) { return new MethodParameter((Method) methodOrConstructor, parameterIndex); } else if (methodOrConstructor instanceof Constructor) { return new MethodParameter((Constructor) methodOrConstructor, parameterIndex); } else { throw new IllegalArgumentException("Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor"); } } public EditorInf getEditor() { return editor; } public void setEditor(EditorInf editor) { this.editor = editor; } public void setParameterName(String parameterName) { this.parameterName = parameterName; } public void setDataBeanBind(boolean dataBeanBind) { this.dataBeanBind = dataBeanBind; } public boolean isDataBeanBind() { return this.dataBeanBind; } public void setDataBindScope(Scope requestScope) { this.requestScope = requestScope; } public Scope getDataBindScope() { return requestScope; } private boolean required = false; public void setRequired(boolean required) { this.required = required; } public boolean isRequired() { return this.required; } private Object defaultValue; public Object getDefaultValue() { return defaultValue; } public void setDefaultValue(Object defaultValue) { this.defaultValue = defaultValue; } public boolean isMultiAnnotations() { return multiAnnotations; } public void setMultiAnnotations(boolean multiAnnotations) { this.multiAnnotations = multiAnnotations; } public List<MethodParameter> getMultiAnnotationParams() { return multiAnnotationParams; } public void setMultiAnnotationParams( List<MethodParameter> multiAnnotationParams) { if(multiAnnotationParams != null && multiAnnotationParams.size() > 0) this.setMultiAnnotations(true); this.multiAnnotationParams = multiAnnotationParams; } public Map getTypeVariableMap() { return typeVariableMap; } protected void setTypeVariableMap(Map typeVariableMap) { this.typeVariableMap = typeVariableMap; } /** * @return the paramNamePrefix */ public String getParamNamePrefix() { return paramNamePrefix; } /** * @param paramNamePrefix the paramNamePrefix to set */ public void setParamNamePrefix(String paramNamePrefix) { this.paramNamePrefix = paramNamePrefix; } /** * @return the requestParam */ public RequestParamWraper getRequestParam() { return requestParam; } /** * @param requestParam the requestParam to set */ public void setRequestParam(RequestParamWraper requestParam) { this.requestParam = requestParam; } private PathVariableWraper pathVariable; public void setPathVariable(PathVariableWraper param) { pathVariable = param; } private CookieValueWraper cookieValue; /** * @return the pathVariable */ public PathVariableWraper getPathVariable() { return pathVariable; } /** * @return the cookieValue */ public CookieValueWraper getCookieValue() { return cookieValue; } /** * @param cookieValue the cookieValue to set */ public void setCookieValue(CookieValueWraper cookieValue) { this.cookieValue = cookieValue; } // private AttributeWraper attribute; /** * @return the attribute */ public AttributeWraper getAttribute() { return attribute; } /** * @param attribute the attribute to set */ public void setAttribute(AttributeWraper attribute) { this.attribute = attribute; } /** * @return the requestHeader */ public RequestHeaderWraper getRequestHeader() { return requestHeader; } /** * @param requestHeader the requestHeader to set */ public void setRequestHeader(RequestHeaderWraper requestHeader) { this.requestHeader = requestHeader; } public void setMapKey(MapKey mapKey) { this.mapKey = mapKey; } public MapKey getMapKey() { return mapKey; } public boolean isPrimaryType() { return primaryType; } public void setPrimaryType(boolean isPrimaryType) { this.primaryType = isPrimaryType; } public PagerParamWraper getPagerParam() { return pagerParam; } public void setPagerParam(PagerParamWraper pagerParam) { this.pagerParam = pagerParam; } public boolean isIsrequestbody() { return isrequestbody; } public void setIsrequestbody(boolean isrequestbody) { this.isrequestbody = isrequestbody; } public RequestBodyWraper getRequestBody() { return requestBody; } public void setRequestBody(RequestBodyWraper requestBody) { this.requestBody = requestBody; } private boolean innerRequestBody(){ if(this.multiAnnotationParams == null || this.multiAnnotationParams.size() == 0){ return false; } for(MethodParameter p:multiAnnotationParams){ if(p.getRequestBody() != null) { return true; } } return false; } /** * 判断参数是否带requestbody注解 * @return */ public boolean requestbody() { return isrequestbody || innerRequestBody(); } }