1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.internal.matchers; 2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Method; 4b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.hamcrest.BaseMatcher; 6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/** 8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Convenient base class for Matchers that require a non-null value of a specific type. 9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * This simply implements the null check, checks the type and then casts. 10b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * 11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * @author Joe Walnes 12b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 13b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpublic abstract class TypeSafeMatcher<T> extends BaseMatcher<T> { 14b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 15b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private Class<?> expectedType; 16b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Subclasses should implement this. The item will already have been checked for 19b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * the specific type and will never be null. 20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public abstract boolean matchesSafely(T item); 22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot protected TypeSafeMatcher() { 24b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot expectedType = findExpectedType(getClass()); 25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private static Class<?> findExpectedType(Class<?> fromClass) { 28b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (Class<?> c = fromClass; c != Object.class; c = c.getSuperclass()) { 29b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot for (Method method : c.getDeclaredMethods()) { 30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot if (isMatchesSafelyMethod(method)) { 31b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return method.getParameterTypes()[0]; 32b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 33b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 34b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 35b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 36b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot throw new Error("Cannot determine correct type for matchesSafely() method."); 37b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 38b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 39b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot private static boolean isMatchesSafelyMethod(Method method) { 40b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return method.getName().equals("matchesSafely") 41b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot && method.getParameterTypes().length == 1 42b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot && !method.isSynthetic(); 43b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 44b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 45b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot protected TypeSafeMatcher(Class<T> expectedType) { 46b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot this.expectedType = expectedType; 47b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 48b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot 49b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot /** 50b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Method made final to prevent accidental override. 51b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * If you need to override this, there's no point on extending TypeSafeMatcher. 52b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Instead, extend the {@link BaseMatcher}. 53b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */ 54b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot @SuppressWarnings({"unchecked"}) 55b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot public final boolean matches(Object item) { 56b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot return item != null 57b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot && expectedType.isInstance(item) 58b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot && matchesSafely((T) item); 59b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot } 60b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot} 61