001 //Copyright 2004, 2005 The Apache Software Foundation
002
003 //Licensed under the Apache License, Version 2.0 (the "License");
004 //you may not use this file except in compliance with the License.
005 //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
010 //distributed under the License is distributed on an "AS IS" BASIS,
011 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 //See the License for the specific language governing permissions and
013 //limitations under the License.
014 package org.apache.tapestry.enhance;
015
016 import java.lang.reflect.Method;
017 import java.lang.reflect.ParameterizedType;
018 import java.lang.reflect.Type;
019 import java.lang.reflect.TypeVariable;
020
021
022 /**
023 * Implementation of {@link MethodSignature} that supports jdk 1.5 generic typing support.
024 *
025 */
026 public class GenericsMethodSignatureImpl extends MethodSignatureImpl implements MethodSignature
027 {
028 boolean _isGeneric;
029
030 public GenericsMethodSignatureImpl(Class type, Method m)
031 {
032 super(findReturnType(type, m), m.getName(), findParameterTypes(type, m), m.getExceptionTypes());
033
034 _isGeneric = type.getGenericSuperclass() != null && ParameterizedType.class.isInstance(type.getGenericSuperclass());
035 }
036
037 public boolean isGeneric()
038 {
039 return _isGeneric;
040 }
041
042 static Class findReturnType(Class type, Method m)
043 {
044 Type ret = m.getGenericReturnType();
045
046 if (TypeVariable.class.isInstance(ret)
047 && type.getGenericSuperclass() != null
048 && ParameterizedType.class.isInstance(type.getGenericSuperclass())) {
049
050 TypeVariable tvar = (TypeVariable)ret;
051 ParameterizedType param = (ParameterizedType)type.getGenericSuperclass();
052
053 Class resolvedType = resolveType(param, tvar);
054 if (resolvedType != null)
055 return resolvedType;
056
057 }
058
059 return m.getReturnType();
060 }
061
062 static Class resolveType(ParameterizedType param, TypeVariable var)
063 {
064 if (param.getActualTypeArguments().length < 1)
065 return null;
066
067 for (int i=0; i < var.getBounds().length; i++) {
068
069 Type t = var.getBounds()[i];
070 Class resolvedType = null;
071 if (ParameterizedType.class.isInstance(t)) {
072
073 ParameterizedType pparam = (ParameterizedType)t;
074 for (int e=0; e < pparam.getActualTypeArguments().length; e++) {
075 if (!TypeVariable.class.isInstance(pparam.getActualTypeArguments()[e]))
076 continue;
077
078 resolvedType = resolveType(pparam, (TypeVariable)pparam.getActualTypeArguments()[e]);
079 }
080 } else {
081
082 resolvedType = findType(param.getActualTypeArguments(), (Class)t);
083 }
084
085 if (resolvedType != null)
086 return resolvedType;
087 }
088
089 return null;
090 }
091
092 static Class findType(Type[] types, Class type)
093 {
094 for (int i = 0; i < types.length; i++) {
095
096 if (Class.class.isInstance(types[i]) && type.isAssignableFrom((Class)types[i]))
097 return (Class)types[i];
098 }
099
100 return null;
101 }
102
103 static Class[] findParameterTypes(Class type, Method m)
104 {
105 if (type.getGenericSuperclass() == null
106 || !ParameterizedType.class.isInstance(type.getGenericSuperclass()))
107 return m.getParameterTypes();
108
109 ParameterizedType param = (ParameterizedType)type.getGenericSuperclass();
110 Type[] genTypes = m.getGenericParameterTypes();
111 Class[] types = new Class[genTypes.length];
112
113 typeSearch:
114 for (int i=0; i < genTypes.length; i++) {
115
116 if (TypeVariable.class.isInstance(genTypes[i])) {
117
118 Class resolved = resolveType(param, (TypeVariable)genTypes[i]);
119
120 if (resolved != null) {
121 types[i] = resolved;
122 continue;
123 }
124 }
125
126 types[i] = m.getParameterTypes()[i];
127 }
128
129 return types;
130 }
131
132
133 }