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 }