1/* 2 * Copyright (c) 2007 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5package org.mockito.internal.invocation; 6 7import java.lang.reflect.Method; 8 9import org.mockito.ArgumentMatcher; 10 11@SuppressWarnings({"unchecked","rawtypes"}) 12public class TypeSafeMatching implements ArgumentMatcherAction { 13 14 private final static ArgumentMatcherAction TYPE_SAFE_MATCHING_ACTION = new TypeSafeMatching(); 15 16 private TypeSafeMatching() {} 17 18 19 public static ArgumentMatcherAction matchesTypeSafe(){ 20 return TYPE_SAFE_MATCHING_ACTION; 21 } 22 @Override 23 public boolean apply(ArgumentMatcher matcher, Object argument) { 24 return isCompatible(matcher, argument) && matcher.matches(argument); 25 } 26 27 28 /** 29 * Returns <code>true</code> if the given <b>argument</b> can be passed to 30 * the given <code>argumentMatcher</code> without causing a 31 * {@link ClassCastException}. 32 */ 33 private static boolean isCompatible(ArgumentMatcher<?> argumentMatcher, Object argument) { 34 if (argument == null) 35 return true; 36 37 Class<?> expectedArgumentType = getArgumentType(argumentMatcher); 38 39 return expectedArgumentType.isInstance(argument); 40 } 41 42 /** 43 * Returns the type of {@link ArgumentMatcher#matches(Object)} of the given 44 * {@link ArgumentMatcher} implementation. 45 */ 46 private static Class<?> getArgumentType(ArgumentMatcher<?> argumentMatcher) { 47 Method[] methods = argumentMatcher.getClass().getMethods(); 48 49 for (Method method : methods) { 50 if (isMatchesMethod(method)) { 51 return method.getParameterTypes()[0]; 52 } 53 } 54 throw new NoSuchMethodError("Method 'matches(T)' not found in ArgumentMatcher: " + argumentMatcher + " !\r\n Please file a bug with this stack trace at: https://github.com/mockito/mockito/issues/new "); 55 } 56 57 /** 58 * Returns <code>true</code> if the given method is 59 * {@link ArgumentMatcher#matches(Object)} 60 */ 61 private static boolean isMatchesMethod(Method method) { 62 if (method.getParameterTypes().length != 1) { 63 return false; 64 } 65 if (method.isBridge()) { 66 return false; 67 } 68 return method.getName().equals("matches"); 69 } 70} 71