org.simpleflatmapper.reflect.meta.PropertyFinder Maven / Gradle / Ivy
Show all versions of sfm-reflect Show documentation
package org.simpleflatmapper.reflect.meta;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.reflect.getter.NullGetter;
import org.simpleflatmapper.reflect.setter.NullSetter;
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 {
protected final Predicate> propertyFilter;
private final boolean selfScoreFullName;
protected PropertyFinder(Predicate> propertyFilter, boolean selfScoreFullName) {
this.propertyFilter = propertyFilter;
this.selfScoreFullName = selfScoreFullName;
}
public final PropertyMeta findProperty(PropertyNameMatcher propertyNameMatcher, Object[] properties) {
return findProperty(propertyNameMatcher, properties, new DefaultPropertyFinderProbe(propertyNameMatcher));
}
@SuppressWarnings("unchecked")
public final PropertyMeta findProperty(PropertyNameMatcher propertyNameMatcher, Object[] properties, PropertyFinderProbe propertyFinderProbe) {
MatchingProperties matchingProperties = new MatchingProperties(propertyFilter, propertyFinderProbe);
lookForProperties(propertyNameMatcher, properties, matchingProperties, PropertyMatchingScore.newInstance(selfScoreFullName), true, IDENTITY_TRANSFORMER);
return (PropertyMeta)matchingProperties.selectBestMatch();
}
public abstract void lookForProperties(
PropertyNameMatcher propertyNameMatcher,
Object[] properties,
FoundProperty matchingProperties,
PropertyMatchingScore score,
boolean allowSelfReference,
PropertyFinderTransformer propertyFinderTransformer);
public abstract List getEligibleInstantiatorDefinitions();
public abstract PropertyFinder> getSubPropertyFinder(PropertyMeta, ?> owner);
public abstract PropertyFinder> getOrCreateSubPropertyFinder(SubPropertyMeta, ?, ?> subPropertyMeta);
public Predicate> getPropertyFilter() {
return propertyFilter;
}
public abstract Type getOwnerType();
public boolean selfScoreFullName() {
return selfScoreFullName;
}
protected static class MatchingProperties implements FoundProperty {
private final List> matchedProperties = new ArrayList>();
private final Predicate> propertyFilter;
private final PropertyFinderProbe propertyFinderProbe;
public MatchingProperties(Predicate> propertyFilter, PropertyFinderProbe propertyFinderProbe) {
this.propertyFilter = propertyFilter;
this.propertyFinderProbe = propertyFinderProbe;
}
@Override
public > void found(P propertyMeta,
Runnable selectionCallback,
PropertyMatchingScore score) {
if (propertyFilter.test(propertyMeta)) {
propertyFinderProbe.found(propertyMeta, score);
matchedProperties.add(new MatchedProperty(propertyMeta, selectionCallback, score));
}
}
public PropertyMeta selectBestMatch() {
if (matchedProperties.isEmpty()) return null;
Collections.sort(matchedProperties);
MatchedProperty selectedMatchedProperty = matchedProperties.get(0);
selectedMatchedProperty.select();
propertyFinderProbe.select(selectedMatchedProperty.propertyMeta);
return selectedMatchedProperty.propertyMeta;
}
}
private static class MatchedProperty> implements Comparable>{
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 o) {
int i = this.score.compareTo(o.score);
if (i == 0) {
return compare(this.propertyMeta, o.propertyMeta);
} else {
return i;
}
}
private int compare(PropertyMeta, ?> p1, PropertyMeta, ?> p2) {
if (p1.isConstructorProperty()) {
if (!p2.isConstructorProperty()) {
return -1;
}
} else if (p2.isConstructorProperty()) {
return 1;
} else if (!p1.isSelf()) {
if (p2.isSelf()) {
return -1;
}
} else if (!p2.isSelf()) {
return 1;
} else if (!p1.isSubProperty()) {
if (p2.isSubProperty()) {
return -1;
}
} else if (!p2.isSubProperty()) {
return 1;
}
return getterSetterCompare(p1, p2);
}
private int getterSetterCompare(PropertyMeta, ?> p1, PropertyMeta, ?> p2) {
return nbGetterSetter(p2) - nbGetterSetter(p1);
}
private int nbGetterSetter(PropertyMeta, ?> p) {
int c = 0;
if (!NullGetter.isNull(p.getGetter())) {
c++;
}
if (!NullSetter.isNull(p.getSetter())) {
c++;
}
return c;
}
public void select() {
if (selectionCallback != null) selectionCallback.run();
}
@Override
public String toString() {
return "MatchedProperty{" +
"propertyMeta=" + propertyMeta +
", score=" + score + ":" + nbGetterSetter(propertyMeta) +
", getter=" + propertyMeta.getGetter() +
", setter=" + propertyMeta.getSetter() +
'}';
}
}
public interface FoundProperty {
> void found(P propertyMeta,
Runnable selectionCallback,
PropertyMatchingScore score);
}
public void manualMatch(PropertyMeta, ?> prop) {
if (prop.isSubProperty()) {
SubPropertyMeta subPropertyMeta = (SubPropertyMeta) prop;
PropertyMeta ownerProperty = subPropertyMeta.getOwnerProperty();
manualMatch(ownerProperty);
PropertyFinder> subPropertyFinder = getOrCreateSubPropertyFinder(subPropertyMeta);
subPropertyFinder.manualMatch(subPropertyMeta.getSubProperty());
}
}
public interface PropertyFinderTransformer {
PropertyFinder apply(PropertyFinder propertyFinder);
}
public static PropertyFinderTransformer IDENTITY_TRANSFORMER = new PropertyFinderTransformer() {
@Override
public PropertyFinder apply(PropertyFinder propertyFinder) {
return propertyFinder;
}
@Override
public String toString() {
return "IDENTITY_TRANSFORMER";
}
};
public interface PropertyFinderProbe {
void found(PropertyMeta propertyMeta, PropertyMatchingScore score);
void select(PropertyMeta propertyMeta);
}
public static class DefaultPropertyFinderProbe implements PropertyFinderProbe {
private static final boolean DEBUG = Boolean.getBoolean("org.simpleflatmapper.probe.propertyFinder");
private final PropertyNameMatcher propertyNameMatcher;
public DefaultPropertyFinderProbe(PropertyNameMatcher propertyNameMatcher) {
this.propertyNameMatcher = propertyNameMatcher;
}
@Override
public void found(PropertyMeta propertyMeta, PropertyMatchingScore score) {
if (DEBUG) {
System.out.println("PropertyFinder for '" + propertyNameMatcher + "' - found " + score + " " + propertyMeta.getPath());
}
}
@Override
public void select(PropertyMeta propertyMeta) {
if (DEBUG) {
System.out.println("PropertyFinder for '" + propertyNameMatcher + "' - select " + propertyMeta.getPath());
}
}
}
}