001 package org.hamcrest;
002
003 import org.hamcrest.internal.ReflectiveTypeFinder;
004
005 /**
006 * Supporting class for matching a feature of an object. Implement <code>featureValueOf()</code>
007 * in a subclass to pull out the feature to be matched against.
008 *
009 * @param <T> The type of the object to be matched
010 * @param <U> The type of the feature to be matched
011 */
012 public abstract class FeatureMatcher<T, U> extends TypeSafeDiagnosingMatcher<T> {
013 private static final ReflectiveTypeFinder TYPE_FINDER = new ReflectiveTypeFinder("featureValueOf", 1, 0);
014 private final Matcher<? super U> subMatcher;
015 private final String featureDescription;
016 private final String featureName;
017
018 /**
019 * Constructor
020 * @param subMatcher The matcher to apply to the feature
021 * @param featureDescription Descriptive text to use in describeTo
022 * @param featureName Identifying text for mismatch message
023 */
024 public FeatureMatcher(Matcher<? super U> subMatcher, String featureDescription, String featureName) {
025 super(TYPE_FINDER);
026 this.subMatcher = subMatcher;
027 this.featureDescription = featureDescription;
028 this.featureName = featureName;
029 }
030
031 /**
032 * Implement this to extract the interesting feature.
033 * @param actual the target object
034 * @return the feature to be matched
035 */
036 protected abstract U featureValueOf(T actual);
037
038 @Override
039 protected boolean matchesSafely(T actual, Description mismatch) {
040 final U featureValue = featureValueOf(actual);
041 if (!subMatcher.matches(featureValue)) {
042 mismatch.appendText(featureName).appendText(" ");
043 subMatcher.describeMismatch(featureValue, mismatch);
044 return false;
045 }
046 return true;
047 };
048
049 @Override
050 public final void describeTo(Description description) {
051 description.appendText(featureDescription).appendText(" ")
052 .appendDescriptionOf(subMatcher);
053 }
054 }