/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockito.internal.invocation; import java.lang.reflect.Method; import org.mockito.ArgumentMatcher; @SuppressWarnings({"unchecked","rawtypes"}) public class TypeSafeMatching implements ArgumentMatcherAction { private final static ArgumentMatcherAction TYPE_SAFE_MATCHING_ACTION = new TypeSafeMatching(); private TypeSafeMatching() {} public static ArgumentMatcherAction matchesTypeSafe(){ return TYPE_SAFE_MATCHING_ACTION; } @Override public boolean apply(ArgumentMatcher matcher, Object argument) { return isCompatible(matcher, argument) && matcher.matches(argument); } /** * Returns <code>true</code> if the given <b>argument</b> can be passed to * the given <code>argumentMatcher</code> without causing a * {@link ClassCastException}. */ private static boolean isCompatible(ArgumentMatcher<?> argumentMatcher, Object argument) { if (argument == null) return true; Class<?> expectedArgumentType = getArgumentType(argumentMatcher); return expectedArgumentType.isInstance(argument); } /** * Returns the type of {@link ArgumentMatcher#matches(Object)} of the given * {@link ArgumentMatcher} implementation. */ private static Class<?> getArgumentType(ArgumentMatcher<?> argumentMatcher) { Method[] methods = argumentMatcher.getClass().getMethods(); for (Method method : methods) { if (isMatchesMethod(method)) { return method.getParameterTypes()[0]; } } 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 "); } /** * Returns <code>true</code> if the given method is * {@link ArgumentMatcher#matches(Object)} */ private static boolean isMatchesMethod(Method method) { if (method.getParameterTypes().length != 1) { return false; } if (method.isBridge()) { return false; } return method.getName().equals("matches"); } }