Package br.com.bfmapper

Source Code of br.com.bfmapper.Mapping

package br.com.bfmapper;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.ClassUtils;
import org.springframework.beans.BeanUtils;

import br.com.bfmapper.transformer.ComplexTransformer;
import br.com.bfmapper.transformer.EnumTransformer;
import br.com.bfmapper.transformer.NumberTransformer;
import br.com.bfmapper.transformer.SimpleTransformer;
import br.com.bfmapper.transformer.Transformer;
import br.com.bfmapper.util.ReflectionUtils;

public class Mapping implements Serializable {

  private static final long serialVersionUID = 4371444630053025368L;
 
  private MappingContext mappingContext = new MappingContext();
 
  public synchronized  Mapping apply(Object o) {
    this.setAppliedObjectItem(new AppliedObject(o));
    return this;
  }
 
  public synchronized Mapping applyOn(Object o, String attribute) {
    this.setAppliedObjectItem(new AppliedObject(AppliedType.APPLY_ON, o, attribute));
    return this;
  }
 
  private synchronized void setAppliedObjectItem(AppliedObject appliedObject) {
    this.mappingContext.getAppliedObjects().add(appliedObject);
  }
 
  public synchronized <T> T to(T target) {
    if (target == null) {
      return null;
    }
   
    for (AppliedObject appliedObject : this.mappingContext.getAppliedObjects()) {
      Object appliedObjectSource = appliedObject.getSourceObject();
     
      if (appliedObjectSource == null) {
        continue;
      }
     
      this.addToCache(appliedObjectSource, target);
     
      if (appliedObject.getAppliedType().equals(AppliedType.APPLY)) {
        to( target, appliedObjectSource );       
     

      if (appliedObject.getAppliedType().equals(AppliedType.APPLY_ON)) {
        this.applyConverterOnFieldName(appliedObjectSource, target, appliedObject.getAttribute());
     
    }
    this.mappingContext.clear();
    return target;
  }

    private <T> void to( T target, Object appliedObjectSource )
    {
        if (appliedObjectSource.getClass().equals(target.getClass())) {
          this.evalEqualsProperties(appliedObjectSource, target, null);                   
        } else {
          Converter converter = this.getConverter(appliedObjectSource.getClass(), target.getClass());
          if (converter != null) {
            this.applyConverter(converter, appliedObjectSource, target);
          } else {
            this.applyConverterOnField(appliedObjectSource, target);
          }
        }
    }

  private void addToCache(Object source, Object target) {
    this.mappingContext.getCachedObjects().put(source, target);
  }
 
  public <T> T to(Class<T> target) {
    T returnValue = null;
    boolean validateApply = false;
   
    for (AppliedObject appliedObject : this.mappingContext.getAppliedObjects()) {
      Object appliedObjectSource = appliedObject.getSourceObject();
      /* se pelo menos um appliedObjectSource for diferente de null, valida a chamada da conversão */
      if (appliedObjectSource != null) {
        validateApply = true;
        break;
      }
    } 

    if (validateApply) {
      returnValue = target.cast(this.to(this.instanceFactory(target)));
    }
   
    return returnValue;
  }
 
  @SuppressWarnings("unchecked")
    public <T> T deepClone(T value) {
      return (T) this.apply(value).to(value.getClass());
  }
 
  public <T,E extends Collection<T>> Collection<T> toCollection(Class<T> target, Class<E> targetCollection) {
      E col  = instanceFactory( targetCollection );
     
      return toCollection( target, col );
  }

  public <T,E extends Collection<T>> E toCollection( Class<T> target, E col )
    {
        for ( AppliedObject appliedObj : this.mappingContext.getAppliedObjects() )
        {
          Object src = appliedObj.getSourceObject();
            if(src instanceof Collection) {
              Collection<?> srcCol = (Collection<?>) src;
              for ( Object object : srcCol )
                {
                  T targetObject = instanceFactory( target );
                  to(targetObject , object );
                  col.add(targetObject);
                }
          }else {
              col.add( to( target ) );
          }
        }
       
        this.mappingContext.clear();
     
      return col;
    }
 
    public <T> Collection<T> toCollection(Class<T> target) {
      return toCollection( target, ArrayList.class );
  }
 
  private <E> E  instanceFactory(Class<E> target) {
    E object = null;
    try {
      object = ReflectionUtils.newInstance(target);
    } catch (Exception e) {
      throw new IllegalArgumentException(e);
    }
    return object;
  }

  private Object applyConverter(Converter converter, Object source, Object target) {
    for (Converter.Property property : converter.getProperties()) {
      this.resolveProperty(source, target, property);
    }

    this.evalEqualsProperties(source, target, converter);
   
    for (CustomTransformer customTransformer: converter.getCustomTransfomers()) {
        customTransformer.apply(source, target);
    }
   
    return target;
  }
 
  private void resolveProperty(Object source, Object target, Converter.Property property) {
    String targetProperty = property.getTargetProperty(source.getClass());
   
    if (targetProperty != null) {
      Object value = property.getSourceValue(source);
     
      if (property instanceof Converter.PropertyMapping) {
        Converter.PropertyMapping propertyMapping = (Converter.PropertyMapping) property;
        if (!propertyMapping.isShallowCopy()) {
            value = this.resolveValue(source, target, propertyMapping.getSourceProperty(source.getClass()), targetProperty, value, propertyMapping.getTransformer());   
        }
      }

      try {
        if (value != null) {
          PropertyDescriptor targetPropertyDescriptor = BeanUtils.getPropertyDescriptor(target.getClass(), targetProperty);
         
          if (targetPropertyDescriptor == null || targetPropertyDescriptor.getWriteMethod() != null) {
            try {
                ReflectionUtils.invokeRecursiveSetter(target, targetProperty, value);   
                        } catch (Exception e) {
                            //hack to set collections without set method in chained properties
                            if (ClassUtils.isAssignable(value.getClass(), Collection.class) && targetProperty.contains(".")) {
                                Object chainedObjectTarget = ReflectionUtils.prepareInvokeRecursiveSetter(target, targetProperty, value);
                                String lastProperty = targetProperty.substring(targetProperty.lastIndexOf(".") + 1);
                                setCollectionValueFromReadMethod(BeanUtils.getPropertyDescriptor(chainedObjectTarget.getClass(), lastProperty), chainedObjectTarget, value);     
                            }
                        }
          } else if (ClassUtils.isAssignable(value.getClass(), Collection.class)) {
            setCollectionValueFromReadMethod(targetPropertyDescriptor, target, value);
           
          }
        }
      } catch (Exception e) {
        throw new IllegalArgumentException(e);
      }
    }
  }

  private Collection<?> getInstanceFromCollectionType(Class<?> collectionClass) {
    Class<?> collectionClassResult = null;
    if (ClassUtils.isAssignable(collectionClass, Set.class)) {
      collectionClassResult = HashSet.class;
    } else {
      collectionClassResult = ArrayList.class;
    }
   
    return ReflectionUtils.newInstance(collectionClassResult);
  }

  private void applyConverterOnField(Object source, Object target) {
    Converter converter = null;

    PropertyDescriptor targetProperty = null;
   
    for (PropertyDescriptor property: BeanUtils.getPropertyDescriptors(target.getClass())) {
      converter = this.getConverter(source.getClass(), property.getPropertyType());
     
      if (converter != null) {
        targetProperty = property;
        break;
      }
    }
   
    if (converter != null) {
      try {
        Object instance = ReflectionUtils.invokeRecursiveGetter(target, targetProperty.getName());
        if (instance == null) {
          instance = ReflectionUtils.newInstance(targetProperty.getPropertyType())
        }
       
        ReflectionUtils.invokeRecursiveSetter(target, targetProperty.getName(), this.applyConverter(converter, source, instance));
      } catch (Exception e) {
        throw new IllegalArgumentException(e);
      }
    }
  }
 
  private void applyConverterOnFieldName(Object source, Object target, String fieldName) {
    try {
      Class<?> fieldType = ReflectionUtils.invokeRecursiveType(target, fieldName);
      Converter converter = this.getConverter(source.getClass(), fieldType);
     
      if (converter != null) {
          Object fieldValue = ReflectionUtils.invokeRecursiveGetter(target, fieldName);
          if (fieldValue == null) {
              fieldValue = ReflectionUtils.newInstance(fieldType);
          }
         
        ReflectionUtils.invokeRecursiveSetter(target, fieldName, this.applyConverter(converter, source, fieldValue));
      }
    } catch (Exception e) {
      throw new IllegalArgumentException(e);
    }
  }
 
  private Converter getConverter(Class<?> sourceClass, Class<?> targetClass) {
    Converter converterResult = null;
   
    for (Converter converter : MappingRules.getConverters()) {
      if (isValidConverter(converter, sourceClass, targetClass)) {
        converterResult = converter;
        break;
      }
    }
    return converterResult;
  }
 
  private boolean isValidConverter(Converter converter, Class<?> sourceClass, Class<?> targetClass) {
    sourceClass = ReflectionUtils.getTargetClass(sourceClass);
    targetClass = ReflectionUtils.getTargetClass(targetClass);
   
    Class<?> sourceConverter = converter.getSourceClass();
    Class<?> targetConverter = converter.getTargetClass();
    return (sourceClass.equals(sourceConverter) && targetClass.equals(targetConverter)) || (targetClass.equals(sourceConverter) && sourceClass.equals(targetConverter));   
  }
 
  private void evalEqualsProperties(Object source, Object target, Converter converter) {
    String targetPropertyName = null;
    Object value = null;
    try {
 
      for(PropertyDescriptor targetPropertyDescriptor : BeanUtils.getPropertyDescriptors(target.getClass())) {
        targetPropertyName = targetPropertyDescriptor.getName();

        if (targetPropertyName.equals("class") || (converter != null && (converter.containsProperty(source.getClass(), targetPropertyName) ||
                converter.getExcludedProperties().contains(targetPropertyName)))) {
          continue;
        }

        PropertyDescriptor sourcePropertyDescriptor = BeanUtils.getPropertyDescriptor(source.getClass(), targetPropertyName);

        if (sourcePropertyDescriptor == null) {
          continue;
        }

        Class<?> sourcePropertyClass = sourcePropertyDescriptor.getPropertyType();
        Class<?> targetPropertyClass = targetPropertyDescriptor.getPropertyType();
        value = sourcePropertyDescriptor.getReadMethod().invoke(source);

                if (!this.isSimpleType(sourcePropertyClass, targetPropertyClass)) {
          value = this.resolveValue(source, target, targetPropertyName, targetPropertyName, value, null);
        }

        /* the value of the targetProperty won't be replaced by the value of the sourceProperty in case it's null */
        if (value != null) {
          if (targetPropertyDescriptor.getWriteMethod() != null) {
            targetPropertyDescriptor.getWriteMethod().invoke(target, value);
          } else if (ClassUtils.isAssignable(targetPropertyClass, Collection.class)) {
              setCollectionValueFromReadMethod(targetPropertyDescriptor, target, value);
          }
        }
      }
    } catch (Exception e) {
      throw new IllegalArgumentException("Converting error. \nSource: " + source + "\n" +
          "Target: " + target + "\nTarget Property: " + targetPropertyName + "\nConverter: " + converter + "\nValue: " + value, e);
    }
  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
    private void setCollectionValueFromReadMethod(PropertyDescriptor targetPropertyDescriptor, Object target, Object value) {
      /* generated beans by webservices don't have set for collections */
      try {
            ((Collection<?>)targetPropertyDescriptor.getReadMethod().invoke(target)).addAll((Collection)value);
        } catch (Exception e) {
            throw new IllegalArgumentException("illegal attribute from " + target.getClass().getSimpleName());
        }     
  }
 
  private boolean isSimpleType(Class<?> sourceClass, Class<?> targetClass) {
    return ReflectionUtils.isSimpleType(sourceClass) && ReflectionUtils.isPrimitiveWrapperAssignable(sourceClass, targetClass);
  }
 
  private Object resolveValue(Object source, Object target, String sourceProperty, String targetProperty, Object value, Transformer transformer) {
        Class<?> sourceClassAttribute = ReflectionUtils.invokeRecursiveType(source, sourceProperty);
      Class<?> targetClassAttribute = ReflectionUtils.invokeRecursiveType(target, targetProperty);
   
    if (ClassUtils.isAssignable(targetClassAttribute, Collection.class) && value instanceof Collection<?>) {
      value = this.resolveCollectionValue(source, target, sourceProperty, targetProperty, targetClassAttribute, value, transformer);
   
    } else if (transformer != null || ReflectionUtils.isSimpleType(sourceClassAttribute) || ReflectionUtils.isSimpleType(targetClassAttribute)) {
      value = this.resolveSimpleValue(source, target, targetClassAttribute, value, transformer);
     
    } else if (value != null) {
      Converter converter = this.getConverter(sourceClassAttribute, targetClassAttribute);
        if (converter != null) {
            try {
                Object targetInstance = this.mappingContext.getCachedObjects().get(value);

                if (targetInstance == null) {
                  targetInstance = ReflectionUtils.invokeRecursiveGetter(target, targetProperty);
                 
                  if (targetInstance == null) {
                      if (ReflectionUtils.isInnerClass(targetClassAttribute)) {
                          targetInstance = ReflectionUtils.newInnerClassInstance(targetClassAttribute, target);
                      } else {
                          targetInstance = ReflectionUtils.newInstance(targetClassAttribute);
                      }
                  }
                 
                    this.addToCache(value, targetInstance);
                    value = this.applyConverter(converter, value, targetInstance);
                } else {
                    value = targetInstance;
                }
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
        } else if (targetClassAttribute.equals(sourceClassAttribute)) {
            Object returnValue = instanceFactory(targetClassAttribute);
            evalEqualsProperties(value, returnValue, null);
           
            value = returnValue;
        } else {
            value = null;
        }
    }

    return value;
  }

  private Object resolveSimpleValue(Object source, Object target, Class<?> targetClassAttribute, Object value, Transformer transformer) {
    if (transformer != null) {
      /* use custom transformer user */
      if (transformer instanceof SimpleTransformer) {
        value = ((SimpleTransformer) transformer).transform(value, targetClassAttribute);
       
      } else if (transformer instanceof ComplexTransformer) {
        value = ((ComplexTransformer) transformer).transform(source, target, value, targetClassAttribute);
       
      } else {
        throw new IllegalArgumentException("Incorrect transformer instance");
      }
    } else if (ClassUtils.isAssignable(targetClassAttribute, Number.class) || value instanceof Number || ClassUtils.isAssignable(ClassUtils.primitiveToWrapper(targetClassAttribute), Number.class)) {
      /* use automatic transformer number */
      value = new NumberTransformer().transform(value, targetClassAttribute);
   
    } else if (ClassUtils.isAssignable(targetClassAttribute, Enum.class) || value instanceof Enum) {
      /* use automatic transformer enumeration */
      value = new EnumTransformer().transform(value, targetClassAttribute);
    }
   
    return value;
  }
 
  @SuppressWarnings("unchecked")
  private Object resolveCollectionValue(Object source, Object target, String sourceProperty, String targetProperty, Class<?> targetClassAttribute, Object value, Transformer transformer) {
    if (ClassUtils.isAssignable(targetClassAttribute, Collection.class) && value instanceof Collection<?>) {
      /* use automatic transformer collection */
      Class<?> sourceCollectionItemClass = ReflectionUtils.getGenericClassFromRecursiveField(source, sourceProperty, 0);
      Class<?> targetCollectionItemClass = ReflectionUtils.getGenericClassFromRecursiveField(target, targetProperty, 0);
      Converter converter = this.getConverter(sourceCollectionItemClass, targetCollectionItemClass);
     
      try {
        Object sourceValue = value;
        value = this.getInstanceFromCollectionType(targetClassAttribute);
        Collection<Object> targetCollection = (Collection<Object>) value;
       
        if (converter != null) {
          for (Object sourceItem : (Collection<Object>) sourceValue) {
            Object targetInstance = null;
           
                    if (ReflectionUtils.isInnerClass(targetCollectionItemClass)) {
                      targetInstance = ReflectionUtils.newInnerClassInstance(targetCollectionItemClass, target);
                    } else {
                      targetInstance = ReflectionUtils.newInstance(targetCollectionItemClass);
                    }
           
            targetCollection.add(this.applyConverter(converter, sourceItem, targetInstance));
          }
        } else if (ReflectionUtils.isSimpleType(targetCollectionItemClass)) {
          for (Object sourceItem : (Collection<Object>) sourceValue) {
            targetCollection.add(this.resolveSimpleValue(source, target, targetCollectionItemClass, sourceItem, transformer));
          }
         
        } else if (sourceCollectionItemClass.equals(targetCollectionItemClass)) {
                    for (Object sourceItem : (Collection<Object>) sourceValue) {
                        Object returnValue = instanceFactory(targetCollectionItemClass);
                       
                        this.evalEqualsProperties(sourceItem, returnValue, null);
                        targetCollection.add(returnValue);
                    }
                    value = targetCollection;
           
          // TODO - implementar conversao de List dentro de List (recursivo)
        }
      } catch (Exception e) {
        throw new IllegalArgumentException(e);
      }
    } else if (ClassUtils.isAssignable(targetClassAttribute, Map.class) || value instanceof Map<?, ?>) {
        // TODO - implementar conversao de Map
        value = null;
    }
   
    return value;
  }
 
}
TOP

Related Classes of br.com.bfmapper.Mapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.