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