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

org.sfm.reflect.meta.ObjectPropertyFinder Maven / Gradle / Ivy

package org.sfm.reflect.meta;

import org.sfm.map.MapperBuildingException;
import org.sfm.reflect.ConstructorDefinition;
import org.sfm.reflect.ConstructorParameter;

import java.util.*;

final class ObjectPropertyFinder implements PropertyFinder {
	
	private final List> eligibleConstructorDefinitions;
	private final ObjectClassMeta classMeta;
	private final Map> subPropertyFinders = new HashMap>();

    ObjectPropertyFinder(ObjectClassMeta classMeta) throws MapperBuildingException {
		this.classMeta = classMeta;
		this.eligibleConstructorDefinitions = classMeta.getConstructorDefinitions() != null ? new ArrayList>(classMeta.getConstructorDefinitions()) : null;
	}

	/* (non-Javadoc)
	 * @see org.sfm.reflect.PropertyFinder#findProperty(org.sfm.utils.PropertyNameMatcher)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public  PropertyMeta findProperty(final PropertyNameMatcher propertyNameMatcher) {
		// check for constructor
		PropertyMeta prop = lookForConstructor(propertyNameMatcher);

		if (prop == null) {
			prop = lookForProperty(propertyNameMatcher);
			
			if (prop == null) {
				prop = lookForSubPropertyInConstructors(propertyNameMatcher);
				
				if (prop == null) {
					prop = lookForSubProperty(propertyNameMatcher);
					
				} else {
					ConstructorPropertyMeta constructorProperty = (ConstructorPropertyMeta) ((SubPropertyMeta)prop).getOwnerProperty();
					removeNonMatching(constructorProperty.getConstructorParameter());
				}
			}
			
		} else {
			ConstructorPropertyMeta constructorProperty = (ConstructorPropertyMeta) prop;
			removeNonMatching(constructorProperty.getConstructorParameter());
		}

		return (PropertyMeta) prop;
	}

    @SuppressWarnings("unchecked")
    @Override
    public  ConstructorPropertyMeta findConstructor(ConstructorDefinition constructorDefinition) {
        ConstructorPropertyMeta prop = lookForConstructor(constructorDefinition);

        if (prop != null) {
            removeNonMatching(prop.getConstructorParameter());
        }

        return (ConstructorPropertyMeta) prop;
    }



    private ConstructorPropertyMeta lookForConstructor(final ConstructorDefinition constructorDefinition) {
        if (classMeta.getConstructorProperties() != null) {
            ConstructorParameter parameter = constructorDefinition.getParameters()[0];
            for (ConstructorPropertyMeta prop : classMeta.getConstructorProperties()) {
                if (prop.getName().equals(parameter.getName())
                        && prop.getConstructorParameter().equals(parameter)) {
                    return prop;
                }
            }
        }

        return null;
    }

    private ConstructorPropertyMeta lookForConstructor(final PropertyNameMatcher propertyNameMatcher) {
		if (classMeta.getConstructorProperties() != null) {
			for (ConstructorPropertyMeta prop : classMeta.getConstructorProperties()) {
				if (propertyNameMatcher.matches(getColumnName(prop))
						&& hasConstructorMatching(prop.getConstructorParameter())) {
					return prop;
				}
			}
		}
		
		return null;
	}

	private PropertyMeta lookForProperty(final PropertyNameMatcher propertyNameMatcher) {
		for (PropertyMeta prop : classMeta.getProperties()) {
			if (propertyNameMatcher.matches(getColumnName(prop))) {
				return prop;
			}
		}
		return null;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private PropertyMeta lookForSubPropertyInConstructors(final PropertyNameMatcher propertyNameMatcher) {
		if (classMeta.getConstructorProperties() != null) {
			for (ConstructorPropertyMeta prop : classMeta.getConstructorProperties()) {
				PropertyNameMatcher subPropMatcher = propertyNameMatcher.partialMatch(getColumnName(prop));
				if (subPropMatcher != null && hasConstructorMatching(prop.getConstructorParameter())) {
					PropertyMeta subProp = lookForSubProperty(subPropMatcher, prop);
					if (subProp != null) {
						return new SubPropertyMeta(classMeta.getReflectionService(), prop, subProp);
					}
				}
			}
		}
		return null;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private PropertyMeta lookForSubProperty(final PropertyNameMatcher propertyNameMatcher) {
		for (PropertyMeta prop : classMeta.getProperties()) {
			PropertyNameMatcher subPropMatcher = propertyNameMatcher.partialMatch(getColumnName(prop));
			if (subPropMatcher != null) {
				PropertyMeta subProp =  lookForSubProperty(subPropMatcher, prop);
				if (subProp != null) {
					return new SubPropertyMeta(classMeta.getReflectionService(), prop, subProp);
				}
			}
		}

		return null;
	}
	
	private PropertyMeta lookForSubProperty(
			final PropertyNameMatcher propertyNameMatcher,
			final PropertyMeta prop) {
		PropertyFinder subPropertyFinder = subPropertyFinders.get(getColumnName(prop));
		if (subPropertyFinder == null) {
			subPropertyFinder = prop.getClassMeta().newPropertyFinder();
			subPropertyFinders.put(prop.getName(), subPropertyFinder);
		}

		return subPropertyFinder.findProperty(propertyNameMatcher);
	}

    private String getColumnName(PropertyMeta prop) {
        return this.classMeta.getAlias(prop.getName());
    }


    private void removeNonMatching(ConstructorParameter param) {
		ListIterator> li = eligibleConstructorDefinitions.listIterator();
		while(li.hasNext()){
			ConstructorDefinition cd = li.next();
			if (!cd.hasParam(param)) {
				li.remove();
			}
		}
	}
	
	private boolean hasConstructorMatching(ConstructorParameter param) {
		for(ConstructorDefinition cd : eligibleConstructorDefinitions) {
			if (cd.hasParam(param)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public List> getEligibleConstructorDefinitions() {
		return eligibleConstructorDefinitions;
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy