package org.simpleflatmapper.reflect.meta;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.util.Predicate;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public abstract class PropertyFinder<T> {
protected final Predicate<PropertyMeta<?, ?>> propertyFilter;
protected PropertyFinder(Predicate<PropertyMeta<?, ?>> propertyFilter) {
this.propertyFilter = propertyFilter;
}
@SuppressWarnings("unchecked")
public final <E> PropertyMeta<T, E> findProperty(PropertyNameMatcher propertyNameMatcher) {
MatchingProperties matchingProperties = new MatchingProperties(propertyFilter);
lookForProperties(propertyNameMatcher, matchingProperties, PropertyMatchingScore.INITIAL, true, IDENTITY_TRANSFORMER);
return (PropertyMeta<T, E>)matchingProperties.selectBestMatch();
}
public abstract void lookForProperties(
PropertyNameMatcher propertyNameMatcher,
FoundProperty<T> matchingProperties,
PropertyMatchingScore score,
boolean allowSelfReference,
PropertyFinderTransformer propertyFinderTransformer);
public abstract List<InstantiatorDefinition> getEligibleInstantiatorDefinitions();
public abstract PropertyFinder<?> getSubPropertyFinder(PropertyMeta<?, ?> owner);
public Predicate<PropertyMeta<?, ?>> getPropertyFilter() {
return propertyFilter;
}
public abstract Type getOwnerType();
protected static class MatchingProperties<T> implements FoundProperty<T> {
private final List<MatchedProperty<T, ?>> matchedProperties = new ArrayList<MatchedProperty<T, ?>>();
private final Predicate<PropertyMeta<?, ?>> propertyFilter;
public MatchingProperties(Predicate<PropertyMeta<?, ?>> propertyFilter) {
this.propertyFilter = propertyFilter;
}
@Override
public <P extends PropertyMeta<T, ?>> void found(P propertyMeta,
Runnable selectionCallback,
PropertyMatchingScore score) {
if (propertyFilter.test(propertyMeta)) {
matchedProperties.add(new MatchedProperty<T, P>(propertyMeta, selectionCallback, score));
}
}
public PropertyMeta<T, ?> selectBestMatch() {
if (matchedProperties.isEmpty()) return null;
Collections.sort(matchedProperties);
MatchedProperty<T, ?> selectedMatchedProperty = matchedProperties.get(0);
selectedMatchedProperty.select();
return selectedMatchedProperty.propertyMeta;
}
}
private static class MatchedProperty<T, P extends PropertyMeta<T, ?>> implements Comparable<MatchedProperty<T, ?>>{
private final P propertyMeta;
private final Runnable selectionCallback;
private final PropertyMatchingScore score;
private MatchedProperty(P propertyMeta, Runnable selectionCallback, PropertyMatchingScore score) {
this.propertyMeta = propertyMeta;
this.selectionCallback = selectionCallback;
this.score = score;
}
@Override
public int compareTo(MatchedProperty<T, ?> o) {
return this.score.compareTo(o.score);
}
public void select() {
if (selectionCallback != null) selectionCallback.run();
}
}
public interface FoundProperty<T> {
<P extends PropertyMeta<T, ?>> void found(P propertyMeta,
Runnable selectionCallback,
PropertyMatchingScore score);
}
public interface PropertyFinderTransformer {
<T> PropertyFinder<T> apply(PropertyFinder<T> propertyFinder);
}
public static PropertyFinderTransformer IDENTITY_TRANSFORMER = new PropertyFinderTransformer() {
@Override
public <T> PropertyFinder<T> apply(PropertyFinder<T> propertyFinder) {
return propertyFinder;
}
@Override
public String toString() {
return "IDENTITY_TRANSFORMER";
}
};
}