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