How to use method of org.easymock.internal.BridgeMethodResolver class

Best Easymock code snippet using org.easymock.internal.BridgeMethodResolver.

Run Easymock automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

copy
1/**
2 * Copyright 2001-2013 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.easymock.internal;
17
18import java.lang.reflect.*;
19import java.util.*;
20
21/**
22 * Code taken from the <a href="http://www.springframework.org">Spring
23 * framework</a>.
24 * 
25 * Helper for resolving synthetic {@link Method#isBridge bridge Methods} to the
26 * {@link Method} being bridged.
27 * 
28 * <p>
29 * Given a synthetic {@link Method#isBridge bridge Method} returns the
30 * {@link Method} being bridged. A bridge method may be created by the compiler
31 * when extending a parameterized type whose methods have parameterized
32 * arguments. During runtime invocation the bridge {@link Method} may be invoked
33 * and/or used via reflection. When attempting to locate annotations on
34 * {@link Method Methods}, it is wise to check for bridge {@link Method Methods}
35 * as appropriate and find the bridged {@link Method}.
36 * 
37 * <p>
38 * See <a href="http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.4.5"
39 * > The Java Language Specification</a> for more details on the use of bridge
40 * methods.
41 * 
42 * @author Rob Harrop
43 * @author Juergen Hoeller
44 */
45public final class BridgeMethodResolver {
46
47    // Hard to test all cases since bridges varies from JVM implementation
48    // Plus, the code is taken from Spring so we consider it is working
49    // So, don't check coverage over the class
50
51    // ///CLOVER:OFF
52    private BridgeMethodResolver() {
53    }
54
55    /**
56     * Find the original method for the supplied {@link Method bridge Method}.
57     * <p>
58     * It is safe to call this method passing in a non-bridge {@link Method}
59     * instance. In such a case, the supplied {@link Method} instance is
60     * returned directly to the caller. Callers are <strong>not</strong>
61     * required to check for bridging before calling this method.
62     * 
63     * @param bridgeMethod
64     *            the bridge method
65     * @return the original method for the bridge
66     * @throws IllegalStateException
67     *             if no bridged {@link Method} can be found
68     */
69    public static Method findBridgedMethod(final Method bridgeMethod) {
70        assert bridgeMethod != null : "Method must not be null";
71
72        if (!bridgeMethod.isBridge()) {
73            return bridgeMethod;
74        }
75
76        // Gather all methods with matching name and parameter size.
77        final List<Method> candidateMethods = new ArrayList<Method>();
78        final Method[] methods = getAllDeclaredMethods(bridgeMethod.getDeclaringClass());
79        for (final Method candidateMethod : methods) {
80            if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) {
81                candidateMethods.add(candidateMethod);
82            }
83        }
84
85        Method result;
86        // Now perform simple quick checks.
87        if (candidateMethods.size() == 1) {
88            result = candidateMethods.get(0);
89        } else {
90            result = searchCandidates(candidateMethods, bridgeMethod);
91        }
92
93        if (result == null) {
94            throw new IllegalStateException("Unable to locate bridged method for bridge method '"
95                    + bridgeMethod + "'");
96        }
97
98        return result;
99    }
100
101    /**
102     * Search for the bridged method in the given candidates.
103     * 
104     * @param candidateMethods
105     *            the List of candidate Methods
106     * @param bridgeMethod
107     *            the bridge method
108     * @return the bridged method, or <code>null</code> if none found
109     */
110    private static Method searchCandidates(final List<Method> candidateMethods, final Method bridgeMethod) {
111        final Map<TypeVariable<?>, Type> typeParameterMap = createTypeVariableMap(bridgeMethod
112                .getDeclaringClass());
113        for (int i = 0; i < candidateMethods.size(); i++) {
114            final Method candidateMethod = candidateMethods.get(i);
115            if (isBridgeMethodFor(bridgeMethod, candidateMethod, typeParameterMap)) {
116                return candidateMethod;
117            }
118        }
119        return null;
120    }
121
122    /**
123     * Return <code>true</code> if the supplied '<code>candidateMethod</code>'
124     * can be consider a validate candidate for the {@link Method} that is
125     * {@link Method#isBridge() bridged} by the supplied {@link Method bridge
126     * Method}. This method performs inexpensive checks and can be used quickly
127     * filter for a set of possible matches.
128     */
129    private static boolean isBridgedCandidateFor(final Method candidateMethod, final Method bridgeMethod) {
130        return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod)
131                && candidateMethod.getName().equals(bridgeMethod.getName()) && candidateMethod
132                .getParameterTypes().length == bridgeMethod.getParameterTypes().length);
133    }
134
135    /**
136     * Determine whether or not the bridge {@link Method} is the bridge for the
137     * supplied candidate {@link Method}.
138     */
139    private static boolean isBridgeMethodFor(final Method bridgeMethod, final Method candidateMethod,
140            final Map<TypeVariable<?>, Type> typeVariableMap) {
141        if (isResolvedTypeMatch(candidateMethod, bridgeMethod, typeVariableMap)) {
142            return true;
143        }
144        final Method method = findGenericDeclaration(bridgeMethod);
145        return (method != null ? isResolvedTypeMatch(method, candidateMethod, typeVariableMap) : false);
146    }
147
148    /**
149     * Search for the generic {@link Method} declaration whose erased signature
150     * matches that of the supplied bridge method.
151     * 
152     * @throws IllegalStateException
153     *             if the generic declaration cannot be found
154     */
155    private static Method findGenericDeclaration(final Method bridgeMethod) {
156        // Search parent types for method that has same signature as bridge.
157        Class<?> superclass = bridgeMethod.getDeclaringClass().getSuperclass();
158        while (!Object.class.equals(superclass)) {
159            final Method method = searchForMatch(superclass, bridgeMethod);
160            if (method != null && !method.isBridge()) {
161                return method;
162            }
163            superclass = superclass.getSuperclass();
164        }
165
166        // Search interfaces.
167        final Class<?>[] interfaces = getAllInterfacesForClass(bridgeMethod.getDeclaringClass());
168        for (final Class<?> anInterface : interfaces) {
169            final Method method = searchForMatch(anInterface, bridgeMethod);
170            if (method != null && !method.isBridge()) {
171                return method;
172            }
173        }
174
175        return null;
176    }
177
178    /**
179     * Return <code>true</code> if the {@link Type} signature of both the
180     * supplied {@link Method#getGenericParameterTypes() generic Method} and
181     * concrete {@link Method} are equal after resolving all
182     * {@link TypeVariable TypeVariables} using the supplied
183     * {@link #createTypeVariableMap TypeVariable Map}, otherwise returns
184     * <code>false</code>.
185     */
186    private static boolean isResolvedTypeMatch(final Method genericMethod, final Method candidateMethod,
187            final Map<TypeVariable<?>, Type> typeVariableMap) {
188        final Type[] genericParameters = genericMethod.getGenericParameterTypes();
189        final Class<?>[] candidateParameters = candidateMethod.getParameterTypes();
190        if (genericParameters.length != candidateParameters.length) {
191            return false;
192        }
193        for (int i = 0; i < genericParameters.length; i++) {
194            final Type genericParameter = genericParameters[i];
195            final Class<?> candidateParameter = candidateParameters[i];
196            if (candidateParameter.isArray()) {
197                // An array type: compare the component type.
198                final Type rawType = getRawType(genericParameter, typeVariableMap);
199                if (rawType instanceof GenericArrayType) {
200                    if (!candidateParameter.getComponentType().equals(
201                            getRawType(((GenericArrayType) rawType).getGenericComponentType(),
202                                    typeVariableMap))) {
203                        return false;
204                    }
205                    break;
206                }
207            }
208            // A non-array type: compare the type itself.
209            if (!candidateParameter.equals(getRawType(genericParameter, typeVariableMap))) {
210                return false;
211            }
212        }
213        return true;
214    }
215
216    /**
217     * Determine the raw type for the given generic parameter type.
218     */
219    private static Type getRawType(final Type genericType, final Map<TypeVariable<?>, Type> typeVariableMap) {
220        if (genericType instanceof TypeVariable<?>) {
221            final TypeVariable<?> tv = (TypeVariable<?>) genericType;
222            final Type result = typeVariableMap.get(tv);
223            return (result != null ? result : Object.class);
224        } else if (genericType instanceof ParameterizedType) {
225            return ((ParameterizedType) genericType).getRawType();
226        } else {
227            return genericType;
228        }
229    }
230
231    /**
232     * If the supplied {@link Class} has a declared {@link Method} whose
233     * signature matches that of the supplied {@link Method}, then this matching
234     * {@link Method} is returned, otherwise <code>null</code> is returned.
235     */
236    private static Method searchForMatch(final Class<?> type, final Method bridgeMethod) {
237        return findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes());
238    }
239
240    /**
241     * Build a mapping of {@link TypeVariable#getName TypeVariable names} to
242     * concrete {@link Class} for the specified {@link Class}. Searches all
243     * super types, enclosing types and interfaces.
244     */
245    private static Map<TypeVariable<?>, Type> createTypeVariableMap(final Class<?> cls) {
246        final Map<TypeVariable<?>, Type> typeVariableMap = new HashMap<TypeVariable<?>, Type>();
247
248        // interfaces
249        extractTypeVariablesFromGenericInterfaces(cls.getGenericInterfaces(), typeVariableMap);
250
251        // super class
252        Type genericType = cls.getGenericSuperclass();
253        Class<?> type = cls.getSuperclass();
254        while (!Object.class.equals(type)) {
255            if (genericType instanceof ParameterizedType) {
256                final ParameterizedType pt = (ParameterizedType) genericType;
257                populateTypeMapFromParameterizedType(pt, typeVariableMap);
258            }
259            extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(), typeVariableMap);
260            genericType = type.getGenericSuperclass();
261            type = type.getSuperclass();
262        }
263
264        // enclosing class
265        type = cls;
266        while (type.isMemberClass()) {
267            genericType = type.getGenericSuperclass();
268            if (genericType instanceof ParameterizedType) {
269                final ParameterizedType pt = (ParameterizedType) genericType;
270                populateTypeMapFromParameterizedType(pt, typeVariableMap);
271            }
272            type = type.getEnclosingClass();
273        }
274
275        return typeVariableMap;
276    }
277
278    private static void extractTypeVariablesFromGenericInterfaces(final Type[] genericInterfaces,
279            final Map<TypeVariable<?>, Type> typeVariableMap) {
280        for (final Type genericInterface : genericInterfaces) {
281            if (genericInterface instanceof ParameterizedType) {
282                final ParameterizedType pt = (ParameterizedType) genericInterface;
283                populateTypeMapFromParameterizedType(pt, typeVariableMap);
284                if (pt.getRawType() instanceof Class<?>) {
285                    extractTypeVariablesFromGenericInterfaces(((Class<?>) pt.getRawType())
286                            .getGenericInterfaces(), typeVariableMap);
287                }
288            } else if (genericInterface instanceof Class<?>) {
289                extractTypeVariablesFromGenericInterfaces(((Class<?>) genericInterface)
290                        .getGenericInterfaces(), typeVariableMap);
291            }
292        }
293    }
294
295    /**
296     * Read the {@link TypeVariable TypeVariables} from the supplied
297     * {@link ParameterizedType} and add mappings corresponding to the
298     * {@link TypeVariable#getName TypeVariable name} -> concrete type to the
299     * supplied {@link Map}.
300     * <p>
301     * Consider this case:
302     * 
303     * <pre class="code>
304     * public interface Foo&lt;S, T&gt; {
305     *  ..
306     * }
307     * 
308     * public class FooImpl implements Foo&lt;String, Integer&gt; {
309     *  ..
310     * }
311     * </pre>
312     * 
313     * For '<code>FooImpl</code>' the following mappings would be added to the
314     * {@link Map}: {S=java.lang.String, T=java.lang.Integer}.
315     */
316    private static void populateTypeMapFromParameterizedType(final ParameterizedType type,
317            final Map<TypeVariable<?>, Type> typeVariableMap) {
318        if (type.getRawType() instanceof Class<?>) {
319            final Type[] actualTypeArguments = type.getActualTypeArguments();
320            final TypeVariable<?>[] typeVariables = ((Class<?>) type.getRawType()).getTypeParameters();
321            for (int i = 0; i < actualTypeArguments.length; i++) {
322                final Type actualTypeArgument = actualTypeArguments[i];
323                final TypeVariable<?> variable = typeVariables[i];
324                if (actualTypeArgument instanceof Class<?>) {
325                    typeVariableMap.put(variable, actualTypeArgument);
326                } else if (actualTypeArgument instanceof GenericArrayType) {
327                    typeVariableMap.put(variable, actualTypeArgument);
328                } else if (actualTypeArgument instanceof ParameterizedType) {
329                    typeVariableMap.put(variable, ((ParameterizedType) actualTypeArgument).getRawType());
330                } else if (actualTypeArgument instanceof TypeVariable<?>) {
331                    // We have a type that is parameterized at instantiation time
332                    // the nearest match on the bridge method will be the bounded type.
333                    final TypeVariable<?> typeVariableArgument = (TypeVariable<?>) actualTypeArgument;
334                    Type resolvedType = typeVariableMap.get(typeVariableArgument);
335                    if (resolvedType == null) {
336                        resolvedType = extractClassForTypeVariable(typeVariableArgument);
337                    }
338                    if (resolvedType != null) {
339                        typeVariableMap.put(variable, resolvedType);
340                    }
341                }
342            }
343        }
344    }
345
346    /**
347     * Extracts the bound '<code>Class</code>' for a give {@link TypeVariable}.
348     */
349    private static Class<?> extractClassForTypeVariable(final TypeVariable<?> typeVariable) {
350        final Type[] bounds = typeVariable.getBounds();
351        Type result = null;
352        if (bounds.length > 0) {
353            final Type bound = bounds[0];
354            if (bound instanceof ParameterizedType) {
355                result = ((ParameterizedType) bound).getRawType();
356            } else if (bound instanceof Class<?>) {
357                result = bound;
358            } else if (bound instanceof TypeVariable<?>) {
359                result = extractClassForTypeVariable((TypeVariable<?>) bound);
360            }
361        }
362        return (result instanceof Class<?> ? (Class<?>) result : null);
363    }
364
365    /**
366     * Return all interfaces that the given class implements as array, including
367     * ones implemented by superclasses.
368     * <p>
369     * If the class itself is an interface, it gets returned as sole interface.
370     * 
371     * @param clazz
372     *            the class to analyse for interfaces
373     * @return all interfaces that the given object implements as array
374     */
375    private static Class<?>[] getAllInterfacesForClass(Class<?> clazz) {
376        assert clazz != null : "Class must not be null";
377        if (clazz.isInterface()) {
378            return new Class[] { clazz };
379        }
380        final List<Class<?>> interfaces = new ArrayList<Class<?>>();
381        while (clazz != null) {
382            for (int i = 0; i < clazz.getInterfaces().length; i++) {
383                final Class<?> ifc = clazz.getInterfaces()[i];
384                if (!interfaces.contains(ifc)) {
385                    interfaces.add(ifc);
386                }
387            }
388            clazz = clazz.getSuperclass();
389        }
390        return interfaces.toArray(new Class[interfaces.size()]);
391    }
392
393    /**
394     * Attempt to find a {@link Method} on the supplied class with the supplied
395     * name and parameter types. Searches all superclasses up to
396     * <code>Object</code>.
397     * <p>
398     * Returns <code>null</code> if no {@link Method} can be found.
399     * 
400     * @param clazz
401     *            the class to introspect
402     * @param name
403     *            the name of the method
404     * @param paramTypes
405     *            the parameter types of the method
406     * @return the Method object, or <code>null</code> if none found
407     */
408    private static Method findMethod(final Class<?> clazz, final String name, final Class<?>[] paramTypes) {
409        assert clazz != null : "Class must not be null";
410        assert name != null : "Method name must not be null";
411        Class<?> searchType = clazz;
412        while (!Object.class.equals(searchType) && searchType != null) {
413            final Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType
414                    .getDeclaredMethods());
415            for (final Method method : methods) {
416                if (name.equals(method.getName()) && Arrays.equals(paramTypes, method.getParameterTypes())) {
417                    return method;
418                }
419            }
420            searchType = searchType.getSuperclass();
421        }
422        return null;
423    }
424
425    /**
426     * Get all declared methods on the leaf class and all superclasses. Leaf
427     * class methods are included first.
428     */
429    private static Method[] getAllDeclaredMethods(Class<?> leafClass) {
430        final List<Method> list = new LinkedList<Method>();
431
432        // Keep backing up the inheritance hierarchy.
433        do {
434            final Method[] methods = leafClass.getDeclaredMethods();
435            for (final Method method : methods) {
436                list.add(method);
437            }
438            leafClass = leafClass.getSuperclass();
439        } while (leafClass != null);
440
441        return list.toArray(new Method[list.size()]);
442    }
443    // ///CLOVER:ON
444}
445
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)