001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.guard;
014    
015    import java.lang.reflect.AccessibleObject;
016    import java.lang.reflect.Constructor;
017    import java.lang.reflect.Field;
018    import java.lang.reflect.Method;
019    import java.util.WeakHashMap;
020    
021    import net.sf.oval.exception.ReflectionException;
022    import net.sf.oval.internal.util.ReflectionUtils;
023    
024    import org.aspectj.lang.JoinPoint;
025    import org.aspectj.lang.reflect.ConstructorSignature;
026    import org.aspectj.lang.reflect.MethodSignature;
027    
028    /**
029     * This class determines the names of constructor and method parameters based on the static 
030     * JoinPoint fields added to the classes by the AspectJ compiler.
031     *  
032     * @author Sebastian Thomschke
033     */
034    public class ParameterNameResolverAspectJImpl implements ParameterNameResolver
035    {
036            private final WeakHashMap<AccessibleObject, String[]> parameterNamesCache = new WeakHashMap<AccessibleObject, String[]>();
037    
038            private void determineParamterNames(final Class< ? > clazz) throws IllegalArgumentException, IllegalAccessException
039            {
040                    assert clazz != null;
041    
042                    for (final Field field : clazz.getDeclaredFields())
043                    {
044                            // search for static fields of type JoinPoint.StaticPart
045                            if (ReflectionUtils.isStatic(field) && field.getType() == JoinPoint.StaticPart.class)
046                            {
047                                    // access the StaticPart object
048                                    field.setAccessible(true);
049                                    final JoinPoint.StaticPart staticPart = (JoinPoint.StaticPart) field.get(null);
050                                    if (staticPart == null)
051                                    {
052                                            break;
053                                    }
054    
055                                    if (staticPart.getSignature() instanceof ConstructorSignature)
056                                    {
057                                            final ConstructorSignature sig = (ConstructorSignature) staticPart.getSignature();
058                                            final String[] parameterNames = sig.getParameterNames();
059    
060                                            final Constructor< ? > constr = sig.getConstructor();
061    
062                                            if (parameterNames.length > 0)
063                                            {
064                                                    parameterNamesCache.put(constr, parameterNames);
065                                            }
066                                    }
067                                    else if (staticPart.getSignature() instanceof MethodSignature)
068                                    {
069                                            final MethodSignature sig = (MethodSignature) staticPart.getSignature();
070                                            final String[] parameterNames = sig.getParameterNames();
071    
072                                            final Method method = sig.getMethod();
073    
074                                            if (parameterNames.length > 0)
075                                            {
076                                                    parameterNamesCache.put(method, parameterNames);
077                                            }
078                                    }
079                            }
080                    }
081            }
082    
083            /**
084             * {@inheritDoc}
085             */
086            public String[] getParameterNames(final Constructor< ? > constructor) throws ReflectionException
087            {
088                    /*
089                     * intentionally the following code is not synchronized
090                     */
091                    String[] parameterNames = parameterNamesCache.get(constructor);
092                    if (parameterNames == null)
093                    {
094                            try
095                            {
096                                    determineParamterNames(constructor.getDeclaringClass());
097                                    parameterNames = parameterNamesCache.get(constructor);
098                            }
099                            catch (final IllegalArgumentException e)
100                            {
101                                    throw new ReflectionException("Cannot detemine parameter names for constructor " + constructor, e);
102                            }
103                            catch (final IllegalAccessException e)
104                            {
105                                    throw new ReflectionException("Cannot detemine parameter names for constructor " + constructor, e);
106                            }
107                    }
108    
109                    if (parameterNames == null)
110                    {
111                            final int parameterCount = constructor.getParameterTypes().length;
112                            parameterNames = new String[parameterCount];
113                            for (int i = 0; i < parameterCount; i++)
114                            {
115                                    parameterNames[i] = "parameter" + i;
116                            }
117                            parameterNamesCache.put(constructor, parameterNames);
118                    }
119                    return parameterNames;
120            }
121    
122            /**
123             * {@inheritDoc}
124             */
125            public String[] getParameterNames(final Method method) throws ReflectionException
126            {
127                    /*
128                     * intentionally the following code is not synchronized
129                     */
130                    String[] parameterNames = parameterNamesCache.get(method);
131                    if (parameterNames == null)
132                    {
133                            try
134                            {
135                                    determineParamterNames(method.getDeclaringClass());
136                                    parameterNames = parameterNamesCache.get(method);
137                            }
138                            catch (final IllegalArgumentException e)
139                            {
140                                    throw new ReflectionException("Cannot detemine parameter names for method " + method, e);
141                            }
142                            catch (final IllegalAccessException e)
143                            {
144                                    throw new ReflectionException("Cannot detemine parameter names for method " + method, e);
145                            }
146                    }
147    
148                    if (parameterNames == null)
149                    {
150                            final int parameterCount = method.getParameterTypes().length;
151                            parameterNames = new String[parameterCount];
152                            for (int i = 0; i < parameterCount; i++)
153                            {
154                                    parameterNames[i] = "parameter" + i;
155                            }
156                            parameterNamesCache.put(method, parameterNames);
157                    }
158                    return parameterNames;
159            }
160    }