package org.simpleflatmapper.map.impl;
import org.simpleflatmapper.reflect.Getter;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.reflect.ReflectionService;
import org.simpleflatmapper.reflect.Setter;
import org.simpleflatmapper.reflect.meta.PropertyFinder;
import org.simpleflatmapper.reflect.meta.PropertyMatchingScore;
import org.simpleflatmapper.reflect.meta.PropertyMeta;
import org.simpleflatmapper.reflect.meta.PropertyNameMatcher;
import org.simpleflatmapper.util.Function;
import org.simpleflatmapper.util.TypeHelper;
import java.lang.reflect.Type;
import java.util.List;
public class ExtendPropertyFinder<T> extends PropertyFinder<T> {
private static final Runnable EMPTY_CALLBACK = new Runnable() { @Override public void run() { } };
private static final Function<PropertyFinderTransformer, PropertyFinderTransformer> IDENTITY =
new Function<PropertyFinderTransformer, PropertyFinderTransformer>() {
@Override
public PropertyFinderTransformer apply(PropertyFinderTransformer propertyFinderTransformer) {
return propertyFinderTransformer;
}
};
private final PropertyFinder<T> delegate;
private final List<CustomProperty<?, ?>> customProperties;
private final Function<PropertyFinderTransformer, PropertyFinderTransformer> transformerFunction;
public ExtendPropertyFinder(PropertyFinder<T> delegate,
List<CustomProperty<?, ?>> customProperties) {
this(delegate, customProperties, IDENTITY);
}
public ExtendPropertyFinder(PropertyFinder<T> delegate,
List<CustomProperty<?, ?>> customProperties,
Function<PropertyFinderTransformer, PropertyFinderTransformer> transformerFunction) {
super(delegate.getPropertyFilter());
this.delegate = delegate;
this.customProperties = customProperties;
this.transformerFunction = transformerFunction;
}
@Override
public void lookForProperties(final PropertyNameMatcher propertyNameMatcher, final FoundProperty<T> matchingProperties, final PropertyMatchingScore score, final boolean allowSelfReference, final PropertyFinderTransformer propertyFinderTransformer) {
for (CustomProperty<?, ?> property : customProperties) {
if (property.isApplicable(delegate.getOwnerType()) && propertyNameMatcher.matches(property.getName())) {
matchingProperties.found((CustomProperty<T, ?>) property, EMPTY_CALLBACK, score);
}
}
PropertyFinderTransformer newTransformer = transformerFunction.apply(propertyFinderTransformer);
delegate
.lookForProperties(
propertyNameMatcher,
matchingProperties,
score.decrease(1),
allowSelfReference,
newTransformer);
}
@Override
public List<InstantiatorDefinition> getEligibleInstantiatorDefinitions() {
return delegate.getEligibleInstantiatorDefinitions();
}
@SuppressWarnings("unchecked")
@Override
public PropertyFinder<?> getSubPropertyFinder(PropertyMeta<?, ?> owner) {
return delegate.getSubPropertyFinder(owner);
}
@Override
public Type getOwnerType() {
return delegate.getOwnerType();
}
public static class CustomProperty<T, P> extends PropertyMeta<T, P> {
private final Type type;
private final Setter<? super T, ? super P> setter;
private final Getter<? super T, ? extends P> getter;
public CustomProperty(
Type ownerType,
ReflectionService reflectService,
String name,
Type type,
Setter<? super T, ? super P> setter,
Getter<? super T, ? extends P> getter) {
super(name, ownerType, reflectService);
this.type = type;
this.setter = setter;
this.getter = getter;
}
@Override
public Setter<? super T, ? super P> getSetter() {
return setter;
}
@Override
public Getter<? super T, ? extends P> getGetter() {
return getter;
}
@Override
public Type getPropertyType() {
return type;
}
@Override
public String getPath() {
return getName();
}
public boolean isApplicable(Type ownerType) {
return TypeHelper.isAssignable(getOwnerType(), ownerType);
}
@Override
public boolean isConstructorProperty() {
return false;
}
@Override
public boolean isSubProperty() {
return false;
}
@Override
public boolean isSelf() {
return false;
}
@Override
public boolean isValid() {
return true;
}
}
public static class ExtendPropertyFinderTransformer implements PropertyFinder.PropertyFinderTransformer {
private final PropertyFinder.PropertyFinderTransformer propertyFinderTransformer;
private final List<CustomProperty<?, ?>> customProperties;
public ExtendPropertyFinderTransformer(PropertyFinder.PropertyFinderTransformer propertyFinderTransformer, List<CustomProperty<?, ?>> customProperties) {
this.propertyFinderTransformer = propertyFinderTransformer;
this.customProperties = customProperties;
}
@Override
public <T> PropertyFinder<T> apply(PropertyFinder<T> propertyFinder) {
if (propertyFinder instanceof ExtendPropertyFinder) {
throw new IllegalStateException();
}
return new ExtendPropertyFinder<T>(propertyFinderTransformer.apply(propertyFinder), customProperties);
}
}
}