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 <T> 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 <T> 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 }