001    package org.apache.commons.ognl.internal.entry;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    /*
023     * $Id: GenericMethodParameterTypeFactory.java 1194956 2011-10-29 18:02:14Z mcucchiara $
024     */
025    
026    import org.apache.commons.ognl.internal.CacheException;
027    
028    import java.lang.reflect.Array;
029    import java.lang.reflect.GenericArrayType;
030    import java.lang.reflect.ParameterizedType;
031    import java.lang.reflect.Type;
032    import java.lang.reflect.TypeVariable;
033    
034    public class GenericMethodParameterTypeFactory
035        implements CacheEntryFactory<GenericMethodParameterTypeCacheEntry, Class<?>[]>
036    {
037        public Class<?>[] create( GenericMethodParameterTypeCacheEntry entry )
038            throws CacheException
039        {
040            Class<?>[] types;
041    
042            ParameterizedType param = (ParameterizedType) entry.type.getGenericSuperclass();
043            Type[] genTypes = entry.method.getGenericParameterTypes();
044            TypeVariable<?>[] declaredTypes = entry.method.getDeclaringClass().getTypeParameters();
045    
046            types = new Class[genTypes.length];
047    
048            for ( int i = 0; i < genTypes.length; i++ )
049            {
050                TypeVariable<?> paramType = null;
051    
052                if ( TypeVariable.class.isInstance( genTypes[i] ) )
053                {
054                    paramType = (TypeVariable<?>) genTypes[i];
055                }
056                else if ( GenericArrayType.class.isInstance( genTypes[i] ) )
057                {
058                    paramType = (TypeVariable<?>) ( (GenericArrayType) genTypes[i] ).getGenericComponentType();
059                }
060                else if ( ParameterizedType.class.isInstance( genTypes[i] ) )
061                {
062                    types[i] = (Class<?>) ( (ParameterizedType) genTypes[i] ).getRawType();
063                    continue;
064                }
065                else if ( Class.class.isInstance( genTypes[i] ) )
066                {
067                    types[i] = (Class<?>) genTypes[i];
068                    continue;
069                }
070    
071                Class<?> resolved = resolveType( param, paramType, declaredTypes );
072    
073                if ( resolved != null )
074                {
075                    if ( GenericArrayType.class.isInstance( genTypes[i] ) )
076                    {
077                        resolved = Array.newInstance( resolved, 0 ).getClass();
078                    }
079    
080                    types[i] = resolved;
081                    continue;
082                }
083                types[i] = entry.method.getParameterTypes()[i];
084            }
085    
086            return types;
087        }
088    
089        private Class<?> resolveType( ParameterizedType param, TypeVariable<?> var, TypeVariable<?>[] declaredTypes )
090        {
091            if ( param.getActualTypeArguments().length < 1 )
092            {
093                return null;
094            }
095    
096            for ( int i = 0; i < declaredTypes.length; i++ )
097            {
098                if ( !TypeVariable.class.isInstance( param.getActualTypeArguments()[i] )
099                    && declaredTypes[i].getName().equals( var.getName() ) )
100                {
101                    return (Class<?>) param.getActualTypeArguments()[i];
102                }
103            }
104    
105            return null;
106        }
107    }