    001    package org.hamcrest;
    002
    003    import org.hamcrest.internal.ReflectiveTypeFinder;
    004
    005
    006    /**
    007     * Convenient base class for Matchers that require a non-null value of a specific type
    008     * and that will report why the received value has been rejected.
    009     * This implements the null check, checks the type and then casts.
    010     * To use, implement <pre>matchesSafely()</pre>.
    011     *
    012     * @param <T>
    013     * @author Neil Dunn
    014     * @author Nat Pryce
    015     * @author Steve Freeman
    016     */
    017    public abstract class TypeSafeDiagnosingMatcher<T> extends BaseMatcher<T> {
    018        private static final ReflectiveTypeFinder TYPE_FINDER = new ReflectiveTypeFinder("matchesSafely", 2, 0);
    019        private final Class<?> expectedType;
    020
    021        /**
    022         * Subclasses should implement this. The item will already have been checked
    023         * for the specific type and will never be null.
    024         */
    025        protected abstract boolean matchesSafely(T item, Description mismatchDescription);
    026
    027        /**
    028         * Use this constructor if the subclass that implements <code>matchesSafely</code>
    029         * is <em>not</em> the class that binds &lt;T&gt; to a type.
    030         * @param expectedType The expectedType of the actual value.
    031         */
    032        protected TypeSafeDiagnosingMatcher(Class<?> expectedType) {
    033          this.expectedType = expectedType;
    034        }
    035
    036        /**
    037         * Use this constructor if the subclass that implements <code>matchesSafely</code>
    038         * is <em>not</em> the class that binds &lt;T&gt; to a type.
    039         * @param typeFinder A type finder to extract the type
    040         */
    041        protected TypeSafeDiagnosingMatcher(ReflectiveTypeFinder typeFinder) {
    042          this.expectedType = typeFinder.findExpectedType(getClass());
    043        }
    044
    045        /**
    046         * The default constructor for simple sub types
    047         */
    048        protected TypeSafeDiagnosingMatcher() {
    049          this(TYPE_FINDER);
    050        }
    051
    052        @Override
    053        @SuppressWarnings("unchecked")
    054        public final boolean matches(Object item) {
    055            return item != null
    056                && expectedType.isInstance(item)
    057                && matchesSafely((T) item, new Description.NullDescription());
    058        }
    059
    060        @SuppressWarnings("unchecked")
    061        @Override
    062        public final void describeMismatch(Object item, Description mismatchDescription) {
    063          if (item == null || !expectedType.isInstance(item)) {
    064            super.describeMismatch(item, mismatchDescription);
    065          } else {
    066            matchesSafely((T) item, mismatchDescription);
    067          }
    068        }
    069    }