package tc.oc.commons.core.reflect; import java.util.HashMap; import java.util.Map; import com.google.common.base.Function; /** * Find the value(s) of a heritable, shadowable property, given a function * to extract the property from a type. After traversal, the {@link #values()} map * will contain the most derived values found in the entire ancestry. No type * in the map will be assignable to any other type in the map. * * The given function is applied to each visited type. If the function returns a non-null value, * it is saved in the result map, and the visitor returns false, indicating that traversal * should NOT continue along the current ancestral line. If the function returns null, * the visitor returns true to continue traversing. */ public class InheritablePropertyVisitor<T> extends ReflectionVisitor { private final Map<Class<?>, T> values = new HashMap<>(); private final Function<Class<?>, T> extractor; public InheritablePropertyVisitor(Function<Class<?>, T> extractor) { this.extractor = extractor; } public Map<Class<?>, T> values() { return values; } @Override public boolean visit(Class<?> cls) { T value = extractor.apply(cls); if(value != null) { for(Class<?> prior : values.keySet()) { if(cls.isAssignableFrom(prior)) { // If there is already a value for a more derived type, bail out return false; } else if(prior.isAssignableFrom(cls)) { // If we find any values for less derived types, remove them values.remove(prior); } } values.put(cls, value); return false; } return super.visit(cls); } }