All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simpleflatmapper.reflect.meta.PropertyFinder Maven / Gradle / Ivy

package org.simpleflatmapper.reflect.meta;

import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.reflect.TypeAffinity;
import org.simpleflatmapper.reflect.getter.NullGetter;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.util.ConstantPredicate;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.TypeHelper;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public abstract class PropertyFinder {
	private final boolean selfScoreFullName;

	protected PropertyFinder(boolean selfScoreFullName) {
		this.selfScoreFullName = selfScoreFullName;
	}

	public final  PropertyMeta findProperty(PropertyNameMatcher propertyNameMatcher, Object[] properties, TypeAffinity typeAffinity, PropertyFilter propertyFilter) {
		return findProperty(propertyNameMatcher, properties, toTypeAffinityScorer(typeAffinity), propertyFilter);
	}
	public final  PropertyMeta findProperty(PropertyNameMatcher propertyNameMatcher, Object[] properties, TypeAffinityScorer typeAffinity, PropertyFilter propertyFilter) {
		return findProperty(propertyNameMatcher, properties, typeAffinity, new DefaultPropertyFinderProbe(propertyNameMatcher), propertyFilter);
	}

	public final  PropertyMeta findProperty(PropertyNameMatcher propertyNameMatcher, Object[] properties, TypeAffinity typeAffinity, PropertyFinderProbe propertyFinderProbe, PropertyFilter propertyFilter) {
		return findProperty(propertyNameMatcher, properties, toTypeAffinityScorer(typeAffinity), propertyFinderProbe, propertyFilter);
	}
		@SuppressWarnings("unchecked")
	public final  PropertyMeta findProperty(PropertyNameMatcher propertyNameMatcher, Object[] properties, TypeAffinityScorer typeAffinity, PropertyFinderProbe propertyFinderProbe, PropertyFilter propertyFilter) {
		MatchingProperties matchingProperties = new MatchingProperties(propertyFinderProbe);
		lookForProperties(propertyNameMatcher, properties, matchingProperties, PropertyMatchingScore.newInstance(selfScoreFullName), true, IDENTITY_TRANSFORMER,  typeAffinity, propertyFilter);
		return (PropertyMeta)matchingProperties.selectBestMatch();
	}

	private TypeAffinityScorer toTypeAffinityScorer(TypeAffinity typeAffinity) {
		return new TypeAffinityScorer(typeAffinity);
	}

	public abstract void lookForProperties(
            PropertyNameMatcher propertyNameMatcher,
            Object[] properties,
            FoundProperty matchingProperties,
            PropertyMatchingScore score,
            boolean allowSelfReference,
            PropertyFinderTransformer propertyFinderTransformer,
            TypeAffinityScorer typeAffinityScorer,
			PropertyFilter propertyFilter);


	public abstract List getEligibleInstantiatorDefinitions();

    public abstract PropertyFinder getSubPropertyFinder(PropertyMeta owner);
	public abstract PropertyFinder getOrCreateSubPropertyFinder(SubPropertyMeta subPropertyMeta);

	public abstract Type getOwnerType();

	public boolean selfScoreFullName() {
		return selfScoreFullName;
	}

	protected static class MatchingProperties implements FoundProperty {
		private final List> matchedProperties = new ArrayList>();
		private final PropertyFinderProbe propertyFinderProbe;

		public MatchingProperties(PropertyFinderProbe propertyFinderProbe) {
			this.propertyFinderProbe = propertyFinderProbe;
		}

		@Override
		public 

> void found(P propertyMeta, Runnable selectionCallback, PropertyMatchingScore score, TypeAffinityScorer typeAffinityScorer) { propertyFinderProbe.found(propertyMeta, score); matchedProperties.add(new MatchedProperty(propertyMeta, selectionCallback, score, propertyMeta.typeAffinityScore(typeAffinityScorer))); } 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; } } public static class MatchedProperty> implements Comparable>{ private final P propertyMeta; private final Runnable selectionCallback; private final PropertyMatchingScore score; private final int typeAffinityScore; public MatchedProperty(P propertyMeta, Runnable selectionCallback, PropertyMatchingScore score, int typeAffinityScore) { this.propertyMeta = propertyMeta; this.selectionCallback = selectionCallback; this.score = score; this.typeAffinityScore = typeAffinityScore; } public PropertyMatchingScore getScore() { return score; } public P getPropertyMeta() { return propertyMeta; } @Override public int compareTo(MatchedProperty o) { int i = this.score.compareTo(o.score); if (i == 0) { i = (typeAffinityScore > o.typeAffinityScore) ? -1 : ((typeAffinityScore == o.typeAffinityScore) ? 0 : 1); if (i == 0) { return compare(this.propertyMeta, o.propertyMeta); } else { return i; } } 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.getPath() + ", score=" + score + ":" + nbGetterSetter(propertyMeta) + ", getter=" + propertyMeta.getGetter() + ", setter=" + propertyMeta.getSetter() + '}'; } } public static class TypeAffinityScorer { private Class[] affinities; public TypeAffinityScorer(TypeAffinity typeAffinity) { if (typeAffinity == null || typeAffinity.getAffinities() == null) { affinities = new Class[0]; } else { affinities = typeAffinity.getAffinities(); } } public TypeAffinityScorer(Class[] affinities) { this.affinities = affinities; } public int score(Type type) { for(int i = 0; i < affinities.length; i++) { if (TypeHelper.isAssignable(type, affinities[i])) { return affinities.length - i; } } return -1; } } public interface FoundProperty {

> void found(P propertyMeta, Runnable selectionCallback, PropertyMatchingScore score, TypeAffinityScorer typeAffinityScorer); } 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()); } } } public static final class PropertyFilter { private final Predicate> propertyMetaPredicate; private final Predicate> pathMetaPredicate; private static final PropertyFilter TRUE_FILTER = new PropertyFilter(ConstantPredicate.>truePredicate(), ConstantPredicate.>truePredicate()); public PropertyFilter(Predicate> predicate) { this.propertyMetaPredicate = predicate; this.pathMetaPredicate = predicate; } public PropertyFilter(Predicate> propertyMetaPredicate, Predicate> pathMetaPredicate) { this.propertyMetaPredicate = propertyMetaPredicate; this.pathMetaPredicate = pathMetaPredicate; } public static PropertyFilter trueFilter() { return TRUE_FILTER; } public boolean testProperty(PropertyMeta propertyMeta) { return propertyMetaPredicate.test(propertyMeta); } public boolean testPath(PropertyMeta propertyMeta) { return pathMetaPredicate.test(propertyMeta); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy