    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    }