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.HashMap; import java.util.List; import java.util.Map; public abstract class AbstractIndexPropertyFinder<T> extends PropertyFinder<T> { protected final ClassMeta<T> classMeta; protected final List<IndexedElement<T, ?>> elements; public AbstractIndexPropertyFinder(ClassMeta<T> classMeta, Predicate<PropertyMeta<?, ?>> propertyFilter) { super(propertyFilter); this.elements = new ArrayList<IndexedElement<T, ?>>(); this.classMeta = classMeta; } @SuppressWarnings("unchecked") @Override public void lookForProperties( PropertyNameMatcher propertyNameMatcher, FoundProperty<T> matchingProperties, PropertyMatchingScore score, boolean allowSelfReference, PropertyFinderTransformer propertyFinderTransformer) { IndexedColumn indexedColumn = propertyNameMatcher.matchIndex(); if (indexedColumn != null) { lookForAgainstColumn(indexedColumn, matchingProperties, score, propertyFinderTransformer); } else { extrapolateIndex(propertyNameMatcher, matchingProperties, score.decrease(1), propertyFinderTransformer); speculativeMatching(propertyNameMatcher, matchingProperties, score.shift(), propertyFinderTransformer); } } @SuppressWarnings("unchecked") protected void lookForAgainstColumn(IndexedColumn indexedColumn, final FoundProperty<T> matchingProperties, PropertyMatchingScore score, PropertyFinderTransformer propertyFinderTransformer) { if (indexedColumn == null || !isValidIndex(indexedColumn)) { // no index found return; } final IndexedElement<T, ?> indexedElement = getIndexedElement(indexedColumn); if (indexedColumn.getSubPropertyNameMatcher() == null) { matchingProperties.found(indexedElement.getPropertyMeta(), new Runnable() { @Override public void run() { if (!indexedElement.hasProperty(SelfPropertyMeta.PROPERTY_PATH)) { indexedElement.addProperty(SelfPropertyMeta.PROPERTY_PATH); } } }, score); return ; } final PropertyFinder<?> eltPropertyFinder = indexedElement.getPropertyFinder(); if (eltPropertyFinder == null) { return; } propertyFinderTransformer.apply(eltPropertyFinder) .lookForProperties(indexedColumn.getSubPropertyNameMatcher(), new FoundProperty() { @Override public void found(final PropertyMeta propertyMeta, final Runnable selectionCallback, final PropertyMatchingScore score) { PropertyMeta subProperty; if (propertyMeta.isSelf()) { subProperty = indexedElement.getPropertyMeta(); } else { subProperty = new SubPropertyMeta(classMeta.getReflectionService(), indexedElement.getPropertyMeta(), propertyMeta); } matchingProperties.found(subProperty, new Runnable() { @Override public void run() { selectionCallback.run(); indexedElement.addProperty(propertyMeta); } }, score); } }, score, true, propertyFinderTransformer); } private void speculativeMatching(PropertyNameMatcher propertyNameMatcher, FoundProperty foundProperty, PropertyMatchingScore score, PropertyFinderTransformer propertyFinderTransformer) { // try to match against prefix PropertyNameMatch speculativeMatch = propertyNameMatcher.speculativeMatch(); if (speculativeMatch != null) { extrapolateIndex(speculativeMatch.getLeftOverMatcher(), foundProperty, score, propertyFinderTransformer); } } protected abstract boolean isValidIndex(IndexedColumn indexedColumn); protected abstract <E> IndexedElement<T,?> getIndexedElement(IndexedColumn indexedColumn); protected abstract void extrapolateIndex(PropertyNameMatcher propertyNameMatcher, FoundProperty foundProperty, PropertyMatchingScore score, PropertyFinderTransformer propertyFinderTransformer); @Override public List<InstantiatorDefinition> getEligibleInstantiatorDefinitions() { return classMeta.getInstantiatorDefinitions(); } @Override public Type getOwnerType() { return classMeta.getType(); } @Override public PropertyFinder<?> getSubPropertyFinder(PropertyMeta<?, ?> owner) { for(IndexedElement<T, ?> ie : elements) { if (ie.getPropertyMeta().equals(owner)) { return ie.getPropertyFinder(); } } throw new IllegalArgumentException("Unexpected owner " + owner); } }