mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#302 Making MappingContext immutable
This commit is contained in:
parent
d42216ee4f
commit
9adbb423c6
@ -19,8 +19,6 @@
|
|||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.processing.Messager;
|
import javax.annotation.processing.Messager;
|
||||||
@ -28,11 +26,13 @@ import javax.lang.model.element.TypeElement;
|
|||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.model.common.TypeFactory;
|
import org.mapstruct.ap.model.common.TypeFactory;
|
||||||
|
import org.mapstruct.ap.model.source.Method;
|
||||||
import org.mapstruct.ap.model.source.SourceMethod;
|
import org.mapstruct.ap.model.source.SourceMethod;
|
||||||
import org.mapstruct.ap.option.Options;
|
import org.mapstruct.ap.option.Options;
|
||||||
import org.mapstruct.ap.prism.MapperPrism;
|
|
||||||
import org.mapstruct.ap.util.MapperConfig;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides the context for the builders.
|
* This class provides the context for the builders.
|
||||||
@ -61,6 +61,53 @@ import org.mapstruct.ap.util.MapperConfig;
|
|||||||
*/
|
*/
|
||||||
public class MappingContext {
|
public class MappingContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the most suitable way for mapping an element (property, iterable element etc.) from source to target.
|
||||||
|
* There are 2 basic types of mappings:
|
||||||
|
* <ul>
|
||||||
|
* <li>conversions</li>
|
||||||
|
* <li>methods</li>
|
||||||
|
* </ul>
|
||||||
|
* conversions are essentially one line mappings, such as String to Integer and Integer to Long methods come in some
|
||||||
|
* varieties:
|
||||||
|
* <ul>
|
||||||
|
* <li>referenced mapping methods, these are methods implemented (or referenced) by the user. Sometimes indicated
|
||||||
|
* with the 'uses' in the mapping annotations or part of the abstract mapper class</li>
|
||||||
|
* <li>generated mapping methods (by means of MapStruct)</li>
|
||||||
|
* <li>built in methods</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public interface MappingResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a parameter assignment
|
||||||
|
*
|
||||||
|
* @param mappingMethod target mapping method
|
||||||
|
* @param mappedElement used for error messages
|
||||||
|
* @param sourceType parameter to match
|
||||||
|
* @param targetType return type to match
|
||||||
|
* @param targetPropertyName name of the target property
|
||||||
|
* @param dateFormat used for formatting dates in build in methods that need context information
|
||||||
|
* @param qualifiers used for further select the appropriate mapping method based on class and name
|
||||||
|
* @param sourceReference call to source type as string
|
||||||
|
*
|
||||||
|
* @return an assignment to a method parameter, which can either be:
|
||||||
|
* <ol>
|
||||||
|
* <li>MethodReference</li>
|
||||||
|
* <li>TypeConversion</li>
|
||||||
|
* <li>Direct Assignment (empty TargetAssignment)</li>
|
||||||
|
* <li>null, no assignment found</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
Assignment getTargetAssignment(Method mappingMethod, String mappedElement, Type sourceType, Type targetType,
|
||||||
|
String targetPropertyName, String dateFormat, List<TypeMirror> qualifiers,
|
||||||
|
String sourceReference);
|
||||||
|
|
||||||
|
Set<VirtualMappingMethod> getUsedVirtualMappings();
|
||||||
|
}
|
||||||
|
|
||||||
private final TypeFactory typeFactory;
|
private final TypeFactory typeFactory;
|
||||||
private final Elements elementUtils;
|
private final Elements elementUtils;
|
||||||
private final Types typeUtils;
|
private final Types typeUtils;
|
||||||
@ -69,32 +116,27 @@ public class MappingContext {
|
|||||||
private final TypeElement mapperTypeElement;
|
private final TypeElement mapperTypeElement;
|
||||||
private final List<SourceMethod> sourceModel;
|
private final List<SourceMethod> sourceModel;
|
||||||
private final List<MapperReference> mapperReferences;
|
private final List<MapperReference> mapperReferences;
|
||||||
private MappingResolver mappingResolver;
|
private final MappingResolver mappingResolver;
|
||||||
private final List<MappingMethod> mappingsToGenerate = new ArrayList<MappingMethod>();
|
private final List<MappingMethod> mappingsToGenerate = new ArrayList<MappingMethod>();
|
||||||
|
|
||||||
/**
|
public MappingContext(TypeFactory typeFactory,
|
||||||
* Private methods which are not present in the original mapper interface and are added to map certain property
|
Elements elementUtils,
|
||||||
* types.
|
Types typeUtils,
|
||||||
*/
|
Messager messager,
|
||||||
private final Set<VirtualMappingMethod> usedVirtualMappings = new HashSet<VirtualMappingMethod>();
|
Options options,
|
||||||
|
MappingResolver mappingResolver,
|
||||||
|
TypeElement mapper,
|
||||||
|
List<SourceMethod> sourceModel,
|
||||||
public MappingContext( TypeFactory typeFactory,
|
List<MapperReference> mapperReferences) {
|
||||||
Elements elementUtils,
|
|
||||||
Types typeUtils,
|
|
||||||
Messager messager,
|
|
||||||
Options options,
|
|
||||||
TypeElement mapper,
|
|
||||||
List<SourceMethod> sourceModel ) {
|
|
||||||
this.typeFactory = typeFactory;
|
this.typeFactory = typeFactory;
|
||||||
this.elementUtils = elementUtils;
|
this.elementUtils = elementUtils;
|
||||||
this.typeUtils = typeUtils;
|
this.typeUtils = typeUtils;
|
||||||
this.messager = messager;
|
this.messager = messager;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.mappingResolver = mappingResolver;
|
||||||
this.mapperTypeElement = mapper;
|
this.mapperTypeElement = mapper;
|
||||||
this.sourceModel = sourceModel;
|
this.sourceModel = sourceModel;
|
||||||
this.mapperReferences = initReferencedMappers( mapper );
|
this.mapperReferences = mapperReferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeElement getMapperTypeElement() {
|
public TypeElement getMapperTypeElement() {
|
||||||
@ -133,39 +175,11 @@ public class MappingContext {
|
|||||||
return mappingResolver;
|
return mappingResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMappingResolver(MappingResolver mappingResolver) {
|
|
||||||
this.mappingResolver = mappingResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<MappingMethod> getMappingsToGenerate() {
|
public List<MappingMethod> getMappingsToGenerate() {
|
||||||
return mappingsToGenerate;
|
return mappingsToGenerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<VirtualMappingMethod> getUsedVirtualMappings() {
|
public Set<VirtualMappingMethod> getUsedVirtualMappings() {
|
||||||
return usedVirtualMappings;
|
return mappingResolver.getUsedVirtualMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MapperReference> initReferencedMappers(TypeElement element) {
|
|
||||||
List<MapperReference> result = new LinkedList<MapperReference>();
|
|
||||||
List<String> variableNames = new LinkedList<String>();
|
|
||||||
|
|
||||||
MapperConfig mapperPrism = MapperConfig.getInstanceOn( element );
|
|
||||||
|
|
||||||
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
|
||||||
DefaultMapperReference mapperReference = DefaultMapperReference.getInstance(
|
|
||||||
typeFactory.getType( usedMapper ),
|
|
||||||
MapperPrism.getInstanceOn( typeUtils.asElement( usedMapper ) ) != null,
|
|
||||||
typeFactory,
|
|
||||||
variableNames
|
|
||||||
);
|
|
||||||
|
|
||||||
result.add( mapperReference );
|
|
||||||
variableNames.add( mapperReference.getVariableName() );
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2012-2014 Gunnar Morling (http://www.gunnarmorling.de/)
|
|
||||||
* and/or other contributors as indicated by the @authors tag. See the
|
|
||||||
* copyright.txt file in the distribution for a full listing of all
|
|
||||||
* contributors.
|
|
||||||
*
|
|
||||||
* 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.mapstruct.ap.model;
|
|
||||||
|
|
||||||
import org.mapstruct.ap.model.assignment.Assignment;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
|
||||||
import org.mapstruct.ap.model.source.Method;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Sjaak Derksen
|
|
||||||
*/
|
|
||||||
public interface MappingResolver {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a parameter assignment
|
|
||||||
*
|
|
||||||
* @param mappingMethod target mapping method
|
|
||||||
* @param mappedElement used for error messages
|
|
||||||
* @param sourceType parameter to match
|
|
||||||
* @param targetType return type to match
|
|
||||||
* @param targetPropertyName name of the target property
|
|
||||||
* @param dateFormat used for formatting dates in build in methods that need context information
|
|
||||||
* @param qualifiers used for further select the appropriate mapping method based on class and name
|
|
||||||
* @param sourceReference call to source type as string
|
|
||||||
*
|
|
||||||
* @return an assignment to a method parameter, which can either be:
|
|
||||||
* <ol>
|
|
||||||
* <li>MethodReference</li>
|
|
||||||
* <li>TypeConversion</li>
|
|
||||||
* <li>Direct Assignment (empty TargetAssignment)</li>
|
|
||||||
* <li>null, no assignment found</li>
|
|
||||||
* </ol>
|
|
||||||
*/
|
|
||||||
Assignment getTargetAssignment(
|
|
||||||
Method mappingMethod,
|
|
||||||
String mappedElement,
|
|
||||||
Type sourceType,
|
|
||||||
Type targetType,
|
|
||||||
String targetPropertyName,
|
|
||||||
String dateFormat,
|
|
||||||
List<TypeMirror> qualifiers,
|
|
||||||
String sourceReference );
|
|
||||||
|
|
||||||
}
|
|
@ -20,10 +20,12 @@ package org.mapstruct.ap.processor;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import javax.annotation.processing.Messager;
|
import javax.annotation.processing.Messager;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
@ -33,14 +35,17 @@ import javax.lang.model.util.ElementFilter;
|
|||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.Types;
|
import javax.lang.model.util.Types;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.BeanMappingMethod;
|
import org.mapstruct.ap.model.BeanMappingMethod;
|
||||||
import org.mapstruct.ap.model.Decorator;
|
import org.mapstruct.ap.model.Decorator;
|
||||||
|
import org.mapstruct.ap.model.DefaultMapperReference;
|
||||||
import org.mapstruct.ap.model.DelegatingMethod;
|
import org.mapstruct.ap.model.DelegatingMethod;
|
||||||
import org.mapstruct.ap.model.EnumMappingMethod;
|
import org.mapstruct.ap.model.EnumMappingMethod;
|
||||||
import org.mapstruct.ap.model.IterableMappingMethod;
|
import org.mapstruct.ap.model.IterableMappingMethod;
|
||||||
import org.mapstruct.ap.model.MapMappingMethod;
|
import org.mapstruct.ap.model.MapMappingMethod;
|
||||||
import org.mapstruct.ap.model.Mapper;
|
import org.mapstruct.ap.model.Mapper;
|
||||||
import org.mapstruct.ap.model.MapperReference;
|
import org.mapstruct.ap.model.MapperReference;
|
||||||
|
import org.mapstruct.ap.model.MappingContext;
|
||||||
import org.mapstruct.ap.model.MappingMethod;
|
import org.mapstruct.ap.model.MappingMethod;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.model.common.TypeFactory;
|
import org.mapstruct.ap.model.common.TypeFactory;
|
||||||
@ -48,7 +53,7 @@ import org.mapstruct.ap.model.source.Mapping;
|
|||||||
import org.mapstruct.ap.model.source.SourceMethod;
|
import org.mapstruct.ap.model.source.SourceMethod;
|
||||||
import org.mapstruct.ap.option.Options;
|
import org.mapstruct.ap.option.Options;
|
||||||
import org.mapstruct.ap.prism.DecoratedWithPrism;
|
import org.mapstruct.ap.prism.DecoratedWithPrism;
|
||||||
import org.mapstruct.ap.model.MappingContext;
|
import org.mapstruct.ap.prism.MapperPrism;
|
||||||
import org.mapstruct.ap.processor.creation.MappingResolverImpl;
|
import org.mapstruct.ap.processor.creation.MappingResolverImpl;
|
||||||
import org.mapstruct.ap.util.MapperConfig;
|
import org.mapstruct.ap.util.MapperConfig;
|
||||||
|
|
||||||
@ -60,7 +65,6 @@ import org.mapstruct.ap.util.MapperConfig;
|
|||||||
*/
|
*/
|
||||||
public class MapperCreationProcessor implements ModelElementProcessor<List<SourceMethod>, Mapper> {
|
public class MapperCreationProcessor implements ModelElementProcessor<List<SourceMethod>, Mapper> {
|
||||||
|
|
||||||
|
|
||||||
private Elements elementUtils;
|
private Elements elementUtils;
|
||||||
private Types typeUtils;
|
private Types typeUtils;
|
||||||
private Messager messager;
|
private Messager messager;
|
||||||
@ -75,16 +79,20 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
this.messager = context.getMessager();
|
this.messager = context.getMessager();
|
||||||
this.options = context.getOptions();
|
this.options = context.getOptions();
|
||||||
this.typeFactory = context.getTypeFactory();
|
this.typeFactory = context.getTypeFactory();
|
||||||
|
|
||||||
|
List<MapperReference> mapperReferences = initReferencedMappers( mapperTypeElement );
|
||||||
|
|
||||||
MappingContext ctx = new MappingContext(
|
MappingContext ctx = new MappingContext(
|
||||||
typeFactory,
|
typeFactory,
|
||||||
elementUtils,
|
elementUtils,
|
||||||
typeUtils,
|
typeUtils,
|
||||||
messager,
|
messager,
|
||||||
options,
|
options,
|
||||||
|
new MappingResolverImpl( context.getMessager(), elementUtils, typeUtils, typeFactory, sourceModel, mapperReferences ),
|
||||||
mapperTypeElement,
|
mapperTypeElement,
|
||||||
sourceModel
|
sourceModel,
|
||||||
|
mapperReferences
|
||||||
);
|
);
|
||||||
ctx.setMappingResolver( new MappingResolverImpl( ctx ) );
|
|
||||||
this.mappingContext = ctx;
|
this.mappingContext = ctx;
|
||||||
return getMapper( mapperTypeElement, sourceModel );
|
return getMapper( mapperTypeElement, sourceModel );
|
||||||
}
|
}
|
||||||
@ -94,6 +102,27 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
return 1000;
|
return 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<MapperReference> initReferencedMappers(TypeElement element) {
|
||||||
|
List<MapperReference> result = new LinkedList<MapperReference>();
|
||||||
|
List<String> variableNames = new LinkedList<String>();
|
||||||
|
|
||||||
|
MapperConfig mapperPrism = MapperConfig.getInstanceOn( element );
|
||||||
|
|
||||||
|
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
|
||||||
|
DefaultMapperReference mapperReference = DefaultMapperReference.getInstance(
|
||||||
|
typeFactory.getType( usedMapper ),
|
||||||
|
MapperPrism.getInstanceOn( typeUtils.asElement( usedMapper ) ) != null,
|
||||||
|
typeFactory,
|
||||||
|
variableNames
|
||||||
|
);
|
||||||
|
|
||||||
|
result.add( mapperReference );
|
||||||
|
variableNames.add( mapperReference.getVariableName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private Mapper getMapper(TypeElement element, List<SourceMethod> methods) {
|
private Mapper getMapper(TypeElement element, List<SourceMethod> methods) {
|
||||||
List<MapperReference> mapperReferences = mappingContext.getMapperReferences();
|
List<MapperReference> mapperReferences = mappingContext.getMapperReferences();
|
||||||
List<MappingMethod> mappingMethods = getMappingMethods( methods );
|
List<MappingMethod> mappingMethods = getMappingMethods( methods );
|
||||||
|
@ -18,26 +18,29 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.processor.creation;
|
package org.mapstruct.ap.processor.creation;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.MappingResolver;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.mapstruct.ap.conversion.ConversionProvider;
|
import org.mapstruct.ap.conversion.ConversionProvider;
|
||||||
import org.mapstruct.ap.conversion.Conversions;
|
import org.mapstruct.ap.conversion.Conversions;
|
||||||
import org.mapstruct.ap.model.assignment.Assignment;
|
|
||||||
import org.mapstruct.ap.model.MapperReference;
|
|
||||||
import org.mapstruct.ap.model.MappingContext;
|
|
||||||
import org.mapstruct.ap.model.VirtualMappingMethod;
|
|
||||||
import org.mapstruct.ap.model.AssignmentFactory;
|
import org.mapstruct.ap.model.AssignmentFactory;
|
||||||
import org.mapstruct.ap.model.Direct;
|
import org.mapstruct.ap.model.Direct;
|
||||||
|
import org.mapstruct.ap.model.MapperReference;
|
||||||
|
import org.mapstruct.ap.model.MappingContext.MappingResolver;
|
||||||
|
import org.mapstruct.ap.model.VirtualMappingMethod;
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.model.common.DefaultConversionContext;
|
import org.mapstruct.ap.model.common.DefaultConversionContext;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
import org.mapstruct.ap.model.common.TypeFactory;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
import org.mapstruct.ap.model.source.SourceMethod;
|
import org.mapstruct.ap.model.source.SourceMethod;
|
||||||
import org.mapstruct.ap.model.source.builtin.BuiltInMappingMethods;
|
import org.mapstruct.ap.model.source.builtin.BuiltInMappingMethods;
|
||||||
@ -46,50 +49,47 @@ import org.mapstruct.ap.model.source.selector.MethodSelectors;
|
|||||||
import org.mapstruct.ap.util.Strings;
|
import org.mapstruct.ap.util.Strings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves class is responsible for resolving the most suitable way to resolve a mapping from source to target.
|
* The one and only implementation of {@link MappingResolver}. The class has been split into an interface an
|
||||||
*
|
* implementation for the sake of avoiding package dependencies. Specifically, this implementation refers to classes
|
||||||
* There are 2 basic types of mappings:
|
* which should not be exposed to the {@code model} package.
|
||||||
* <ul>
|
|
||||||
* <li>conversions</li>
|
|
||||||
* <li>methods</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* conversions are essentially one line mappings, such as String to Integer and Integer to Long
|
|
||||||
* methods come in some varieties:
|
|
||||||
* <ul>
|
|
||||||
* <li>referenced mapping methods, these are methods implemented (or referenced) by the user. Sometimes indicated
|
|
||||||
* with the 'uses' in the mapping annotations or part of the abstract mapper class</li>
|
|
||||||
* <li>generated mapping methods (by means of MapStruct)</li>
|
|
||||||
* <li>built in methods</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
*
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public class MappingResolverImpl implements MappingResolver {
|
public class MappingResolverImpl implements MappingResolver {
|
||||||
|
|
||||||
|
private final Messager messager;
|
||||||
|
private final Types typeUtils;
|
||||||
|
private final TypeFactory typeFactory;
|
||||||
|
|
||||||
|
private final List<SourceMethod> sourceModel;
|
||||||
|
private final List<MapperReference> mapperReferences;
|
||||||
|
|
||||||
private final Conversions conversions;
|
private final Conversions conversions;
|
||||||
private final BuiltInMappingMethods builtInMethods;
|
private final BuiltInMappingMethods builtInMethods;
|
||||||
private final MethodSelectors methodSelectors;
|
private final MethodSelectors methodSelectors;
|
||||||
private final MappingContext mappingContext;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private methods which are not present in the original mapper interface and are added to map certain property
|
* Private methods which are not present in the original mapper interface and are added to map certain property
|
||||||
types.
|
* types.
|
||||||
* @param mappingContext
|
|
||||||
*/
|
*/
|
||||||
public MappingResolverImpl( MappingContext mappingContext ) {
|
private final Set<VirtualMappingMethod> usedVirtualMappings = new HashSet<VirtualMappingMethod>();
|
||||||
this.conversions = new Conversions( mappingContext.getElementUtils(), mappingContext.getTypeFactory() );
|
|
||||||
this.builtInMethods = new BuiltInMappingMethods( mappingContext.getTypeFactory() );
|
|
||||||
this.methodSelectors = new MethodSelectors(
|
|
||||||
mappingContext.getTypeUtils(),
|
|
||||||
mappingContext.getElementUtils(),
|
|
||||||
mappingContext.getTypeFactory()
|
|
||||||
);
|
|
||||||
this.mappingContext = mappingContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public MappingResolverImpl(Messager messager, Elements elementUtils, Types typeUtils, TypeFactory typeFactory, List<SourceMethod> sourceModel, List<MapperReference> mapperReferences) {
|
||||||
|
this.messager = messager;
|
||||||
|
this.typeUtils = typeUtils;
|
||||||
|
this.typeFactory = typeFactory;
|
||||||
|
|
||||||
|
this.sourceModel = sourceModel;
|
||||||
|
this.mapperReferences = mapperReferences;
|
||||||
|
|
||||||
|
this.conversions = new Conversions( elementUtils, typeFactory );
|
||||||
|
this.builtInMethods = new BuiltInMappingMethods( typeFactory );
|
||||||
|
this.methodSelectors = new MethodSelectors(
|
||||||
|
typeUtils,
|
||||||
|
elementUtils,
|
||||||
|
typeFactory
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns a parameter assignment
|
* returns a parameter assignment
|
||||||
@ -122,74 +122,64 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
List<TypeMirror> qualifiers,
|
List<TypeMirror> qualifiers,
|
||||||
String sourceReference ) {
|
String sourceReference ) {
|
||||||
|
|
||||||
ResolvingAttempt attempt = new ResolvingAttempt( mappingMethod,
|
ResolvingAttempt attempt = new ResolvingAttempt( sourceModel,
|
||||||
|
mapperReferences,
|
||||||
|
mappingMethod,
|
||||||
mappedElement,
|
mappedElement,
|
||||||
targetPropertyName,
|
targetPropertyName,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
qualifiers,
|
qualifiers,
|
||||||
sourceReference,
|
sourceReference
|
||||||
conversions,
|
|
||||||
builtInMethods,
|
|
||||||
methodSelectors,
|
|
||||||
mappingContext
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return attempt.getTargetAssignment( sourceType, targetType );
|
return attempt.getTargetAssignment( sourceType, targetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<VirtualMappingMethod> getUsedVirtualMappings() {
|
||||||
|
return usedVirtualMappings;
|
||||||
|
}
|
||||||
|
|
||||||
private static class ResolvingAttempt {
|
private class ResolvingAttempt {
|
||||||
|
|
||||||
private final Method mappingMethod;
|
private final Method mappingMethod;
|
||||||
private final String mappedElement;
|
private final String mappedElement;
|
||||||
private final List<MapperReference> mapperReferences;
|
|
||||||
private final List<SourceMethod> methods;
|
private final List<SourceMethod> methods;
|
||||||
private final String targetPropertyName;
|
private final String targetPropertyName;
|
||||||
private final String dateFormat;
|
private final String dateFormat;
|
||||||
private final List<TypeMirror> qualifiers;
|
private final List<TypeMirror> qualifiers;
|
||||||
private final String sourceReference;
|
private final String sourceReference;
|
||||||
private final Conversions conversions;
|
|
||||||
private final BuiltInMappingMethods builtInMethods;
|
|
||||||
private final MethodSelectors methodSelectors;
|
|
||||||
private final MappingContext mappingContext;
|
|
||||||
|
|
||||||
// resolving via 2 steps creates the possibillity of wrong matches, first builtin method matches,
|
// resolving via 2 steps creates the possibillity of wrong matches, first builtin method matches,
|
||||||
// second doesn't. In that case, the first builtin method should not lead to a virtual method
|
// second doesn't. In that case, the first builtin method should not lead to a virtual method
|
||||||
// so this set must be cleared.
|
// so this set must be cleared.
|
||||||
private final Set<VirtualMappingMethod> virtualMethodCandidates;
|
private final Set<VirtualMappingMethod> virtualMethodCandidates;
|
||||||
|
|
||||||
private ResolvingAttempt( Method mappingMethod,
|
private ResolvingAttempt( List<SourceMethod> sourceModel,
|
||||||
|
List<MapperReference> mapperReferences,
|
||||||
|
Method mappingMethod,
|
||||||
String mappedElement,
|
String mappedElement,
|
||||||
String targetPropertyName,
|
String targetPropertyName,
|
||||||
String dateFormat,
|
String dateFormat,
|
||||||
List<TypeMirror> qualifiers,
|
List<TypeMirror> qualifiers,
|
||||||
String sourceReference,
|
String sourceReference ) {
|
||||||
Conversions conversions,
|
|
||||||
BuiltInMappingMethods builtInMethods,
|
|
||||||
MethodSelectors methodSelectors,
|
|
||||||
MappingContext mappingContext ) {
|
|
||||||
this.mappingMethod = mappingMethod;
|
this.mappingMethod = mappingMethod;
|
||||||
this.mappedElement = mappedElement;
|
this.mappedElement = mappedElement;
|
||||||
this.mapperReferences = mappingContext.getMapperReferences();
|
this.methods = sourceModel;
|
||||||
this.methods = mappingContext.getSourceModel();
|
|
||||||
this.targetPropertyName = targetPropertyName;
|
this.targetPropertyName = targetPropertyName;
|
||||||
this.dateFormat = dateFormat;
|
this.dateFormat = dateFormat;
|
||||||
this.qualifiers = qualifiers;
|
this.qualifiers = qualifiers;
|
||||||
this.sourceReference = sourceReference;
|
this.sourceReference = sourceReference;
|
||||||
this.conversions = conversions;
|
|
||||||
this.builtInMethods = builtInMethods;
|
|
||||||
this.methodSelectors = methodSelectors;
|
|
||||||
this.mappingContext = mappingContext;
|
|
||||||
this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>();
|
this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Assignment getTargetAssignment( Type sourceType, Type targetType ) {
|
private Assignment getTargetAssignment( Type sourceType, Type targetType ) {
|
||||||
|
|
||||||
// first simpele mapping method
|
// first simple mapping method
|
||||||
Assignment referencedMethod = resolveViaMethod( sourceType, targetType );
|
Assignment referencedMethod = resolveViaMethod( sourceType, targetType );
|
||||||
if ( referencedMethod != null ) {
|
if ( referencedMethod != null ) {
|
||||||
referencedMethod.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
|
referencedMethod.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
|
||||||
mappingContext.getUsedVirtualMappings().addAll( virtualMethodCandidates );
|
usedVirtualMappings.addAll( virtualMethodCandidates );
|
||||||
return referencedMethod;
|
return referencedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,21 +199,21 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
// 2 step method, first: method(method(souurce))
|
// 2 step method, first: method(method(souurce))
|
||||||
referencedMethod = resolveViaMethodAndMethod( sourceType, targetType );
|
referencedMethod = resolveViaMethodAndMethod( sourceType, targetType );
|
||||||
if ( referencedMethod != null ) {
|
if ( referencedMethod != null ) {
|
||||||
mappingContext.getUsedVirtualMappings().addAll( virtualMethodCandidates );
|
usedVirtualMappings.addAll( virtualMethodCandidates );
|
||||||
return referencedMethod;
|
return referencedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 step method, then: method(conversion(souurce))
|
// 2 step method, then: method(conversion(souurce))
|
||||||
referencedMethod = resolveViaConversionAndMethod( sourceType, targetType );
|
referencedMethod = resolveViaConversionAndMethod( sourceType, targetType );
|
||||||
if ( referencedMethod != null ) {
|
if ( referencedMethod != null ) {
|
||||||
mappingContext.getUsedVirtualMappings().addAll( virtualMethodCandidates );
|
usedVirtualMappings.addAll( virtualMethodCandidates );
|
||||||
return referencedMethod;
|
return referencedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 step method, finally: conversion(method(souurce))
|
// 2 step method, finally: conversion(method(souurce))
|
||||||
conversion = resolveViaMethodAndConversion( sourceType, targetType );
|
conversion = resolveViaMethodAndConversion( sourceType, targetType );
|
||||||
if ( conversion != null ) {
|
if ( conversion != null ) {
|
||||||
mappingContext.getUsedVirtualMappings().addAll( virtualMethodCandidates );
|
usedVirtualMappings.addAll( virtualMethodCandidates );
|
||||||
return conversion;
|
return conversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +229,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConversionContext ctx =
|
ConversionContext ctx =
|
||||||
new DefaultConversionContext( mappingContext.getTypeFactory(), targetType, dateFormat );
|
new DefaultConversionContext( typeFactory, targetType, dateFormat );
|
||||||
return conversionProvider.to( ctx );
|
return conversionProvider.to( ctx );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +244,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
SourceMethod matchingSourceMethod = getBestMatch( methods, sourceType, targetType );
|
SourceMethod matchingSourceMethod = getBestMatch( methods, sourceType, targetType );
|
||||||
|
|
||||||
if ( matchingSourceMethod != null ) {
|
if ( matchingSourceMethod != null ) {
|
||||||
return getMappingMethodReference( matchingSourceMethod, mapperReferences, targetType );
|
return getMappingMethodReference( matchingSourceMethod, targetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
// then a matching built-in method
|
// then a matching built-in method
|
||||||
@ -264,7 +254,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
if ( matchingBuiltInMethod != null ) {
|
if ( matchingBuiltInMethod != null ) {
|
||||||
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
|
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
|
||||||
ConversionContext ctx =
|
ConversionContext ctx =
|
||||||
new DefaultConversionContext( mappingContext.getTypeFactory(), targetType, dateFormat );
|
new DefaultConversionContext( typeFactory, targetType, dateFormat );
|
||||||
Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx );
|
Assignment methodReference = AssignmentFactory.createMethodReference( matchingBuiltInMethod, ctx );
|
||||||
methodReference.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
|
methodReference.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
|
||||||
return methodReference;
|
return methodReference;
|
||||||
@ -424,7 +414,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
returnType,
|
returnType,
|
||||||
Strings.join( candidates, ", " ) );
|
Strings.join( candidates, ", " ) );
|
||||||
|
|
||||||
mappingMethod.printMessage( mappingContext.getMessager(), Kind.ERROR, errorMsg );
|
mappingMethod.printMessage( messager, Kind.ERROR, errorMsg );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !candidates.isEmpty() ) {
|
if ( !candidates.isEmpty() ) {
|
||||||
@ -435,9 +425,8 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Assignment getMappingMethodReference( SourceMethod method,
|
private Assignment getMappingMethodReference( SourceMethod method,
|
||||||
List<MapperReference> mapperReferences,
|
|
||||||
Type targetType ) {
|
Type targetType ) {
|
||||||
MapperReference mapperReference = findMapperReference( mapperReferences, method );
|
MapperReference mapperReference = findMapperReference( method );
|
||||||
|
|
||||||
return AssignmentFactory.createMethodReference(
|
return AssignmentFactory.createMethodReference(
|
||||||
method,
|
method,
|
||||||
@ -446,7 +435,7 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MapperReference findMapperReference( List<MapperReference> mapperReferences, SourceMethod method ) {
|
private MapperReference findMapperReference( SourceMethod method ) {
|
||||||
for ( MapperReference ref : mapperReferences ) {
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
return ref;
|
return ref;
|
||||||
@ -513,14 +502,14 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
// constructor which accepts the source type
|
// constructor which accepts the source type
|
||||||
|
|
||||||
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty()
|
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty()
|
||||||
? mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror()
|
? typeFactory.getType( Object.class ).getTypeMirror()
|
||||||
: sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
: sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
|
|
||||||
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty()
|
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty()
|
||||||
? mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror()
|
? typeFactory.getType( Object.class ).getTypeMirror()
|
||||||
: targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
: targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
|
|
||||||
return mappingContext.getTypeUtils().isAssignable( sourceElementType, targetElementType );
|
return typeUtils.isAssignable( sourceElementType, targetElementType );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -544,8 +533,8 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
TypeMirror targetValueType;
|
TypeMirror targetValueType;
|
||||||
|
|
||||||
if ( sourceType.getTypeParameters().isEmpty() ) {
|
if ( sourceType.getTypeParameters().isEmpty() ) {
|
||||||
sourceKeyType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
sourceKeyType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||||
sourceValueType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
sourceValueType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
@ -553,16 +542,16 @@ public class MappingResolverImpl implements MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( targetType.getTypeParameters().isEmpty() ) {
|
if ( targetType.getTypeParameters().isEmpty() ) {
|
||||||
targetKeyType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
targetKeyType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||||
targetValueType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
targetValueType = typeFactory.getType( Object.class ).getTypeMirror();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
targetKeyType = targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
targetKeyType = targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
targetValueType = targetType.getTypeParameters().get( 1 ).getTypeMirror();
|
targetValueType = targetType.getTypeParameters().get( 1 ).getTypeMirror();
|
||||||
}
|
}
|
||||||
|
|
||||||
return mappingContext.getTypeUtils().isAssignable( sourceKeyType, targetKeyType )
|
return typeUtils.isAssignable( sourceKeyType, targetKeyType )
|
||||||
&& mappingContext.getTypeUtils().isAssignable( sourceValueType, targetValueType );
|
&& typeUtils.isAssignable( sourceValueType, targetValueType );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user