
org.modelmapper.internal.MappingEngineImpl Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2011 the original author or 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 org.modelmapper.internal;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.modelmapper.Condition;
import org.modelmapper.ConfigurationException;
import org.modelmapper.Converter;
import org.modelmapper.Provider;
import org.modelmapper.TypeMap;
import org.modelmapper.TypeToken;
import org.modelmapper.internal.converter.ConverterStore;
import org.modelmapper.internal.util.Iterables;
import org.modelmapper.internal.util.Objects;
import org.modelmapper.internal.util.Primitives;
import org.modelmapper.internal.util.Types;
import org.modelmapper.spi.ConstantMapping;
import org.modelmapper.spi.Mapping;
import org.modelmapper.spi.MappingContext;
import org.modelmapper.spi.MappingEngine;
import org.modelmapper.spi.PropertyMapping;
import org.modelmapper.spi.SourceMapping;
/**
* MappingEngine implementation that caches ConditionalConverters by source and destination type
* pairs.
*
* @author Jonathan Halterman
*/
public class MappingEngineImpl implements MappingEngine {
/** Cache of conditional converters */
private final Map, Converter, ?>> converterCache = new ConcurrentHashMap, Converter, ?>>();
private final InheritingConfiguration configuration;
private final TypeMapStore typeMapStore;
private final ConverterStore converterStore;
public MappingEngineImpl(InheritingConfiguration configuration) {
this.configuration = configuration;
this.typeMapStore = configuration.typeMapStore;
this.converterStore = configuration.converterStore;
}
/**
* Initial entry point.
*/
public D map(S source, Class sourceType, D destination,
TypeToken destinationTypeToken, String typeMapName) {
MappingContextImpl context = new MappingContextImpl(source, sourceType,
destination, destinationTypeToken.getRawType(), destinationTypeToken.getType(),
typeMapName, this);
D result = null;
try {
result = map(context);
} catch (ConfigurationException e) {
throw e;
} catch (ErrorsException e) {
throw context.errors.toMappingException();
} catch (Throwable t) {
context.errors.errorMapping(sourceType, destinationTypeToken.getType(), t);
}
context.errors.throwMappingExceptionIfErrorsExist();
return result;
}
/**
* Performs mapping using a TypeMap if one exists, else a converter if one applies, else a newly
* created TypeMap. Recursive entry point.
*/
@Override
@SuppressWarnings("unchecked")
public D map(MappingContext context) {
MappingContextImpl contextImpl = (MappingContextImpl) context;
Class destinationType = context.getDestinationType();
// Resolve some circular dependencies
if (!Iterables.isIterable(destinationType)) {
D circularDest = contextImpl.destinationForSource();
if (circularDest != null && circularDest.getClass().isAssignableFrom(contextImpl.getDestinationType()))
return circularDest;
}
D destination = null;
TypeMap typeMap = typeMapStore.get(context.getSourceType(), context.getDestinationType(),
context.getTypeMapName());
if (typeMap != null) {
destination = typeMap(contextImpl, typeMap);
} else {
Converter converter = converterFor(context);
if (converter != null && (context.getDestination() == null || context.getParent() != null))
destination = convert(context, converter);
else if (!Primitives.isPrimitive(context.getSourceType()) && !Primitives.isPrimitive(context.getDestinationType())) {
// Call getOrCreate in case TypeMap was created concurrently
typeMap = typeMapStore.getOrCreate(context.getSource(), context.getSourceType(),
context.getDestinationType(), context.getTypeMapName(), this);
destination = typeMap(contextImpl, typeMap);
} else if (context.getDestinationType().isAssignableFrom(context.getSourceType()))
destination = (D) context.getSource();
}
contextImpl.setDestination(destination, true);
return destination;
}
/**
* Performs a type mapping for the {@code typeMap} and {@code context}.
*/
D typeMap(MappingContextImpl context, TypeMap typeMap) {
if (context.getParent() != null && context.getDestination() == null)
context.setDestination(destinationProperty(context), false);
context.setTypeMap(typeMap);
@SuppressWarnings("unchecked")
Condition condition = (Condition) typeMap.getCondition();
boolean noSkip = condition == null || condition.applies(context);
if (noSkip && typeMap.getConverter() != null)
return convert(context, typeMap.getConverter());
if (context.getDestination() == null && Types.isInstantiable(context.getDestinationType())) {
D destination = createDestination(context);
if (destination == null)
return null;
}
if (noSkip) {
Converter converter = typeMap.getPreConverter();
if (converter != null)
context.setDestination(convert(context, converter), true);
for (Mapping mapping : typeMap.getMappings())
propertyMap(mapping, context);
converter = typeMap.getPostConverter();
if (converter != null)
context.setDestination(convert(context, converter), true);
}
return context.getDestination();
}
@SuppressWarnings("unchecked")
private void propertyMap(Mapping mapping, MappingContextImpl context) {
MappingImpl mappingImpl = (MappingImpl) mapping;
String propertyPath = context.destinationPath + mappingImpl.getPath();
if (context.isShaded(propertyPath))
return;
if (mapping.getCondition() == null && mapping.isSkipped()) // skip()
return;
Object source = resolveSourceValue(context, mapping);
MappingContextImpl
© 2015 - 2025 Weber Informatics LLC | Privacy Policy