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    }