package org.hamcrest;
import org.hamcrest.internal.
ReflectiveTypeFinder;
/**
* Convenient base class for Matchers that require a non-null value of a specific type.
* This simply implements the null check, checks the type and then casts.
*
* @author Joe Walnes
* @author Steve Freeman
* @author Nat Pryce
*/
public abstract class
TypeSafeMatcher<T> extends
BaseMatcher<T> {
private static final
ReflectiveTypeFinder TYPE_FINDER = new
ReflectiveTypeFinder("matchesSafely", 1, 0);
final private
Class<?>
expectedType;
/**
* The default constructor for simple sub types
*/
protected
TypeSafeMatcher() {
this(
TYPE_FINDER);
}
/**
* Use this constructor if the subclass that implements <code>matchesSafely</code>
* is <em>not</em> the class that binds <T> to a type.
* @param expectedType The expectedType of the actual value.
*/
protected
TypeSafeMatcher(
Class<?>
expectedType) {
this.
expectedType =
expectedType;
}
/**
* Use this constructor if the subclass that implements <code>matchesSafely</code>
* is <em>not</em> the class that binds <T> to a type.
* @param typeFinder A type finder to extract the type
*/
protected
TypeSafeMatcher(
ReflectiveTypeFinder typeFinder) {
this.
expectedType =
typeFinder.
findExpectedType(
getClass());
}
/**
* Subclasses should implement this. The item will already have been checked for
* the specific type and will never be null.
*/
protected abstract boolean
matchesSafely(T
item);
/**
* Subclasses should override this. The item will already have been checked for
* the specific type and will never be null.
*/
protected void
describeMismatchSafely(T
item,
Description mismatchDescription) {
super.describeMismatch(
item,
mismatchDescription);
}
/**
* Methods made final to prevent accidental override.
* If you need to override this, there's no point on extending TypeSafeMatcher.
* Instead, extend the {@link BaseMatcher}.
*/
@
Override
@
SuppressWarnings({"unchecked"})
public final boolean
matches(
Object item) {
return
item != null
&&
expectedType.
isInstance(
item)
&&
matchesSafely((T)
item);
}
@
SuppressWarnings("unchecked")
@
Override
final public void
describeMismatch(
Object item,
Description description) {
if (
item == null) {
super.describeMismatch(
item,
description);
} else if (!
expectedType.
isInstance(
item)) {
description.
appendText("was a ")
.
appendText(
item.
getClass().
getName())
.
appendText(" (")
.
appendValue(
item)
.
appendText(")");
} else {
describeMismatchSafely((T)
item,
description);
}
}
}