Package ma.glasnost.orika.impl

Source Code of ma.glasnost.orika.impl.MapperFacadeImpl

/*
* Orika - simpler, better and faster Java bean mapping
*
* Copyright (C) 2011 Orika authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ma.glasnost.orika.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import ma.glasnost.orika.Converter;
import ma.glasnost.orika.MapEntry;
import ma.glasnost.orika.Mapper;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.MappingContextFactory;
import ma.glasnost.orika.MappingException;
import ma.glasnost.orika.ObjectFactory;
import ma.glasnost.orika.converter.ConverterFactory;
import ma.glasnost.orika.impl.mapping.strategy.MappingStrategy;
import ma.glasnost.orika.impl.mapping.strategy.MappingStrategyKey;
import ma.glasnost.orika.impl.mapping.strategy.MappingStrategyRecorder;
import ma.glasnost.orika.impl.util.ClassUtil;
import ma.glasnost.orika.metadata.MapperKey;
import ma.glasnost.orika.metadata.Type;
import ma.glasnost.orika.metadata.TypeFactory;
import ma.glasnost.orika.unenhance.UnenhanceStrategy;
import ma.glasnost.orika.util.CacheLRULinkedHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MapperFacadeImpl implements MapperFacade {
   
    private final MapperFactory mapperFactory;
    private final MappingContextFactory contextFactory;
    private final UnenhanceStrategy unenhanceStrategy;
    private final Map<MappingStrategyKey, MappingStrategy> strategyCache = new CacheLRULinkedHashMap<MappingStrategyKey, MappingStrategy>(
            500);
    private final Logger log = LoggerFactory.getLogger(getClass());
   
    public MapperFacadeImpl(MapperFactory mapperFactory, MappingContextFactory contextFactory, UnenhanceStrategy unenhanceStrategy) {
        this.mapperFactory = mapperFactory;
        this.unenhanceStrategy = unenhanceStrategy;
        this.contextFactory = contextFactory;
    }

    /**
     * Normalize the source type based on the registered converters, mappers and
     * accessible super types, as well as available unenhancers
     *
     * @param sourceObject
     * @param sourceType
     * @param destinationType
     * @return
     */
    @SuppressWarnings("unchecked")
    private <S, D> Type<S> normalizeSourceType(S sourceObject, Type<S> sourceType, Type<D> destinationType) {
       
        Type<?> resolvedType = null;
       
        if (sourceType != null) {
            if (destinationType != null && (canCopyByReference(destinationType, sourceType) || canConvert(sourceType, destinationType))) {
                /*
                 * We shouldn't bother further resolving the source type if
                 * we already have a converter or copy-by-reference for the
                 * originally specified type -- since these operations
                 * override the use of a custom mapper which needs the
                 * resolution.
                 */
              resolvedType = sourceType;
            } else {
               
                if (sourceType.isAssignableFrom(sourceObject.getClass())) {
                    sourceType = (Type<S>) TypeFactory.valueOf(sourceObject.getClass());
                }
                Type<?> sourceObjectType = TypeFactory.resolveTypeOf(sourceObject, sourceType);
                /*
                 * In the case where there is an existing mapper registered
                 * for either the source object type or the source type, we
                 * should use that type, rather than applying unenhancement
                 * which could result in another type which would not use
                 * that mapper
                 */
                if (mapperFactory.existsRegisteredMapper(sourceType, destinationType, false)) {
                  resolvedType = sourceType;
                } else if (mapperFactory.existsRegisteredMapper(sourceObjectType, destinationType, false)) {
                  resolvedType = sourceObjectType;
                } else if (ClassUtil.isConcrete(sourceType)) {
                  resolvedType = unenhanceStrategy.unenhanceType(sourceObject, sourceType);
                } else {
                  resolvedType = unenhanceStrategy.unenhanceType(sourceObject,
                            TypeFactory.resolveTypeOf(sourceObject, sourceType));
                }
            }
        } else {
            resolvedType = unenhanceStrategy.unenhanceType(sourceObject, TypeFactory.typeOf(sourceObject));
        }
     
        return (Type<S>) resolvedType;
    }
   
    public <S, D> D map(S sourceObject, Type<S> sourceType, Type<D> destinationClass) {
        MappingContext context = contextFactory.getContext();
        try {
            return map(sourceObject, sourceType, destinationClass, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
   
    /**
     * Resolves a reusable MappingStrategy for the given set of inputs.
     *
     * @param sourceObject
     * @param rawAType
     * @param rawBType
     * @param context
     * @return
     */
    public <S, D> MappingStrategy resolveMappingStrategy(final S sourceObject, final java.lang.reflect.Type initialSourceType, final java.lang.reflect.Type initialDestinationType, boolean mapInPlace, final MappingContext context) {
       
       
        MappingStrategyKey key = new MappingStrategyKey(sourceObject.getClass(), initialSourceType, initialDestinationType, mapInPlace);
        MappingStrategy strategy = strategyCache.get(key);
       
        if (strategy == null) {
           
            @SuppressWarnings("unchecked")
            Type<S> sourceType = (Type<S>) (initialSourceType != null ? TypeFactory.valueOf(initialSourceType) : TypeFactory.typeOf(sourceObject));
            Type<D> destinationType = TypeFactory.valueOf(initialDestinationType);
           
           
            MappingStrategyRecorder strategyRecorder = new MappingStrategyRecorder(key, unenhanceStrategy);
       
            final Type<S> resolvedSourceType = normalizeSourceType(sourceObject, sourceType, destinationType);
            final S resolvedSourceObject;
           
            if (mapInPlace) {
                resolvedSourceObject = sourceObject;
            } else {
                resolvedSourceObject = unenhanceStrategy.unenhanceObject(sourceObject, sourceType);
            }
       
            strategyRecorder.setResolvedSourceType(resolvedSourceType);
            strategyRecorder.setResolvedDestinationType(destinationType);
            if (sourceObject != resolvedSourceObject) {
                strategyRecorder.setUnenhance(true);
            }
           
            if (!mapInPlace && canCopyByReference(destinationType, resolvedSourceType)) {
                /*
                 * We can copy by reference when source and destination types
                 * are the same and immutable.
                 */
                strategyRecorder.setCopyByReference(true);
            } else if (!mapInPlace && canConvert(resolvedSourceType, destinationType)) {
                strategyRecorder.setResolvedConverter(mapperFactory.getConverterFactory().getConverter(resolvedSourceType,
                            destinationType));
               
            } else {
                Type<? extends D> resolvedDestinationType;
                if (mapInPlace) {
                    resolvedDestinationType = destinationType;
                } else {
                    strategyRecorder.setInstantiate(true);
                    resolvedDestinationType = mapperFactory.lookupConcreteDestinationType(resolvedSourceType, destinationType,
                            context);
                    if (resolvedDestinationType == null) {
                        if (!ClassUtil.isConcrete(destinationType)) {
                            MappingException e = new MappingException("No concrete class mapping defined for source class "
                                    + resolvedSourceType.getName());
                            e.setDestinationType(destinationType);
                            e.setSourceType(resolvedSourceType);
                            throw e;
                        } else {
                            resolvedDestinationType = destinationType;
                        }
                    }
                }
                strategyRecorder.setResolvedDestinationType(resolvedDestinationType);
                strategyRecorder.setResolvedMapper(resolveMapper(resolvedSourceType, resolvedDestinationType));
                if (!mapInPlace) {
                    strategyRecorder.setResolvedObjectFactory(mapperFactory.lookupObjectFactory(resolvedDestinationType));
                }
            }
            strategy = strategyRecorder.playback();
            if (log.isDebugEnabled()) {
                log.debug(strategyRecorder.describeDetails());
            }
            strategyCache.put(key, strategy);
        }
       
        /*
         * Set the resolved types on the current mapping context; this can be used
         * by downstream Mappers to determine the originally resolved types
         */
        context.setResolvedSourceType(strategy.getSoureType());
        context.setResolvedDestinationType(strategy.getDestinationType());
       
        return strategy;
    }
   
   
   
    @SuppressWarnings("unchecked")
    public <S, D> D map(final S sourceObject, final Type<S> sourceType, final Type<D> destinationType, final MappingContext context) {
       
        try {
            if (destinationType == null) {
                throw new MappingException("Can not map to a null class.");
            }
            if (sourceObject == null) {
                return null;
            }
           
            D existingResult = (D) context.getMappedObject(sourceObject, destinationType);
            if (existingResult == null) {
                MappingStrategy strategy = resolveMappingStrategy(sourceObject, sourceType, destinationType, false, context);
                existingResult = (D) strategy.map(sourceObject, null, context);
            }
            return existingResult;
           
        } catch (MappingException e) {
            /* don't wrap our own exceptions */
            throw e;
        } catch (RuntimeException e) {
            if (!ExceptionUtility.originatedByOrika(e)) {
                throw e;
            }
            throw new MappingException("Error encountered while mapping for the following inputs: " + "\nrawSource=" + sourceObject
                    + "\nsourceClass=" + (sourceObject != null ? sourceObject.getClass() : null) + "\nsourceType=" + sourceType
                    + "\ndestinationType=" + destinationType, e);
        }
    }
   
    /**
     * Resolves whether the given mapping operation can use copy-by-reference
     * semantics; should be true if one of the following is true:
     * <ol>
     * <li>resolvedSourceType and destinationType are the same, and one of the
     * immutable types
     * <li>resolvedSourceType is the primitive wrapper for destinationType
     * <li>resolvedSourceType is primitive and destinationType is it's primitive
     * wrapper
     * </ol>
     *
     * @param destinationType
     * @param resolvedSourceType
     * @return
     */
    private <D, S> boolean canCopyByReference(Type<D> destinationType, final Type<S> resolvedSourceType) {
        if (ClassUtil.isImmutable(resolvedSourceType) && (resolvedSourceType.equals(destinationType))) {
            return true;
        } else if (resolvedSourceType.isPrimitiveWrapper()
                && resolvedSourceType.getRawType().equals(ClassUtil.getWrapperType(destinationType.getRawType()))) {
            return true;
        } else if (resolvedSourceType.isPrimitive()
                && destinationType.getRawType().equals(ClassUtil.getWrapperType(resolvedSourceType.getRawType()))) {
            return true;
        } else {
            return false;
        }
    }
   
    public <S, D> void map(S sourceObject, D destinationObject, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
       
        try {
            if (destinationObject == null) {
                throw new MappingException("[destinationObject] can not be null.");
            }
           
            if (destinationType == null) {
                throw new MappingException("[destinationType] can not be null.");
            }
           
            if (sourceObject == null) {
                throw new MappingException("[sourceObject] can not be null.");
            }
           
            if (context.getMappedObject(sourceObject, destinationType) == null) {
                MappingStrategy strategy = resolveMappingStrategy(sourceObject, sourceType, destinationType, true, context);
                strategy.map(sourceObject, destinationObject, context);
            }

        } catch (MappingException e) {
            /* don't wrap our own exceptions */
            throw e;
        } catch (RuntimeException e) {
            if (!ExceptionUtility.originatedByOrika(e)) {
                throw e;
            }
            throw new MappingException("Error encountered while mapping for the following inputs: " + "\nrawSource=" + sourceObject
                    + "\nsourceClass=" + (sourceObject != null ? sourceObject.getClass() : null) + "\nsourceType=" + sourceType
                    + "\nrawDestination=" + destinationObject + "\ndestinationClass="
                    + (destinationObject != null ? destinationObject.getClass() : null) + "\ndestinationType=" + destinationType, e);
        }
       
    }
   
    public <S, D> void map(S sourceObject, D destinationObject, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            map(sourceObject, destinationObject, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> void map(S sourceObject, D destinationObject, MappingContext context) {
       
        try {
            if (destinationObject == null) {
                throw new MappingException("[destinationObject] can not be null.");
            }
           
            if (sourceObject == null) {
                throw new MappingException("[sourceObject] can not be null.");
            }
           
            if (context.getMappedObject(sourceObject, destinationObject.getClass()) == null) {
                MappingStrategy strategy = resolveMappingStrategy(sourceObject, null, destinationObject.getClass(), true, context);
                strategy.map(sourceObject, destinationObject, context);
            }

        } catch (MappingException e) {
            /* don't wrap our own exceptions */
            throw e;
        } catch (RuntimeException e) {
            if (!ExceptionUtility.originatedByOrika(e)) {
                throw e;
            }
            throw new MappingException("Error encountered while mapping for the following inputs: " + "\nrawSource=" + sourceObject
                    + "\nsourceClass=" + (sourceObject != null ? sourceObject.getClass() : null)
                    + "\nrawDestination=" + destinationObject + "\ndestinationClass="
                    + (destinationObject != null ? destinationObject.getClass() : null), e);
        }
    }
   
    public <S, D> void map(S sourceObject, D destinationObject) {
        MappingContext context = contextFactory.getContext();
        try {
            map(sourceObject, destinationObject, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public final <S, D> Set<D> mapAsSet(Iterable<S> source, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsSet(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
       
    }
   
    public final <S, D> Set<D> mapAsSet(Iterable<S> source, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
        return (Set<D>) mapAsCollection(source, sourceType, destinationType, new HashSet<D>(), context);
    }
   
    public final <S, D> List<D> mapAsList(Iterable<S> source, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return (List<D>) mapAsCollection(source, sourceType, destinationType, new ArrayList<D>(), context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public final <S, D> List<D> mapAsList(Iterable<S> source, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
        return (List<D>) mapAsCollection(source, sourceType, destinationType, new ArrayList<D>(), context);
    }
   
    public <S, D> D[] mapAsArray(D[] destination, Iterable<S> source, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsArray(destination, source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> D[] mapAsArray(D[] destination, S[] source, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsArray(destination, source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> D[] mapAsArray(D[] destination, Iterable<S> source, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
       
        if (source == null) {
            return null;
        }
       
        int i = 0;
        for (final S s : source) {
            destination[i++] = map(s, sourceType, destinationType);
        }
        return destination;
    }
   
    public <S, D> D[] mapAsArray(D[] destination, S[] source, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
       
        if (source == null) {
            return null;
        }
       
        int i = 0;
        for (final S s : source) {
            destination[i++] = map(s, sourceType, destinationType, context);
        }
        return destination;
    }
   
    public <S, D> List<D> mapAsList(S[] source, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsList(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> List<D> mapAsList(S[] source, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
        final List<D> destination = new ArrayList<D>(source.length);
        for (final S s : source) {
            destination.add(map(s, sourceType, destinationType, context));
        }
        return destination;
    }
   
    public <S, D> Set<D> mapAsSet(S[] source, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsSet(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> Set<D> mapAsSet(S[] source, Type<S> sourceType, Type<D> destinationType, MappingContext context) {
        final Set<D> destination = new HashSet<D>(source.length);
        for (final S s : source) {
            destination.add(map(s, sourceType, destinationType, context));
        }
        return destination;
    }
   
    /**
     * Map an iterable onto an existing collection
     *
     * @param source
     *            the source iterable
     * @param destination
     *            the destination into which the results will be mapped
     * @param sourceType
     *            the type of
     * @param destinationType
     * @param context
     */
    public <S, D> void mapAsCollection(Iterable<S> source, Collection<D> destination, Type<S> sourceType, Type<D> destinationType,
            MappingContext context) {
        if (source == null) {
            return;
        }
        if (destination != null) {
            destination.clear();
            for (S item : source) {
                destination.add(map(item, sourceType, destinationType, context));
            }
        }
    }
   
    /**
     * Map an array onto an existing collection
     *
     * @param source
     * @param destination
     * @param sourceType
     * @param destinationType
     * @param context
     */
    public <S, D> void mapAsCollection(S[] source, Collection<D> destination, Type<S> sourceType, Type<D> destinationType,
            MappingContext context) {
        if (source == null) {
            return;
        }
        if (destination != null) {
            destination.clear();
            for (S item : source) {
                destination.add(map(item, sourceType, destinationType, context));
            }
        }
    }
   
    Mapper<Object, Object> resolveMapper(Type<?> sourceType, Type<?> destinationType) {
        final MapperKey mapperKey = new MapperKey(sourceType, destinationType);
        Mapper<Object, Object> mapper = mapperFactory.lookupMapper(mapperKey);
       
        if (mapper == null) {
            throw new IllegalStateException(String.format("Cannot create a mapper for classes : %s, %s", destinationType, sourceType));
        }
       
        if ((!mapper.getAType().equals(sourceType) && mapper.getAType().equals(destinationType))
                || (!mapper.getAType().isAssignableFrom(sourceType) && mapper.getAType().isAssignableFrom(destinationType))) {
            mapper = ReversedMapper.reverse(mapper);
        }
        return mapper;
    }
   
    /**
     * Maps the declared properties of the source object into the destination
     * object, using the specified mapper.
     *
     * @param sourceObject
     *            the source object from which to map property values
     * @param destinationObject
     *            the destination object onto which the source object's property
     *            values will be mapped
     * @param sourceType
     *            the type of the source object
     * @param destinationType
     *            the type of the destination object
     * @param context
     *            the current mapping context
     * @param mapper
     *            the mapper to use for mapping the source property values onto
     *            the destination
     * @param strategyBuilder
     *            the strategy builder used to record the mapping strategy taken
     */
    void mapDeclaredProperties(Object sourceObject, Object destinationObject, Type<?> sourceType, Type<?> destinationType,
            MappingContext context, Mapper<Object, Object> mapper, MappingStrategyRecorder strategyBuilder) {
       
        if (mapper.getAType().equals(sourceType)) {
            mapper.mapAtoB(sourceObject, destinationObject, context);
        } else if (mapper.getAType().equals(destinationType)) {
            mapper.mapBtoA(sourceObject, destinationObject, context);
            if (strategyBuilder != null)
                strategyBuilder.setMapReverse(true);
        } else if (mapper.getAType().isAssignableFrom(sourceType)) {
            mapper.mapAtoB(sourceObject, destinationObject, context);
        } else if (mapper.getAType().isAssignableFrom(destinationType)) {
            mapper.mapBtoA(sourceObject, destinationObject, context);
            if (strategyBuilder != null)
                strategyBuilder.setMapReverse(true);
        } else {
            throw new IllegalStateException(String.format("Source object type's must be one of '%s' or '%s'.", mapper.getAType(),
                    mapper.getBType()));
           
        }
    }
   
    private <S, D> D newObject(S sourceObject, Type<? extends D> destinationType, MappingContext context,
            MappingStrategyRecorder strategyBuilder) {
       
        final ObjectFactory<? extends D> objectFactory = mapperFactory.lookupObjectFactory(destinationType);
       
        if (strategyBuilder != null) {
            strategyBuilder.setResolvedObjectFactory(objectFactory);
        }
        return objectFactory.create(sourceObject, context);  
    }
   
    /*
     * (non-Javadoc)
     *
     * @see ma.glasnost.orika.MapperFacade#newObject(java.lang.Object,
     * ma.glasnost.orika.metadata.Type, ma.glasnost.orika.MappingContext)
     */
    public <S, D> D newObject(S sourceObject, Type<? extends D> destinationType, MappingContext context) {
        return newObject(sourceObject, destinationType, context, null);
    }
   
    /**
     * Map the iterable into the provided destination collection and return it
     *
     * @param source
     * @param sourceType
     * @param destinationType
     * @param destination
     * @param context
     * @return
     */
    @SuppressWarnings("unchecked")
    <S, D> Collection<D> mapAsCollection(Iterable<S> source, Type<S> sourceType, Type<D> destinationType, Collection<D> destination,
            MappingContext context) {
       
        if (source == null) {
            return null;
        }
       
        MappingStrategy strategy = null;
        Class<?> sourceClass = null;
        for (final S item : source) {
            if (item == null) {
                continue;
            } else if (strategy == null || (!item.getClass().equals(sourceClass))) {
                /*
                 * Resolve the strategy and reuse; assuming this is a homogeneous collection,
                 * this will save us (n-1) lookups; if not, we would have done those lookups anyway
                 */
                strategy = resolveMappingStrategy(item, sourceType, destinationType, false, context);
                sourceClass = item.getClass();
            }
            D mappedItem = (D) context.getMappedObject(item, destinationType);
            if (mappedItem == null) {
                mappedItem = (D) strategy.map(item, null, context);
            }
            destination.add(mappedItem);
        }
        return destination;
    }
   
    @SuppressWarnings("unchecked")
    public <S, D> D convert(S source, Type<S> sourceType, Type<D> destinationType, String converterId) {
       
        Converter<S, D> converter;
        ConverterFactory converterFactory = mapperFactory.getConverterFactory();
        if (converterId == null) {
            final Type<? extends Object> sourceClass = normalizeSourceType(source, sourceType, destinationType);
            converter = (Converter<S, D>) converterFactory.getConverter(sourceClass, destinationType);
        } else {
            converter = (Converter<S, D>) converterFactory.getConverter(converterId);
        }
       
        return converter.convert(source, destinationType);
    }
   
    private <S, D> boolean canConvert(Type<S> sourceType, Type<D> destinationType) {
        return mapperFactory.getConverterFactory().canConvert(sourceType, destinationType);
    }
   
    public <S, D> D map(S sourceObject, Class<D> destinationClass) {
        MappingContext context = contextFactory.getContext();
        try {
            return map(sourceObject, destinationClass, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    @SuppressWarnings("unchecked")
    public <S, D> D map(S sourceObject, Class<D> destinationClass, MappingContext context) {
       
        try {
            if (destinationClass == null) {
                throw new MappingException("Can not map to a null class.");
            }
            if (sourceObject == null) {
                return null;
            }
           
            D result = (D) context.getMappedObject(sourceObject, destinationClass);
            if (result == null) {
                MappingStrategy strategy = resolveMappingStrategy(sourceObject, null, destinationClass, false, context);
                result = (D) strategy.map(sourceObject, null, context);
            }
            return result;
           
        } catch (MappingException e) {
            /* don't wrap our own exceptions */
            throw e;
        } catch (RuntimeException e) {
            if (!ExceptionUtility.originatedByOrika(e)) {
                throw e;
            }
            throw new MappingException("Error encountered while mapping for the following inputs: " + "\nrawSource=" + sourceObject
                    + "\nsourceClass=" + (sourceObject != null ? sourceObject.getClass() : null)
                    + "\ndestinationClass=" + destinationClass, e);
        }
    }
   
    public <S, D> Set<D> mapAsSet(Iterable<S> source, Class<D> destinationClass) {
        return mapAsSet(source, TypeFactory.elementTypeOf(source), TypeFactory.<D> valueOf(destinationClass));
    }
   
    public <S, D> Set<D> mapAsSet(Iterable<S> source, Class<D> destinationClass, MappingContext context) {
        return mapAsSet(source, TypeFactory.elementTypeOf(source), TypeFactory.<D> valueOf(destinationClass), context);
    }
   
    public <S, D> Set<D> mapAsSet(S[] source, Class<D> destinationClass) {
        return mapAsSet(source, TypeFactory.componentTypeOf(source), TypeFactory.<D> valueOf(destinationClass));
    }
   
    public <S, D> Set<D> mapAsSet(S[] source, Class<D> destinationClass, MappingContext context) {
        return mapAsSet(source, TypeFactory.componentTypeOf(source), TypeFactory.<D> valueOf(destinationClass), context);
    }
   
    public <S, D> List<D> mapAsList(Iterable<S> source, Class<D> destinationClass) {
        return mapAsList(source, TypeFactory.elementTypeOf(source), TypeFactory.<D> valueOf(destinationClass));
    }
   
    public <S, D> List<D> mapAsList(Iterable<S> source, Class<D> destinationClass, MappingContext context) {
        return mapAsList(source, TypeFactory.elementTypeOf(source), TypeFactory.<D> valueOf(destinationClass), context);
    }
   
    public <S, D> List<D> mapAsList(S[] source, Class<D> destinationClass) {
        return mapAsList(source, TypeFactory.componentTypeOf(source), TypeFactory.<D> valueOf(destinationClass));
    }
   
    public <S, D> List<D> mapAsList(S[] source, Class<D> destinationClass, MappingContext context) {
        return mapAsList(source, TypeFactory.componentTypeOf(source), TypeFactory.<D> valueOf(destinationClass), context);
    }
   
    public <S, D> D[] mapAsArray(D[] destination, Iterable<S> source, Class<D> destinationClass) {
        return mapAsArray(destination, source, TypeFactory.elementTypeOf(source), TypeFactory.<D> valueOf(destinationClass));
    }
   
    public <S, D> D[] mapAsArray(D[] destination, S[] source, Class<D> destinationClass) {
        return mapAsArray(destination, source, TypeFactory.componentTypeOf(source), TypeFactory.<D> valueOf(destinationClass));
    }
   
    public <S, D> D[] mapAsArray(D[] destination, Iterable<S> source, Class<D> destinationClass, MappingContext context) {
        return mapAsArray(destination, source, TypeFactory.elementTypeOf(source), TypeFactory.<D> valueOf(destinationClass), context);
    }
   
    public <S, D> D[] mapAsArray(D[] destination, S[] source, Class<D> destinationClass, MappingContext context) {
        return mapAsArray(destination, source, TypeFactory.componentTypeOf(source), TypeFactory.<D> valueOf(destinationClass), context);
    }
   
    public <S, D> D convert(S source, Class<D> destinationClass, String converterId) {
        return convert(source, TypeFactory.typeOf(source), TypeFactory.<D> valueOf(destinationClass), converterId);
    }
   
    /*
     * New mapping type: Map to Map
     */
    public <Sk, Sv, Dk, Dv> Map<Dk, Dv> mapAsMap(Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType,
            Type<? extends Map<Dk, Dv>> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsMap(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
       
    }
   
    @SuppressWarnings("unchecked")
    public <Sk, Sv, Dk, Dv> Map<Dk, Dv> mapAsMap(Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType,
            Type<? extends Map<Dk, Dv>> destinationType, MappingContext context) {
        Map<Dk, Dv> destination = new HashMap<Dk, Dv>(source.size());
       
        /*
         * Resolve the strategy used for the key and value; only re-resolve
         * a strategy if we encounter a different source class. This should allow
         * us to process a homogeneous key/value typed map as quickly as possible
         */
        MappingStrategy keyStrategy = null;
        MappingStrategy valueStrategy = null;
        Class<?> keyClass = null;
        Class<?> valueClass = null;

        for (Entry<Sk, Sv> entry : source.entrySet()) {
            Dk key;
            if (entry.getKey() == null) {
                key = null;
            } else {
                if (keyStrategy == null || !entry.getKey().getClass().equals(keyClass)) {
                    keyStrategy = resolveMappingStrategy(entry.getKey(), sourceType.<Sk> getNestedType(0), destinationType.<Dk> getNestedType(0), false, context);
                    keyClass = entry.getKey().getClass();
                }
                Dk mappedKey = (Dk) context.getMappedObject(entry.getKey(), destinationType.<Dk> getNestedType(0));
                if (mappedKey == null) {
                    mappedKey = (Dk) (Dk) keyStrategy.map(entry.getKey(), null, context);
                }
               
                key = mappedKey;
            }
           
            Dv value;
            if (entry.getValue() == null) {
                value = null;
            } else {
                if (valueStrategy == null || !entry.getValue().getClass().equals(valueClass)) {
                    valueStrategy = resolveMappingStrategy(entry.getValue(), sourceType.<Sv> getNestedType(1), destinationType.<Dv> getNestedType(1), false, context);
                    valueClass = entry.getValue().getClass();
                }
               
                Dv mappedValue = (Dv) context.getMappedObject(entry.getValue(), destinationType.<Dv> getNestedType(1));
                if (mappedValue == null) {
                    mappedValue = (Dv) (Dv) valueStrategy.map(entry.getValue(), null, context);
                }
               
                value = mappedValue;
            }
           
            destination.put(key, value);
        }
        return destination;
    }
   
    public <S, Dk, Dv> Map<Dk, Dv> mapAsMap(Iterable<S> source, Type<S> sourceType, Type<? extends Map<Dk, Dv>> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsMap(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    @SuppressWarnings("unchecked")
    public <S, Dk, Dv> Map<Dk, Dv> mapAsMap(Iterable<S> source, Type<S> sourceType, Type<? extends Map<Dk, Dv>> destinationType,
            MappingContext context) {
       
        Map<Dk, Dv> destination = new HashMap<Dk, Dv>();
        MappingStrategy strategy = null;
        Class<?> entryClass = null;
       
        Type<?> entryType = TypeFactory.valueOf(Map.Entry.class, destinationType.getNestedType(0), destinationType.getNestedType(1));
       
        for (S element : source) {
            if (strategy == null || !element.getClass().equals(entryClass)) {
                strategy = resolveMappingStrategy(element, sourceType, entryType, false, context);
                entryClass = element.getClass();
            }
           
            Map.Entry<Dk, Dv> entry = context.getMappedObject(element, entryType);
            if (entry == null) {
                entry = (Map.Entry<Dk, Dv>) strategy.map(element, null, context);
            }
            destination.put(entry.getKey(), entry.getValue());
        }
       
        return destination;
    }
   
    public <S, Dk, Dv> Map<Dk, Dv> mapAsMap(S[] source, Type<S> sourceType, Type<? extends Map<Dk, Dv>> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsMap(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    @SuppressWarnings("unchecked")
    public <S, Dk, Dv> Map<Dk, Dv> mapAsMap(S[] source, Type<S> sourceType, Type<? extends Map<Dk, Dv>> destinationType,
            MappingContext context) {
       
        Map<Dk, Dv> destination = new HashMap<Dk, Dv>();
        Type<MapEntry<Dk, Dv>> entryType = MapEntry.concreteEntryType(destinationType);
        MappingStrategy strategy = null;
        Class<?> entryClass = null;
       
        for (S element : source) {
            if (strategy == null || !element.getClass().equals(entryClass)) {
                strategy = resolveMappingStrategy(element, sourceType, entryType, false, context);
                entryClass = element.getClass();
            }
           
            MapEntry<Dk, Dv> entry = context.getMappedObject(element, entryType);
            if (entry == null) {
                entry = (MapEntry<Dk, Dv>) strategy.map(element, null, context);
            }
            destination.put(entry.getKey(), entry.getValue());
        }
       
        return destination;
    }
   
    /*
     * New mapping type: Map to List, Set or Array
     */
    public <Sk, Sv, D> List<D> mapAsList(Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsList(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <Sk, Sv, D> List<D> mapAsList(Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType, Type<D> destinationType,
            MappingContext context) {
        /*
         * Use map as collection to map the entry set to a list; requires an
         * existing mapping for Map.Entry to to type D.
         */
        List<D> destination = new ArrayList<D>(source.size());
       
        Type<MapEntry<Sk, Sv>> entryType = MapEntry.concreteEntryType(sourceType);
       
        return (List<D>) mapAsCollection(MapEntry.entrySet(source), entryType, destinationType, destination, context);
    }
   
    public <Sk, Sv, D> Set<D> mapAsSet(Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsSet(source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <Sk, Sv, D> Set<D> mapAsSet(Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType, Type<D> destinationType,
            MappingContext context) {
        /*
         * Use map as collection to map the entry set to a list; requires an
         * existing mapping for Map.Entry to to type D.
         */
        Set<D> destination = new HashSet<D>(source.size());
        Type<Entry<Sk, Sv>> entryType = TypeFactory.resolveTypeOf(source.entrySet(), sourceType).getNestedType(0);
        return (Set<D>) mapAsCollection(source.entrySet(), entryType, destinationType, destination, context);
    }
   
    public <Sk, Sv, D> D[] mapAsArray(D[] destination, Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            return mapAsArray(destination, source, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <Sk, Sv, D> D[] mapAsArray(D[] destination, Map<Sk, Sv> source, Type<? extends Map<Sk, Sv>> sourceType, Type<D> destinationType,
            MappingContext context) {
       
        Type<MapEntry<Sk, Sv>> entryType = MapEntry.concreteEntryType(sourceType);
       
        return mapAsArray(destination, MapEntry.entrySet(source), entryType, destinationType, context);
    }
   
    public <S, D> void mapAsCollection(Iterable<S> source, Collection<D> destination, Class<D> destinationClass) {
        MappingContext context = contextFactory.getContext();
        try {
            mapAsCollection(source, destination, destinationClass, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> void mapAsCollection(Iterable<S> source, Collection<D> destination, Class<D> destinationClass, MappingContext context) {
        mapAsCollection(source, destination, null, TypeFactory.valueOf(destinationClass), context);
    }
   
    public <S, D> void mapAsCollection(S[] source, Collection<D> destination, Class<D> destinationClass) {
        MappingContext context = contextFactory.getContext();
        try {
            mapAsCollection(source, destination, destinationClass, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    @SuppressWarnings("unchecked")
    public <S, D> void mapAsCollection(S[] source, Collection<D> destination, Class<D> destinationClass, MappingContext context) {
        mapAsCollection(source, destination, (Type<S>) TypeFactory.valueOf(source.getClass().getComponentType()),
                TypeFactory.valueOf(destinationClass), context);
    }
   
    public <S, D> void mapAsCollection(Iterable<S> source, Collection<D> destination, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            mapAsCollection(source, destination, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
   
    public <S, D> void mapAsCollection(S[] source, Collection<D> destination, Type<S> sourceType, Type<D> destinationType) {
        MappingContext context = contextFactory.getContext();
        try {
            mapAsCollection(source, destination, sourceType, destinationType, context);
        } finally {
            contextFactory.release(context);
        }
    }
}
TOP

Related Classes of ma.glasnost.orika.impl.MapperFacadeImpl

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.