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 }