mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#302 refactoring of MappingCreationProcessor: using Builders to address smaller concerns
This commit is contained in:
parent
3e411e085e
commit
d42216ee4f
@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.conversion;
|
package org.mapstruct.ap.conversion;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.model.assignment.TypeConversion;
|
import org.mapstruct.ap.model.TypeConversion;
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,8 +23,8 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.model.assignment.AssignmentFactory;
|
import org.mapstruct.ap.model.AssignmentFactory;
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.conversion;
|
package org.mapstruct.ap.conversion;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,9 +21,9 @@ package org.mapstruct.ap.conversion;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.model.assignment.AssignmentFactory;
|
import org.mapstruct.ap.model.AssignmentFactory;
|
||||||
import org.mapstruct.ap.model.assignment.TypeConversion;
|
import org.mapstruct.ap.model.TypeConversion;
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* 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 java.util.Set;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
import org.mapstruct.ap.model.source.Method;
|
||||||
|
import org.mapstruct.ap.model.source.SourceMethod;
|
||||||
|
import org.mapstruct.ap.model.source.builtin.BuiltInMethod;
|
||||||
|
import org.mapstruct.ap.model.source.selector.MethodSelectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class for creating all types of assignments
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class AssignmentFactory {
|
||||||
|
|
||||||
|
private AssignmentFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Assignment createTypeConversion(Set<Type> importTypes, List<Type> exceptionTypes, String expression) {
|
||||||
|
return new TypeConversion( importTypes, exceptionTypes, expression );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Assignment createMethodReference(Method method, MapperReference declaringMapper,
|
||||||
|
Type targetType) {
|
||||||
|
return new MethodReference( method, declaringMapper, targetType );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Assignment createMethodReference(BuiltInMethod method, ConversionContext contextParam) {
|
||||||
|
return new MethodReference( method, contextParam );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Direct createSimple(String sourceRef) {
|
||||||
|
return new Direct( sourceRef );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FactoryMethod createFactoryMethod( Type returnType, MappingContext ctx ) {
|
||||||
|
FactoryMethod result = null;
|
||||||
|
for ( SourceMethod method : ctx.getSourceModel() ) {
|
||||||
|
if ( !method.overridesMethod() && !method.isIterableMapping() && !method.isMapMapping()
|
||||||
|
&& method.getSourceParameters().isEmpty() ) {
|
||||||
|
|
||||||
|
List<Type> parameterTypes = MethodSelectors.getParameterTypes(
|
||||||
|
ctx.getTypeFactory(),
|
||||||
|
method.getParameters(),
|
||||||
|
null,
|
||||||
|
returnType
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( method.matches( parameterTypes, returnType ) ) {
|
||||||
|
if ( result == null ) {
|
||||||
|
MapperReference mapperReference = findMapperReference( ctx.getMapperReferences(), method );
|
||||||
|
result = new MethodReference( method, mapperReference, null );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Ambiguous factory methods: \"%s\" conflicts with \"%s\".",
|
||||||
|
result,
|
||||||
|
method
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MapperReference findMapperReference( List<MapperReference> mapperReferences, SourceMethod method ) {
|
||||||
|
for ( MapperReference ref : mapperReferences ) {
|
||||||
|
if ( ref.getType().equals( method.getDeclaringMapper() ) ) {
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,15 +18,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import org.mapstruct.CollectionMappingStrategy;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.Parameter;
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
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.ReportingPolicy;
|
||||||
|
import org.mapstruct.ap.util.Executables;
|
||||||
|
import org.mapstruct.ap.util.MapperConfig;
|
||||||
|
import org.mapstruct.ap.util.Strings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one
|
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one
|
||||||
@ -44,7 +54,336 @@ public class BeanMappingMethod extends MappingMethod {
|
|||||||
|
|
||||||
private final FactoryMethod factoryMethod;
|
private final FactoryMethod factoryMethod;
|
||||||
|
|
||||||
public BeanMappingMethod(SourceMethod method,
|
public static class Builder {
|
||||||
|
|
||||||
|
private MappingContext ctx;
|
||||||
|
private SourceMethod method;
|
||||||
|
|
||||||
|
public Builder mappingContext(MappingContext mappingContext) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder souceMethod( SourceMethod sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BeanMappingMethod build() {
|
||||||
|
|
||||||
|
// fetch settings from element to implement
|
||||||
|
ReportingPolicy unmappedTargetPolicy = getEffectiveUnmappedTargetPolicy();
|
||||||
|
CollectionMappingStrategy cmStrategy = getEffectiveCollectionMappingStrategy();
|
||||||
|
|
||||||
|
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
|
||||||
|
Set<String> mappedTargetProperties = new HashSet<String>();
|
||||||
|
Set<String> ignoredTargetProperties = new HashSet<String>();
|
||||||
|
|
||||||
|
if ( !reportErrorIfMappedPropertiesDontExist() ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all target accessors
|
||||||
|
List<ExecutableElement> targetAccessors = new ArrayList<ExecutableElement>();
|
||||||
|
targetAccessors.addAll( method.getResultType().getSetters() );
|
||||||
|
targetAccessors.addAll( method.getResultType().getAlternativeTargetAccessors() );
|
||||||
|
|
||||||
|
for ( ExecutableElement targetAccessor : targetAccessors ) {
|
||||||
|
|
||||||
|
String targetPropertyName = Executables.getPropertyName( targetAccessor );
|
||||||
|
|
||||||
|
Mapping mapping = method.getMappingByTargetPropertyName( targetPropertyName );
|
||||||
|
|
||||||
|
if ( mapping != null && mapping.isIgnored() ) {
|
||||||
|
ignoredTargetProperties.add( targetPropertyName );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A target access is in general a setter method on the target object. However, in case of collections,
|
||||||
|
// the current target accessor can also be a getter method.
|
||||||
|
// The following if block, checks if the target accessor should be overruled by an add method.
|
||||||
|
if ( cmStrategy.equals( CollectionMappingStrategy.SETTER_PREFERRED )
|
||||||
|
|| cmStrategy.equals( CollectionMappingStrategy.ADDER_PREFERRED ) ) {
|
||||||
|
|
||||||
|
// first check if there's a setter method.
|
||||||
|
ExecutableElement adderMethod = null;
|
||||||
|
if ( Executables.isSetterMethod( targetAccessor ) ) {
|
||||||
|
Type targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType();
|
||||||
|
// ok, the current accessor is a setter. So now the strategy determines what to use
|
||||||
|
if ( cmStrategy.equals( CollectionMappingStrategy.ADDER_PREFERRED ) ) {
|
||||||
|
adderMethod = method.getResultType().getAdderForType( targetType, targetPropertyName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( Executables.isGetterMethod( targetAccessor ) ) {
|
||||||
|
// the current accessor is a getter (no setter available). But still, an add method is according
|
||||||
|
// to the above strategy (SETTER_PREFERRED || ADDER_PREFERRED) preferred over the getter.
|
||||||
|
Type targetType = ctx.getTypeFactory().getReturnType( targetAccessor );
|
||||||
|
adderMethod = method.getResultType().getAdderForType( targetType, targetPropertyName );
|
||||||
|
}
|
||||||
|
if ( adderMethod != null ) {
|
||||||
|
// an adder has been found (according strategy) so overrule current choice.
|
||||||
|
targetAccessor = adderMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMapping propertyMapping = null;
|
||||||
|
if ( mapping != null ) {
|
||||||
|
|
||||||
|
if ( mapping.getSourceParameterName() != null ) {
|
||||||
|
// this is a parameterized property, so sourceParameter.property
|
||||||
|
Parameter parameter = method.getSourceParameter( mapping.getSourceParameterName() );
|
||||||
|
|
||||||
|
PropertyMapping.PropertyMappingBuilder builder = new PropertyMapping.PropertyMappingBuilder();
|
||||||
|
propertyMapping = builder
|
||||||
|
.mappingContext( ctx )
|
||||||
|
.souceMethod( method )
|
||||||
|
.targetAccessor( targetAccessor )
|
||||||
|
.targetPropertyName( targetPropertyName )
|
||||||
|
.parameter( parameter )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( Executables.isSetterMethod( targetAccessor )
|
||||||
|
|| Executables.isGetterMethod( targetAccessor ) ) {
|
||||||
|
|
||||||
|
if ( !mapping.getConstant().isEmpty() ) {
|
||||||
|
// its a constant
|
||||||
|
PropertyMapping.ConstantMappingBuilder builder =
|
||||||
|
new PropertyMapping.ConstantMappingBuilder();
|
||||||
|
propertyMapping = builder
|
||||||
|
.mappingContext( ctx )
|
||||||
|
.sourceMethod( method )
|
||||||
|
.constantExpression( "\"" + mapping.getConstant() + "\"" )
|
||||||
|
.targetAccessor( targetAccessor )
|
||||||
|
.dateFormat( mapping.getDateFormat() )
|
||||||
|
.qualifiers( mapping.getQualifiers() )
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ( !mapping.getJavaExpression().isEmpty() ) {
|
||||||
|
// its an expression
|
||||||
|
PropertyMapping.JavaExpressionMappingBuilder builder =
|
||||||
|
new PropertyMapping.JavaExpressionMappingBuilder();
|
||||||
|
propertyMapping = builder
|
||||||
|
.mappingContext( ctx )
|
||||||
|
.souceMethod( method )
|
||||||
|
.javaExpression( mapping.getJavaExpression() )
|
||||||
|
.targetAccessor( targetAccessor )
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( propertyMapping == null ) {
|
||||||
|
for ( Parameter sourceParameter : method.getSourceParameters() ) {
|
||||||
|
PropertyMapping.PropertyMappingBuilder builder = new PropertyMapping.PropertyMappingBuilder();
|
||||||
|
PropertyMapping newPropertyMapping = builder
|
||||||
|
.mappingContext( ctx )
|
||||||
|
.souceMethod( method )
|
||||||
|
.targetAccessor( targetAccessor )
|
||||||
|
.targetPropertyName( targetPropertyName )
|
||||||
|
.parameter( sourceParameter )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if ( propertyMapping != null && newPropertyMapping != null ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
"Several possible source properties for target property \"" + targetPropertyName +
|
||||||
|
"\".",
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ( newPropertyMapping != null ) {
|
||||||
|
propertyMapping = newPropertyMapping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( propertyMapping != null ) {
|
||||||
|
propertyMappings.add( propertyMapping );
|
||||||
|
mappedTargetProperties.add( targetPropertyName );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> targetProperties = Executables.getPropertyNames( targetAccessors );
|
||||||
|
|
||||||
|
reportErrorForUnmappedTargetPropertiesIfRequired(
|
||||||
|
method,
|
||||||
|
unmappedTargetPolicy,
|
||||||
|
targetProperties,
|
||||||
|
mappedTargetProperties,
|
||||||
|
ignoredTargetProperties
|
||||||
|
);
|
||||||
|
FactoryMethod factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
|
||||||
|
return new BeanMappingMethod( method, propertyMappings, factoryMethod );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the effective policy for reporting unmapped getReturnType properties. If explicitly set via
|
||||||
|
* {@code Mapper}, this value will be returned. Otherwise the value from the corresponding processor option will
|
||||||
|
* be returned. If that is not set either, the default value from {@code Mapper#unmappedTargetPolicy()} will be
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param element The type declaring the generated mapper type
|
||||||
|
*
|
||||||
|
* @return The effective policy for reporting unmapped getReturnType properties.
|
||||||
|
*/
|
||||||
|
private ReportingPolicy getEffectiveUnmappedTargetPolicy() {
|
||||||
|
MapperConfig mapperSettings = MapperConfig.getInstanceOn( ctx.getMapperTypeElement() );
|
||||||
|
boolean setViaAnnotation = mapperSettings.isSetUnmappedTargetPolicy();
|
||||||
|
ReportingPolicy annotationValue = ReportingPolicy.valueOf( mapperSettings.unmappedTargetPolicy() );
|
||||||
|
|
||||||
|
if ( setViaAnnotation
|
||||||
|
|| ctx.getOptions().getUnmappedTargetPolicy() == null ) {
|
||||||
|
return annotationValue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ctx.getOptions().getUnmappedTargetPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CollectionMappingStrategy getEffectiveCollectionMappingStrategy() {
|
||||||
|
MapperConfig mapperSettings = MapperConfig.getInstanceOn( ctx.getMapperTypeElement() );
|
||||||
|
return mapperSettings.getCollectionMappingStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean reportErrorIfMappedPropertiesDontExist() {
|
||||||
|
// only report errors if this method itself is configured
|
||||||
|
if ( method.isConfiguredByReverseMappingMethod() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all target accessors
|
||||||
|
List<ExecutableElement> targetAccessors = new ArrayList<ExecutableElement>();
|
||||||
|
targetAccessors.addAll( method.getResultType().getSetters() );
|
||||||
|
targetAccessors.addAll( method.getResultType().getAlternativeTargetAccessors() );
|
||||||
|
|
||||||
|
Set<String> targetProperties = Executables.getPropertyNames( targetAccessors );
|
||||||
|
|
||||||
|
boolean foundUnmappedProperty = false;
|
||||||
|
|
||||||
|
for ( List<Mapping> mappedProperties : method.getMappings().values() ) {
|
||||||
|
for ( Mapping mappedProperty : mappedProperties ) {
|
||||||
|
if ( mappedProperty.isIgnored() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mappedProperty.getSourceParameterName() != null ) {
|
||||||
|
Parameter sourceParameter = method.getSourceParameter(
|
||||||
|
mappedProperty.getSourceParameterName()
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( sourceParameter == null ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Method has no parameter named \"%s\".",
|
||||||
|
mappedProperty.getSourceParameterName()
|
||||||
|
),
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedProperty.getMirror(),
|
||||||
|
mappedProperty.getSourceAnnotationValue()
|
||||||
|
);
|
||||||
|
foundUnmappedProperty = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( !hasSourceProperty( sourceParameter, mappedProperty.getSourcePropertyName() ) ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"The type of parameter \"%s\" has no property named \"%s\".",
|
||||||
|
mappedProperty.getSourceParameterName(),
|
||||||
|
mappedProperty.getSourcePropertyName()
|
||||||
|
),
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedProperty.getMirror(),
|
||||||
|
mappedProperty.getSourceAnnotationValue()
|
||||||
|
);
|
||||||
|
foundUnmappedProperty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( mappedProperty.getConstant().isEmpty()
|
||||||
|
&& mappedProperty.getJavaExpression().isEmpty()
|
||||||
|
&& !hasSourceProperty( mappedProperty.getSourcePropertyName() ) ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"No property named \"%s\" exists in source parameter(s).",
|
||||||
|
mappedProperty.getSourceName()
|
||||||
|
),
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedProperty.getMirror(),
|
||||||
|
mappedProperty.getSourceAnnotationValue()
|
||||||
|
);
|
||||||
|
foundUnmappedProperty = true;
|
||||||
|
}
|
||||||
|
if ( !targetProperties.contains( mappedProperty.getTargetName() ) ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Unknown property \"%s\" in return type %s.",
|
||||||
|
mappedProperty.getTargetName(),
|
||||||
|
method.getResultType()
|
||||||
|
),
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedProperty.getMirror(),
|
||||||
|
mappedProperty.getTargetAnnotationValue()
|
||||||
|
);
|
||||||
|
foundUnmappedProperty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !foundUnmappedProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportErrorForUnmappedTargetPropertiesIfRequired( SourceMethod method,
|
||||||
|
ReportingPolicy unmappedTargetPolicy,
|
||||||
|
Set<String> targetProperties,
|
||||||
|
Set<String> mappedTargetProperties,
|
||||||
|
Set<String> ignoredTargetProperties ) {
|
||||||
|
|
||||||
|
Set<String> unmappedTargetProperties = new HashSet<String>();
|
||||||
|
|
||||||
|
for ( String property : targetProperties ) {
|
||||||
|
if ( !mappedTargetProperties.contains( property ) && !ignoredTargetProperties.contains( property ) ) {
|
||||||
|
unmappedTargetProperties.add( property );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !unmappedTargetProperties.isEmpty() && unmappedTargetPolicy.requiresReport() ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
unmappedTargetPolicy.getDiagnosticKind(),
|
||||||
|
MessageFormat.format(
|
||||||
|
"Unmapped target {0,choice,1#property|1<properties}: \"{1}\"",
|
||||||
|
unmappedTargetProperties.size(),
|
||||||
|
Strings.join( unmappedTargetProperties, ", " )
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasSourceProperty( String propertyName ) {
|
||||||
|
for ( Parameter parameter : method.getSourceParameters() ) {
|
||||||
|
if ( hasSourceProperty( parameter, propertyName ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasSourceProperty( Parameter parameter, String propertyName ) {
|
||||||
|
List<ExecutableElement> getters = parameter.getType().getGetters();
|
||||||
|
return Executables.getPropertyNames( getters ).contains( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeanMappingMethod(SourceMethod method,
|
||||||
List<PropertyMapping> propertyMappings,
|
List<PropertyMapping> propertyMappings,
|
||||||
FactoryMethod factoryMethod) {
|
FactoryMethod factoryMethod) {
|
||||||
super( method );
|
super( method );
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model.assignment;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.ModelElement;
|
import org.mapstruct.ap.model.common.ModelElement;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
@ -18,11 +18,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.Parameter;
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
import org.mapstruct.ap.model.source.EnumMapping;
|
import org.mapstruct.ap.model.source.EnumMapping;
|
||||||
|
import org.mapstruct.ap.model.source.Mapping;
|
||||||
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.util.Strings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingMethod} which maps one enum type to another, optionally configured by one or more
|
* A {@link MappingMethod} which maps one enum type to another, optionally configured by one or more
|
||||||
@ -34,7 +41,165 @@ public class EnumMappingMethod extends MappingMethod {
|
|||||||
|
|
||||||
private final List<EnumMapping> enumMappings;
|
private final List<EnumMapping> enumMappings;
|
||||||
|
|
||||||
public EnumMappingMethod(Method method, List<EnumMapping> enumMappings) {
|
public static class Builder {
|
||||||
|
|
||||||
|
private SourceMethod method;
|
||||||
|
private MappingContext ctx;
|
||||||
|
|
||||||
|
public Builder mappingContext( MappingContext mappingContext ) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder souceMethod( SourceMethod sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnumMappingMethod build() {
|
||||||
|
|
||||||
|
if ( !reportErrorIfMappedEnumConstantsDontExist( method )
|
||||||
|
|| !reportErrorIfSourceEnumConstantsWithoutCorrespondingTargetConstantAreNotMapped( method ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EnumMapping> enumMappings = new ArrayList<EnumMapping>();
|
||||||
|
|
||||||
|
List<String> sourceEnumConstants
|
||||||
|
= method.getSourceParameters().iterator().next().getType().getEnumConstants();
|
||||||
|
Map<String, List<Mapping>> mappings = method.getMappings();
|
||||||
|
|
||||||
|
for ( String enumConstant : sourceEnumConstants ) {
|
||||||
|
List<Mapping> mappedConstants = mappings.get( enumConstant );
|
||||||
|
|
||||||
|
if ( mappedConstants == null ) {
|
||||||
|
enumMappings.add( new EnumMapping( enumConstant, enumConstant ) );
|
||||||
|
}
|
||||||
|
else if ( mappedConstants.size() == 1 ) {
|
||||||
|
enumMappings.add( new EnumMapping(
|
||||||
|
enumConstant, mappedConstants.iterator().next().getTargetName() ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List<String> targetConstants = new ArrayList<String>( mappedConstants.size() );
|
||||||
|
for ( Mapping mapping : mappedConstants ) {
|
||||||
|
targetConstants.add( mapping.getTargetName() );
|
||||||
|
}
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"One enum constant must not be mapped to more than one target constant, "
|
||||||
|
+ "but constant %s is mapped to %s.",
|
||||||
|
enumConstant,
|
||||||
|
Strings.join( targetConstants, ", " )
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EnumMappingMethod( method, enumMappings );
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean reportErrorIfMappedEnumConstantsDontExist( SourceMethod method ) {
|
||||||
|
// only report errors if this method itself is configured
|
||||||
|
if ( method.isConfiguredByReverseMappingMethod() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> sourceEnumConstants =
|
||||||
|
method.getSourceParameters().iterator().next().getType().getEnumConstants();
|
||||||
|
List<String> targetEnumConstants = method.getReturnType().getEnumConstants();
|
||||||
|
|
||||||
|
boolean foundIncorrectMapping = false;
|
||||||
|
|
||||||
|
for ( List<Mapping> mappedConstants : method.getMappings().values() ) {
|
||||||
|
for ( Mapping mappedConstant : mappedConstants ) {
|
||||||
|
if ( mappedConstant.getSourceName() == null ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
"A source constant must be specified for mappings of an enum mapping method.",
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedConstant.getMirror()
|
||||||
|
);
|
||||||
|
foundIncorrectMapping = true;
|
||||||
|
}
|
||||||
|
else if ( !sourceEnumConstants.contains( mappedConstant.getSourceName() ) ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Constant %s doesn't exist in enum type %s.",
|
||||||
|
mappedConstant.getSourceName(),
|
||||||
|
method.getSourceParameters().iterator().next().getType()
|
||||||
|
),
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedConstant.getMirror(),
|
||||||
|
mappedConstant.getSourceAnnotationValue()
|
||||||
|
);
|
||||||
|
foundIncorrectMapping = true;
|
||||||
|
}
|
||||||
|
if ( mappedConstant.getTargetName() == null ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
"A target constant must be specified for mappings of an enum mapping method.",
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedConstant.getMirror()
|
||||||
|
);
|
||||||
|
foundIncorrectMapping = true;
|
||||||
|
}
|
||||||
|
else if ( !targetEnumConstants.contains( mappedConstant.getTargetName() ) ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Constant %s doesn't exist in enum type %s.",
|
||||||
|
mappedConstant.getTargetName(),
|
||||||
|
method.getReturnType()
|
||||||
|
),
|
||||||
|
method.getExecutable(),
|
||||||
|
mappedConstant.getMirror(),
|
||||||
|
mappedConstant.getTargetAnnotationValue()
|
||||||
|
);
|
||||||
|
foundIncorrectMapping = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !foundIncorrectMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean reportErrorIfSourceEnumConstantsWithoutCorrespondingTargetConstantAreNotMapped(
|
||||||
|
SourceMethod method ) {
|
||||||
|
|
||||||
|
List<String> sourceEnumConstants =
|
||||||
|
method.getSourceParameters().iterator().next().getType().getEnumConstants();
|
||||||
|
List<String> targetEnumConstants = method.getReturnType().getEnumConstants();
|
||||||
|
Set<String> mappedSourceEnumConstants = method.getMappings().keySet();
|
||||||
|
List<String> unmappedSourceEnumConstants = new ArrayList<String>();
|
||||||
|
|
||||||
|
for ( String sourceEnumConstant : sourceEnumConstants ) {
|
||||||
|
if ( !targetEnumConstants.contains( sourceEnumConstant )
|
||||||
|
&& !mappedSourceEnumConstants.contains( sourceEnumConstant ) ) {
|
||||||
|
unmappedSourceEnumConstants.add( sourceEnumConstant );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !unmappedSourceEnumConstants.isEmpty() ) {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"The following constants from the source enum have no corresponding constant in the "
|
||||||
|
+ "target enum and must be be mapped via @Mapping: %s",
|
||||||
|
Strings.join( unmappedSourceEnumConstants, ", " )
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmappedSourceEnumConstants.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumMappingMethod( Method method, List<EnumMapping> enumMappings ) {
|
||||||
super( method );
|
super( method );
|
||||||
this.enumMappings = enumMappings;
|
this.enumMappings = enumMappings;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.mapstruct.ap.model.assignment.TypeConversion;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import org.mapstruct.ap.model.assignment.SetterWrapper;
|
||||||
import org.mapstruct.ap.model.common.Parameter;
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
@ -37,7 +41,71 @@ public class IterableMappingMethod extends MappingMethod {
|
|||||||
private final FactoryMethod factoryMethod;
|
private final FactoryMethod factoryMethod;
|
||||||
private final boolean overridden;
|
private final boolean overridden;
|
||||||
|
|
||||||
public IterableMappingMethod(Method method, Assignment parameterAssignment, FactoryMethod factoryMethod) {
|
public static class Builder {
|
||||||
|
|
||||||
|
private Method method;
|
||||||
|
private MappingContext ctx;
|
||||||
|
private String dateFormat;
|
||||||
|
private List<TypeMirror> qualifiers;
|
||||||
|
|
||||||
|
public Builder mappingContext( MappingContext mappingContext ) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder method( Method sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder dateFormat( String dateFormat ) {
|
||||||
|
this.dateFormat = dateFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder qualifiers( List<TypeMirror> qualifiers ) {
|
||||||
|
this.qualifiers = qualifiers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IterableMappingMethod build( ) {
|
||||||
|
Type sourceElementType =
|
||||||
|
method.getSourceParameters().iterator().next().getType().getTypeParameters().get( 0 );
|
||||||
|
Type targetElementType =
|
||||||
|
method.getResultType().getTypeParameters().get( 0 );
|
||||||
|
String conversionStr =
|
||||||
|
Strings.getSaveVariableName( sourceElementType.getName(), method.getParameterNames() );
|
||||||
|
|
||||||
|
|
||||||
|
Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method,
|
||||||
|
"collection element",
|
||||||
|
sourceElementType,
|
||||||
|
targetElementType,
|
||||||
|
null, // there is no targetPropertyName
|
||||||
|
dateFormat,
|
||||||
|
qualifiers,
|
||||||
|
conversionStr
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( assignment == null ) {
|
||||||
|
String message = String.format(
|
||||||
|
"Can't create implementation of method %s. Found no method nor built-in conversion for mapping "
|
||||||
|
+ "source element type into target element type.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
method.printMessage( ctx.getMessager(), Diagnostic.Kind.ERROR, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
// target accessor is setter, so decorate assignment as setter
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
|
||||||
|
FactoryMethod factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
|
||||||
|
return new IterableMappingMethod( method, assignment, factoryMethod );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private IterableMappingMethod(Method method, Assignment parameterAssignment, FactoryMethod factoryMethod) {
|
||||||
super( method );
|
super( method );
|
||||||
this.elementAssignment = parameterAssignment;
|
this.elementAssignment = parameterAssignment;
|
||||||
this.factoryMethod = factoryMethod;
|
this.factoryMethod = factoryMethod;
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.mapstruct.ap.model.assignment.TypeConversion;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import org.mapstruct.ap.model.assignment.LocalVarWrapper;
|
||||||
import org.mapstruct.ap.model.common.Parameter;
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.model.source.Method;
|
import org.mapstruct.ap.model.source.Method;
|
||||||
@ -38,7 +42,101 @@ public class MapMappingMethod extends MappingMethod {
|
|||||||
private final FactoryMethod factoryMethod;
|
private final FactoryMethod factoryMethod;
|
||||||
private final boolean overridden;
|
private final boolean overridden;
|
||||||
|
|
||||||
public MapMappingMethod(Method method, Assignment keyAssignment, Assignment valueAssignment,
|
public static class Builder {
|
||||||
|
|
||||||
|
private String keyDateFormat;
|
||||||
|
private String valueDateFormat;
|
||||||
|
private List<TypeMirror> keyQualifiers;
|
||||||
|
private List<TypeMirror> valueQualifiers;
|
||||||
|
private Method method;
|
||||||
|
private MappingContext ctx;
|
||||||
|
|
||||||
|
public Builder mappingContext( MappingContext mappingContext ) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder method( Method sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder keyDateFormat( String keyDateFormat ) {
|
||||||
|
this.keyDateFormat = keyDateFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder valueDateFormat( String valueDateFormat ) {
|
||||||
|
this.valueDateFormat = valueDateFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder keyQualifiers( List<TypeMirror> keyQualifiers ) {
|
||||||
|
this.keyQualifiers = keyQualifiers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder valueQualifiers( List<TypeMirror> valueQualifiers ) {
|
||||||
|
this.valueQualifiers = valueQualifiers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapMappingMethod build() {
|
||||||
|
|
||||||
|
List<Type> sourceTypeParams = method.getSourceParameters().iterator().next().getType().getTypeParameters();
|
||||||
|
List<Type> resultTypeParams = method.getResultType().getTypeParameters();
|
||||||
|
|
||||||
|
// find mapping method or conversion for key
|
||||||
|
Type keySourceType = sourceTypeParams.get( 0 );
|
||||||
|
Type keyTargetType = resultTypeParams.get( 0 );
|
||||||
|
|
||||||
|
Assignment keyAssignment = ctx.getMappingResolver().getTargetAssignment( method,
|
||||||
|
"map key",
|
||||||
|
keySourceType,
|
||||||
|
keyTargetType,
|
||||||
|
null, // there is no targetPropertyName
|
||||||
|
keyDateFormat,
|
||||||
|
keyQualifiers,
|
||||||
|
"entry.getKey()"
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( keyAssignment == null ) {
|
||||||
|
String message = String.format( "Can't create implementation of method %s. Found no method nor "
|
||||||
|
+ "built-in conversion for mapping source key type to target key type.", method );
|
||||||
|
method.printMessage( ctx.getMessager(), Diagnostic.Kind.ERROR, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
// find mapping method or conversion for value
|
||||||
|
Type valueSourceType = sourceTypeParams.get( 1 );
|
||||||
|
Type valueTargetType = resultTypeParams.get( 1 );
|
||||||
|
|
||||||
|
Assignment valueAssignment = ctx.getMappingResolver().getTargetAssignment( method,
|
||||||
|
"map value",
|
||||||
|
valueSourceType,
|
||||||
|
valueTargetType,
|
||||||
|
null, // there is no targetPropertyName
|
||||||
|
valueDateFormat,
|
||||||
|
valueQualifiers,
|
||||||
|
"entry.getValue()"
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( valueAssignment == null ) {
|
||||||
|
String message = String.format( "Can't create implementation of method %s. Found no method nor "
|
||||||
|
+ "built-in conversion for mapping source value type to target value type.", method );
|
||||||
|
method.printMessage( ctx.getMessager(), Diagnostic.Kind.ERROR, message );
|
||||||
|
}
|
||||||
|
|
||||||
|
FactoryMethod factoryMethod = AssignmentFactory.createFactoryMethod( method.getReturnType(), ctx );
|
||||||
|
|
||||||
|
keyAssignment = new LocalVarWrapper( keyAssignment, method.getThrownTypes() );
|
||||||
|
valueAssignment = new LocalVarWrapper( valueAssignment, method.getThrownTypes() );
|
||||||
|
|
||||||
|
return new MapMappingMethod( method, keyAssignment, valueAssignment, factoryMethod );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private MapMappingMethod(Method method, Assignment keyAssignment, Assignment valueAssignment,
|
||||||
FactoryMethod factoryMethod) {
|
FactoryMethod factoryMethod) {
|
||||||
super( method );
|
super( method );
|
||||||
|
|
||||||
|
@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* 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 java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.lang.model.util.Elements;
|
||||||
|
import javax.lang.model.util.Types;
|
||||||
|
import org.mapstruct.ap.model.common.TypeFactory;
|
||||||
|
import org.mapstruct.ap.model.source.SourceMethod;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The following mappers make use of this context:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link BeanMappingMethod.Builder}</li>
|
||||||
|
* <li>{@link PropertyMappingMethod.Builder}</li>
|
||||||
|
* <li>{@link IterableMappingMethod.Builder}</li>
|
||||||
|
* <li>{@link MapMappingMethod.Builder}</li>
|
||||||
|
* <li>{@link EnumMappingMethod.Builder}</li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The context provides:
|
||||||
|
* <ul>
|
||||||
|
* <li>Input for the building process, such as the source model (mapping methods found) and mapper references.</li>
|
||||||
|
* <li>Required factory, utility, reporting methods for building the mappings.</li>
|
||||||
|
* <li>Means to harbor results produced by the builders, such as forged- and virtual mapping methods that should be
|
||||||
|
* generated in a later stage.</li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Sjaak Derksen
|
||||||
|
*/
|
||||||
|
public class MappingContext {
|
||||||
|
|
||||||
|
private final TypeFactory typeFactory;
|
||||||
|
private final Elements elementUtils;
|
||||||
|
private final Types typeUtils;
|
||||||
|
private final Messager messager;
|
||||||
|
private final Options options;
|
||||||
|
private final TypeElement mapperTypeElement;
|
||||||
|
private final List<SourceMethod> sourceModel;
|
||||||
|
private final List<MapperReference> mapperReferences;
|
||||||
|
private MappingResolver mappingResolver;
|
||||||
|
private final List<MappingMethod> mappingsToGenerate = new ArrayList<MappingMethod>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private methods which are not present in the original mapper interface and are added to map certain property
|
||||||
|
* types.
|
||||||
|
*/
|
||||||
|
private final Set<VirtualMappingMethod> usedVirtualMappings = new HashSet<VirtualMappingMethod>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public MappingContext( TypeFactory typeFactory,
|
||||||
|
Elements elementUtils,
|
||||||
|
Types typeUtils,
|
||||||
|
Messager messager,
|
||||||
|
Options options,
|
||||||
|
TypeElement mapper,
|
||||||
|
List<SourceMethod> sourceModel ) {
|
||||||
|
this.typeFactory = typeFactory;
|
||||||
|
this.elementUtils = elementUtils;
|
||||||
|
this.typeUtils = typeUtils;
|
||||||
|
this.messager = messager;
|
||||||
|
this.options = options;
|
||||||
|
this.mapperTypeElement = mapper;
|
||||||
|
this.sourceModel = sourceModel;
|
||||||
|
this.mapperReferences = initReferencedMappers( mapper );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeElement getMapperTypeElement() {
|
||||||
|
return mapperTypeElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SourceMethod> getSourceModel() {
|
||||||
|
return sourceModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MapperReference> getMapperReferences() {
|
||||||
|
return mapperReferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeFactory getTypeFactory() {
|
||||||
|
return typeFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Elements getElementUtils() {
|
||||||
|
return elementUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Types getTypeUtils() {
|
||||||
|
return typeUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Messager getMessager() {
|
||||||
|
return messager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Options getOptions() {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MappingResolver getMappingResolver() {
|
||||||
|
return mappingResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMappingResolver(MappingResolver mappingResolver) {
|
||||||
|
this.mappingResolver = mappingResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MappingMethod> getMappingsToGenerate() {
|
||||||
|
return mappingsToGenerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<VirtualMappingMethod> getUsedVirtualMappings() {
|
||||||
|
return usedVirtualMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
}
|
@ -16,17 +16,14 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model.assignment;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
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 org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.FactoryMethod;
|
|
||||||
import org.mapstruct.ap.model.MapperReference;
|
|
||||||
import org.mapstruct.ap.model.MappingMethod;
|
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
import org.mapstruct.ap.model.common.ConversionContext;
|
||||||
import org.mapstruct.ap.model.common.Parameter;
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
@ -18,10 +18,30 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
import javax.tools.Diagnostic;
|
||||||
|
import static org.mapstruct.ap.model.assignment.Assignment.AssignmentType.DIRECT;
|
||||||
|
import static org.mapstruct.ap.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED;
|
||||||
|
import static org.mapstruct.ap.model.assignment.Assignment.AssignmentType.TYPE_CONVERTED_MAPPED;
|
||||||
|
import org.mapstruct.ap.model.assignment.AdderWrapper;
|
||||||
|
import org.mapstruct.ap.model.assignment.GetterCollectionOrMapWrapper;
|
||||||
|
import org.mapstruct.ap.model.assignment.NewCollectionOrMapWrapper;
|
||||||
|
import org.mapstruct.ap.model.assignment.NullCheckWrapper;
|
||||||
|
import org.mapstruct.ap.model.assignment.SetterCollectionOrMapWrapper;
|
||||||
|
import org.mapstruct.ap.model.assignment.SetterWrapper;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.ModelElement;
|
import org.mapstruct.ap.model.common.ModelElement;
|
||||||
|
import org.mapstruct.ap.model.common.Parameter;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
import org.mapstruct.ap.model.source.ForgedMethod;
|
||||||
|
import org.mapstruct.ap.model.source.Mapping;
|
||||||
|
import org.mapstruct.ap.model.source.SourceMethod;
|
||||||
|
import org.mapstruct.ap.util.Executables;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,12 +61,414 @@ public class PropertyMapping extends ModelElement {
|
|||||||
|
|
||||||
private final Assignment assignment;
|
private final Assignment assignment;
|
||||||
|
|
||||||
|
public static class PropertyMappingBuilder {
|
||||||
|
|
||||||
|
private MappingContext ctx;
|
||||||
|
private SourceMethod method;
|
||||||
|
private ExecutableElement targetAccessor;
|
||||||
|
private String targetPropertyName;
|
||||||
|
private Parameter parameter;
|
||||||
|
|
||||||
|
public PropertyMappingBuilder mappingContext(MappingContext mappingContext) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMappingBuilder souceMethod( SourceMethod sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMappingBuilder targetAccessor( ExecutableElement targetAccessor ) {
|
||||||
|
this.targetAccessor = targetAccessor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMappingBuilder targetPropertyName( String targetPropertyName ) {
|
||||||
|
this.targetPropertyName = targetPropertyName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMappingBuilder parameter( Parameter parameter ) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum TargetAccessorType {
|
||||||
|
|
||||||
|
GETTER,
|
||||||
|
SETTER,
|
||||||
|
ADDER
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMapping build() {
|
||||||
|
|
||||||
|
// check if there's a mapping defined
|
||||||
|
Mapping mapping = method.getMappingByTargetPropertyName( targetPropertyName );
|
||||||
|
String dateFormat = null;
|
||||||
|
List<TypeMirror> qualifiers = null;
|
||||||
|
String sourcePropertyName;
|
||||||
|
if ( mapping != null ) {
|
||||||
|
dateFormat = mapping.getDateFormat();
|
||||||
|
qualifiers = mapping.getQualifiers();
|
||||||
|
sourcePropertyName = mapping.getSourcePropertyName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourcePropertyName = targetPropertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ExecutableElement> sourceGetters = parameter.getType().getGetters();
|
||||||
|
|
||||||
|
// then iterate over source accessors (assuming the source is a bean)
|
||||||
|
for ( ExecutableElement sourceAccessor : sourceGetters ) {
|
||||||
|
|
||||||
|
List<Mapping> sourceMappings = method.getMappings().get( sourcePropertyName );
|
||||||
|
if ( method.getMappings().containsKey( sourcePropertyName ) ) {
|
||||||
|
for ( Mapping sourceMapping : sourceMappings ) {
|
||||||
|
boolean mapsToOtherTarget = !sourceMapping.getTargetName().equals( targetPropertyName );
|
||||||
|
if ( Executables.getPropertyName( sourceAccessor ).equals( sourcePropertyName )
|
||||||
|
&& !mapsToOtherTarget ) {
|
||||||
|
return getPropertyMapping( sourceAccessor, dateFormat, qualifiers );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( Executables.getPropertyName( sourceAccessor ).equals( sourcePropertyName ) ) {
|
||||||
|
return getPropertyMapping( sourceAccessor, dateFormat, qualifiers );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertyMapping getPropertyMapping( ExecutableElement sourceAccessor,
|
||||||
|
String dateFormat,
|
||||||
|
List<TypeMirror> qualifiers ) {
|
||||||
|
|
||||||
|
Type sourceType;
|
||||||
|
Type targetType;
|
||||||
|
TargetAccessorType targetAccessorType;
|
||||||
|
String sourceReference = parameter.getName() + "." + sourceAccessor.getSimpleName().toString() + "()";
|
||||||
|
String iteratorReference = null;
|
||||||
|
boolean sourceIsCollection = false;
|
||||||
|
if ( Executables.isSetterMethod( targetAccessor ) ) {
|
||||||
|
sourceType = ctx.getTypeFactory().getReturnType( sourceAccessor );
|
||||||
|
targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType();
|
||||||
|
targetAccessorType = TargetAccessorType.SETTER;
|
||||||
|
}
|
||||||
|
else if ( Executables.isAdderMethod( targetAccessor ) ) {
|
||||||
|
sourceType = ctx.getTypeFactory().getReturnType( sourceAccessor );
|
||||||
|
if ( sourceType.isCollectionType() ) {
|
||||||
|
sourceIsCollection = true;
|
||||||
|
sourceType = sourceType.getTypeParameters().get( 0 );
|
||||||
|
iteratorReference = Executables.getElementNameForAdder( targetAccessor );
|
||||||
|
}
|
||||||
|
targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType();
|
||||||
|
targetAccessorType = TargetAccessorType.ADDER;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourceType = ctx.getTypeFactory().getReturnType( sourceAccessor );
|
||||||
|
targetType = ctx.getTypeFactory().getReturnType( targetAccessor );
|
||||||
|
targetAccessorType = TargetAccessorType.GETTER;
|
||||||
|
}
|
||||||
|
String sourcePropertyName = Executables.getPropertyName( sourceAccessor );
|
||||||
|
String mappedElement = "property '" + sourcePropertyName + "'";
|
||||||
|
|
||||||
|
Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method,
|
||||||
|
mappedElement,
|
||||||
|
sourceType,
|
||||||
|
targetType,
|
||||||
|
targetPropertyName,
|
||||||
|
dateFormat,
|
||||||
|
qualifiers,
|
||||||
|
iteratorReference != null ? iteratorReference : sourceReference
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( assignment == null ) {
|
||||||
|
assignment = forgeMapping( sourceType, targetType, sourceReference, method.getExecutable() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( assignment != null ) {
|
||||||
|
|
||||||
|
if ( targetType.isCollectionOrMapType() ) {
|
||||||
|
|
||||||
|
// wrap the setter in the collection / map initializers
|
||||||
|
if ( targetAccessorType == TargetAccessorType.SETTER ) {
|
||||||
|
|
||||||
|
// wrap the assignment in a new Map or Collection implementation if this is not done in a
|
||||||
|
// mapping method. Note, typeconversons do not apply to collections or maps
|
||||||
|
Assignment newCollectionOrMap = null;
|
||||||
|
if ( assignment.getType() == DIRECT ) {
|
||||||
|
newCollectionOrMap =
|
||||||
|
new NewCollectionOrMapWrapper( assignment, targetType.getImportTypes() );
|
||||||
|
newCollectionOrMap = new SetterWrapper( newCollectionOrMap, method.getThrownTypes() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap the assignment in the setter method
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
|
||||||
|
// target accessor is setter, so wrap the setter in setter map/ collection handling
|
||||||
|
assignment = new SetterCollectionOrMapWrapper(
|
||||||
|
assignment,
|
||||||
|
targetAccessor.getSimpleName().toString(),
|
||||||
|
newCollectionOrMap
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// wrap the assignment in the setter method
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
|
||||||
|
// target accessor is getter, so wrap the setter in getter map/ collection handling
|
||||||
|
assignment = new GetterCollectionOrMapWrapper( assignment );
|
||||||
|
}
|
||||||
|
|
||||||
|
// For collections and maps include a null check, when the assignment type is DIRECT.
|
||||||
|
// for mapping methods (builtin / custom), the mapping method is responsible for the
|
||||||
|
// null check. Typeconversions do not apply to collections and maps.
|
||||||
|
if ( assignment.getType() == DIRECT ) {
|
||||||
|
assignment = new NullCheckWrapper( assignment );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( targetAccessorType == TargetAccessorType.SETTER ) {
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
if ( !sourceType.isPrimitive()
|
||||||
|
&& ( assignment.getType() == TYPE_CONVERTED
|
||||||
|
|| assignment.getType() == TYPE_CONVERTED_MAPPED
|
||||||
|
|| assignment.getType() == DIRECT && targetType.isPrimitive() ) ) {
|
||||||
|
// for primitive types null check is not possible at all, but a conversion needs
|
||||||
|
// a null check.
|
||||||
|
assignment = new NullCheckWrapper( assignment );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TargetAccessorType must be ADDER
|
||||||
|
if ( sourceIsCollection ) {
|
||||||
|
assignment = new AdderWrapper(
|
||||||
|
assignment,
|
||||||
|
method.getThrownTypes(),
|
||||||
|
sourceReference,
|
||||||
|
sourceType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Possibly adding null to a target collection. So should be surrounded by an null check.
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
assignment = new NullCheckWrapper( assignment );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Can't map property \"%s %s\" to \"%s %s\".",
|
||||||
|
sourceType,
|
||||||
|
sourcePropertyName,
|
||||||
|
targetType,
|
||||||
|
targetPropertyName
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new PropertyMapping(
|
||||||
|
parameter.getName(),
|
||||||
|
targetAccessor.getSimpleName().toString(),
|
||||||
|
targetType,
|
||||||
|
assignment
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Assignment forgeMapping( Type sourceType, Type targetType, String sourceReference, Element element ) {
|
||||||
|
|
||||||
|
Assignment assignment = null;
|
||||||
|
if ( sourceType.isCollectionType() && targetType.isCollectionType() ) {
|
||||||
|
|
||||||
|
ForgedMethod methodToGenerate = new ForgedMethod( sourceType, targetType, element );
|
||||||
|
IterableMappingMethod.Builder builder = new IterableMappingMethod.Builder( );
|
||||||
|
|
||||||
|
|
||||||
|
IterableMappingMethod iterableMappingMethod = builder
|
||||||
|
.mappingContext( ctx )
|
||||||
|
.method( methodToGenerate )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if ( !ctx.getMappingsToGenerate().contains( iterableMappingMethod ) ) {
|
||||||
|
ctx.getMappingsToGenerate().add( iterableMappingMethod );
|
||||||
|
}
|
||||||
|
assignment = AssignmentFactory.createMethodReference( methodToGenerate, null, targetType );
|
||||||
|
assignment.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( sourceType.isMapType() && targetType.isMapType() ) {
|
||||||
|
|
||||||
|
ForgedMethod methodToGenerate = new ForgedMethod( sourceType, targetType, element );
|
||||||
|
|
||||||
|
MapMappingMethod.Builder builder = new MapMappingMethod.Builder( );
|
||||||
|
MapMappingMethod mapMappingMethod = builder
|
||||||
|
.mappingContext( ctx )
|
||||||
|
.method( methodToGenerate )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if ( !ctx.getMappingsToGenerate().contains( mapMappingMethod ) ) {
|
||||||
|
ctx.getMappingsToGenerate().add( mapMappingMethod );
|
||||||
|
}
|
||||||
|
assignment = AssignmentFactory.createMethodReference( methodToGenerate, null, targetType );
|
||||||
|
assignment.setAssignment( AssignmentFactory.createSimple( sourceReference ) );
|
||||||
|
}
|
||||||
|
return assignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConstantMappingBuilder {
|
||||||
|
|
||||||
|
private MappingContext ctx;
|
||||||
|
private SourceMethod method;
|
||||||
|
private String constantExpression;
|
||||||
|
private ExecutableElement targetAccessor;
|
||||||
|
private String dateFormat;
|
||||||
|
private List<TypeMirror> qualifiers;
|
||||||
|
|
||||||
|
public ConstantMappingBuilder mappingContext(MappingContext mappingContext) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMappingBuilder sourceMethod( SourceMethod sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMappingBuilder constantExpression( String constantExpression ) {
|
||||||
|
this.constantExpression = constantExpression;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMappingBuilder targetAccessor( ExecutableElement targetAccessor ) {
|
||||||
|
this.targetAccessor = targetAccessor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMappingBuilder dateFormat( String dateFormat ) {
|
||||||
|
this.dateFormat = dateFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstantMappingBuilder qualifiers( List<TypeMirror> qualifiers ) {
|
||||||
|
this.qualifiers = qualifiers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMapping build() {
|
||||||
|
|
||||||
|
// source
|
||||||
|
String mappedElement = "constant '" + constantExpression + "'";
|
||||||
|
Type sourceType = ctx.getTypeFactory().getType( String.class );
|
||||||
|
|
||||||
|
// target
|
||||||
|
Type targetType;
|
||||||
|
if ( Executables.isSetterMethod( targetAccessor ) ) {
|
||||||
|
targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
targetType = ctx.getTypeFactory().getReturnType( targetAccessor );
|
||||||
|
}
|
||||||
|
|
||||||
|
String targetPropertyName = Executables.getPropertyName( targetAccessor );
|
||||||
|
|
||||||
|
Assignment assignment = ctx.getMappingResolver().getTargetAssignment( method,
|
||||||
|
mappedElement,
|
||||||
|
sourceType,
|
||||||
|
targetType,
|
||||||
|
targetPropertyName,
|
||||||
|
dateFormat,
|
||||||
|
qualifiers,
|
||||||
|
constantExpression
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( assignment != null ) {
|
||||||
|
|
||||||
|
// target accessor is setter, so decorate assignment as setter
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
|
||||||
|
// wrap when dealing with getter only on target
|
||||||
|
if ( Executables.isGetterMethod( targetAccessor ) ) {
|
||||||
|
assignment = new GetterCollectionOrMapWrapper( assignment );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.getMessager().printMessage(
|
||||||
|
Diagnostic.Kind.ERROR,
|
||||||
|
String.format(
|
||||||
|
"Can't map \"%s %s\" to \"%s %s\".",
|
||||||
|
sourceType,
|
||||||
|
constantExpression,
|
||||||
|
targetType,
|
||||||
|
targetPropertyName
|
||||||
|
),
|
||||||
|
method.getExecutable()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PropertyMapping( targetAccessor.getSimpleName().toString(), targetType, assignment );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class JavaExpressionMappingBuilder {
|
||||||
|
|
||||||
|
private MappingContext ctx;
|
||||||
|
private SourceMethod method;
|
||||||
|
private String javaExpression;
|
||||||
|
private ExecutableElement targetAccessor;
|
||||||
|
|
||||||
|
public JavaExpressionMappingBuilder mappingContext(MappingContext mappingContext) {
|
||||||
|
this.ctx = mappingContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaExpressionMappingBuilder souceMethod( SourceMethod sourceMethod ) {
|
||||||
|
this.method = sourceMethod;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaExpressionMappingBuilder javaExpression( String javaExpression ) {
|
||||||
|
this.javaExpression = javaExpression;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaExpressionMappingBuilder targetAccessor( ExecutableElement targetAccessor ) {
|
||||||
|
this.targetAccessor = targetAccessor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMapping build() {
|
||||||
|
|
||||||
|
Assignment assignment = AssignmentFactory.createSimple( javaExpression );
|
||||||
|
assignment = new SetterWrapper( assignment, method.getThrownTypes() );
|
||||||
|
|
||||||
|
Type targetType;
|
||||||
|
if ( Executables.isSetterMethod( targetAccessor ) ) {
|
||||||
|
targetType = ctx.getTypeFactory().getSingleParameter( targetAccessor ).getType();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
targetType = ctx.getTypeFactory().getReturnType( targetAccessor );
|
||||||
|
|
||||||
|
// target accessor is getter, so wrap the setter in getter map/ collection handling
|
||||||
|
assignment = new GetterCollectionOrMapWrapper( assignment );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PropertyMapping( targetAccessor.getSimpleName().toString(), targetType, assignment );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Constructor for creating mappings of constant expressions.
|
// Constructor for creating mappings of constant expressions.
|
||||||
public PropertyMapping(String targetAccessorName, Type targetType, Assignment propertyAssignment) {
|
private PropertyMapping(String targetAccessorName, Type targetType, Assignment propertyAssignment) {
|
||||||
this( null, targetAccessorName, targetType, propertyAssignment );
|
this( null, targetAccessorName, targetType, propertyAssignment );
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyMapping(String sourceBeanName, String targetAccessorName, Type targetType, Assignment assignment) {
|
private PropertyMapping(String sourceBeanName, String targetAccessorName, Type targetType, Assignment assignment) {
|
||||||
|
|
||||||
this.sourceBeanName = sourceBeanName;
|
this.sourceBeanName = sourceBeanName;
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model.assignment;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
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 org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.ModelElement;
|
import org.mapstruct.ap.model.common.ModelElement;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
@ -23,7 +23,6 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model.assignment;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
@ -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.assignment;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.FactoryMethod;
|
|
||||||
import org.mapstruct.ap.model.MapperReference;
|
|
||||||
import org.mapstruct.ap.model.common.ConversionContext;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
|
||||||
import org.mapstruct.ap.model.source.Method;
|
|
||||||
import org.mapstruct.ap.model.source.SourceMethod;
|
|
||||||
import org.mapstruct.ap.model.source.builtin.BuiltInMethod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory class for creating all types of assignments
|
|
||||||
*
|
|
||||||
* @author Sjaak Derksen
|
|
||||||
*/
|
|
||||||
public class AssignmentFactory {
|
|
||||||
|
|
||||||
private AssignmentFactory() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Assignment createTypeConversion(Set<Type> importTypes, List<Type> exceptionTypes, String expression) {
|
|
||||||
return new TypeConversion( importTypes, exceptionTypes, expression );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FactoryMethod createFactory(SourceMethod method, MapperReference declaringMapper) {
|
|
||||||
return new MethodReference( method, declaringMapper, null );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Assignment createMethodReference(Method method, MapperReference declaringMapper,
|
|
||||||
Type targetType) {
|
|
||||||
return new MethodReference( method, declaringMapper, targetType );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Assignment createMethodReference(BuiltInMethod method, ConversionContext contextParam) {
|
|
||||||
return new MethodReference( method, contextParam );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Direct createSimple(String sourceRef) {
|
|
||||||
return new Direct( sourceRef );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.model.assignment;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.ModelElement;
|
import org.mapstruct.ap.model.common.ModelElement;
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model.assignment;
|
package org.mapstruct.ap.model.assignment;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This wrapper handles the situation were an assignment must be done via a target getter method because there
|
* This wrapper handles the situation were an assignment must be done via a target getter method because there
|
||||||
* is no setter available.
|
* is no setter available.
|
||||||
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.model.assignment;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +21,6 @@ package org.mapstruct.ap.model.assignment;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model.assignment;
|
package org.mapstruct.ap.model.assignment;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps the assignment in a null check.
|
* Wraps the assignment in a null check.
|
||||||
*
|
*
|
||||||
|
@ -21,7 +21,6 @@ package org.mapstruct.ap.model.assignment;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.model.assignment;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.mapstruct.ap.model.Assignment;
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,28 +18,26 @@
|
|||||||
*/
|
*/
|
||||||
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;
|
import org.mapstruct.ap.model.assignment.Assignment;
|
||||||
import org.mapstruct.ap.model.MapperReference;
|
import org.mapstruct.ap.model.MapperReference;
|
||||||
|
import org.mapstruct.ap.model.MappingContext;
|
||||||
import org.mapstruct.ap.model.VirtualMappingMethod;
|
import org.mapstruct.ap.model.VirtualMappingMethod;
|
||||||
import org.mapstruct.ap.model.assignment.AssignmentFactory;
|
import org.mapstruct.ap.model.AssignmentFactory;
|
||||||
import org.mapstruct.ap.model.assignment.Direct;
|
import org.mapstruct.ap.model.Direct;
|
||||||
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;
|
||||||
@ -67,30 +65,29 @@ import org.mapstruct.ap.util.Strings;
|
|||||||
*
|
*
|
||||||
* @author Sjaak Derksen
|
* @author Sjaak Derksen
|
||||||
*/
|
*/
|
||||||
public class MappingResolver {
|
public class MappingResolverImpl implements MappingResolver {
|
||||||
|
|
||||||
private final Messager messager;
|
|
||||||
private final TypeFactory typeFactory;
|
|
||||||
private final Conversions conversions;
|
private final Conversions conversions;
|
||||||
private final BuiltInMappingMethods builtInMethods;
|
private final BuiltInMappingMethods builtInMethods;
|
||||||
private final Types typeUtils;
|
|
||||||
|
|
||||||
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
|
||||||
*/
|
*/
|
||||||
private final Set<VirtualMappingMethod> virtualMethods;
|
public MappingResolverImpl( MappingContext mappingContext ) {
|
||||||
|
this.conversions = new Conversions( mappingContext.getElementUtils(), mappingContext.getTypeFactory() );
|
||||||
|
this.builtInMethods = new BuiltInMappingMethods( mappingContext.getTypeFactory() );
|
||||||
public MappingResolver(Messager messager, TypeFactory typeFactory, Elements elementUtils, Types typeUtils) {
|
this.methodSelectors = new MethodSelectors(
|
||||||
this.messager = messager;
|
mappingContext.getTypeUtils(),
|
||||||
this.typeFactory = typeFactory;
|
mappingContext.getElementUtils(),
|
||||||
this.conversions = new Conversions( elementUtils, typeFactory );
|
mappingContext.getTypeFactory()
|
||||||
this.builtInMethods = new BuiltInMappingMethods( typeFactory );
|
);
|
||||||
this.virtualMethods = new HashSet<VirtualMappingMethod>();
|
this.mappingContext = mappingContext;
|
||||||
this.methodSelectors = new MethodSelectors( typeUtils, elementUtils, typeFactory );
|
|
||||||
this.typeUtils = typeUtils;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,8 +96,6 @@ public class MappingResolver {
|
|||||||
*
|
*
|
||||||
* @param mappingMethod target mapping method
|
* @param mappingMethod target mapping method
|
||||||
* @param mappedElement used for error messages
|
* @param mappedElement used for error messages
|
||||||
* @param mapperReferences list of references to mapper
|
|
||||||
* @param methods list of candidate methods
|
|
||||||
* @param sourceType parameter to match
|
* @param sourceType parameter to match
|
||||||
* @param targetType return type to match
|
* @param targetType return type to match
|
||||||
* @param targetPropertyName name of the target property
|
* @param targetPropertyName name of the target property
|
||||||
@ -116,10 +111,10 @@ public class MappingResolver {
|
|||||||
* <li>null, no assignment found</li>
|
* <li>null, no assignment found</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
*/
|
*/
|
||||||
public Assignment getTargetAssignment( Method mappingMethod,
|
@Override
|
||||||
|
public Assignment getTargetAssignment(
|
||||||
|
Method mappingMethod,
|
||||||
String mappedElement,
|
String mappedElement,
|
||||||
List<MapperReference> mapperReferences,
|
|
||||||
List<SourceMethod> methods,
|
|
||||||
Type sourceType,
|
Type sourceType,
|
||||||
Type targetType,
|
Type targetType,
|
||||||
String targetPropertyName,
|
String targetPropertyName,
|
||||||
@ -129,22 +124,19 @@ public class MappingResolver {
|
|||||||
|
|
||||||
ResolvingAttempt attempt = new ResolvingAttempt( mappingMethod,
|
ResolvingAttempt attempt = new ResolvingAttempt( mappingMethod,
|
||||||
mappedElement,
|
mappedElement,
|
||||||
mapperReferences,
|
|
||||||
methods,
|
|
||||||
targetPropertyName,
|
targetPropertyName,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
qualifiers,
|
qualifiers,
|
||||||
sourceReference,
|
sourceReference,
|
||||||
this
|
conversions,
|
||||||
|
builtInMethods,
|
||||||
|
methodSelectors,
|
||||||
|
mappingContext
|
||||||
);
|
);
|
||||||
|
|
||||||
return attempt.getTargetAssignment( sourceType, targetType );
|
return attempt.getTargetAssignment( sourceType, targetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<VirtualMappingMethod> getVirtualMethodsToGenerate() {
|
|
||||||
return virtualMethods;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class ResolvingAttempt {
|
private static class ResolvingAttempt {
|
||||||
|
|
||||||
@ -156,7 +148,10 @@ public class MappingResolver {
|
|||||||
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 MappingResolver context;
|
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
|
||||||
@ -165,22 +160,26 @@ public class MappingResolver {
|
|||||||
|
|
||||||
private ResolvingAttempt( Method mappingMethod,
|
private ResolvingAttempt( Method mappingMethod,
|
||||||
String mappedElement,
|
String mappedElement,
|
||||||
List<MapperReference> mapperReferences,
|
|
||||||
List<SourceMethod> methods,
|
|
||||||
String targetPropertyName,
|
String targetPropertyName,
|
||||||
String dateFormat,
|
String dateFormat,
|
||||||
List<TypeMirror> qualifiers,
|
List<TypeMirror> qualifiers,
|
||||||
String sourceReference,
|
String sourceReference,
|
||||||
MappingResolver context ) {
|
Conversions conversions,
|
||||||
|
BuiltInMappingMethods builtInMethods,
|
||||||
|
MethodSelectors methodSelectors,
|
||||||
|
MappingContext mappingContext ) {
|
||||||
this.mappingMethod = mappingMethod;
|
this.mappingMethod = mappingMethod;
|
||||||
this.mappedElement = mappedElement;
|
this.mappedElement = mappedElement;
|
||||||
this.mapperReferences = mapperReferences;
|
this.mapperReferences = mappingContext.getMapperReferences();
|
||||||
this.methods = methods;
|
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.context = context;
|
this.conversions = conversions;
|
||||||
|
this.builtInMethods = builtInMethods;
|
||||||
|
this.methodSelectors = methodSelectors;
|
||||||
|
this.mappingContext = mappingContext;
|
||||||
this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>();
|
this.virtualMethodCandidates = new HashSet<VirtualMappingMethod>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,12 +189,12 @@ public class MappingResolver {
|
|||||||
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 ) );
|
||||||
context.virtualMethods.addAll( virtualMethodCandidates );
|
mappingContext.getUsedVirtualMappings().addAll( virtualMethodCandidates );
|
||||||
return referencedMethod;
|
return referencedMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
// then direct assignable
|
// then direct assignable
|
||||||
if ( sourceType.isAssignableTo( targetType ) || context.isPropertyMappable( sourceType, targetType ) ) {
|
if ( sourceType.isAssignableTo( targetType ) || isPropertyMappable( sourceType, targetType ) ) {
|
||||||
Assignment simpleAssignment = AssignmentFactory.createSimple( sourceReference );
|
Assignment simpleAssignment = AssignmentFactory.createSimple( sourceReference );
|
||||||
return simpleAssignment;
|
return simpleAssignment;
|
||||||
}
|
}
|
||||||
@ -210,21 +209,21 @@ public class 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 ) {
|
||||||
context.virtualMethods.addAll( virtualMethodCandidates );
|
mappingContext.getUsedVirtualMappings().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 ) {
|
||||||
context.virtualMethods.addAll( virtualMethodCandidates );
|
mappingContext.getUsedVirtualMappings().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 ) {
|
||||||
context.virtualMethods.addAll( virtualMethodCandidates );
|
mappingContext.getUsedVirtualMappings().addAll( virtualMethodCandidates );
|
||||||
return conversion;
|
return conversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,13 +232,14 @@ public class MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Assignment resolveViaConversion( Type sourceType, Type targetType ) {
|
private Assignment resolveViaConversion( Type sourceType, Type targetType ) {
|
||||||
ConversionProvider conversionProvider = context.conversions.getConversion( sourceType, targetType );
|
ConversionProvider conversionProvider = conversions.getConversion( sourceType, targetType );
|
||||||
|
|
||||||
if ( conversionProvider == null ) {
|
if ( conversionProvider == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConversionContext ctx = new DefaultConversionContext( context.typeFactory, targetType, dateFormat );
|
ConversionContext ctx =
|
||||||
|
new DefaultConversionContext( mappingContext.getTypeFactory(), targetType, dateFormat );
|
||||||
return conversionProvider.to( ctx );
|
return conversionProvider.to( ctx );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,11 +259,12 @@ public class MappingResolver {
|
|||||||
|
|
||||||
// then a matching built-in method
|
// then a matching built-in method
|
||||||
BuiltInMethod matchingBuiltInMethod =
|
BuiltInMethod matchingBuiltInMethod =
|
||||||
getBestMatch( context.builtInMethods.getBuiltInMethods(), sourceType, targetType );
|
getBestMatch( builtInMethods.getBuiltInMethods(), sourceType, targetType );
|
||||||
|
|
||||||
if ( matchingBuiltInMethod != null ) {
|
if ( matchingBuiltInMethod != null ) {
|
||||||
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
|
virtualMethodCandidates.add( new VirtualMappingMethod( matchingBuiltInMethod ) );
|
||||||
ConversionContext ctx = new DefaultConversionContext( context.typeFactory, targetType, dateFormat );
|
ConversionContext ctx =
|
||||||
|
new DefaultConversionContext( mappingContext.getTypeFactory(), 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;
|
||||||
@ -285,7 +286,7 @@ public class MappingResolver {
|
|||||||
private Assignment resolveViaMethodAndMethod( Type sourceType, Type targetType ) {
|
private Assignment resolveViaMethodAndMethod( Type sourceType, Type targetType ) {
|
||||||
|
|
||||||
List<Method> methodYCandidates = new ArrayList<Method>( methods );
|
List<Method> methodYCandidates = new ArrayList<Method>( methods );
|
||||||
methodYCandidates.addAll( context.builtInMethods.getBuiltInMethods() );
|
methodYCandidates.addAll( builtInMethods.getBuiltInMethods() );
|
||||||
|
|
||||||
Assignment methodRefY = null;
|
Assignment methodRefY = null;
|
||||||
|
|
||||||
@ -331,7 +332,7 @@ public class MappingResolver {
|
|||||||
private Assignment resolveViaConversionAndMethod( Type sourceType, Type targetType ) {
|
private Assignment resolveViaConversionAndMethod( Type sourceType, Type targetType ) {
|
||||||
|
|
||||||
List<Method> methodYCandidates = new ArrayList<Method>( methods );
|
List<Method> methodYCandidates = new ArrayList<Method>( methods );
|
||||||
methodYCandidates.addAll( context.builtInMethods.getBuiltInMethods() );
|
methodYCandidates.addAll( builtInMethods.getBuiltInMethods() );
|
||||||
|
|
||||||
Assignment methodRefY = null;
|
Assignment methodRefY = null;
|
||||||
|
|
||||||
@ -373,7 +374,7 @@ public class MappingResolver {
|
|||||||
private Assignment resolveViaMethodAndConversion( Type sourceType, Type targetType ) {
|
private Assignment resolveViaMethodAndConversion( Type sourceType, Type targetType ) {
|
||||||
|
|
||||||
List<Method> methodXCandidates = new ArrayList<Method>( methods );
|
List<Method> methodXCandidates = new ArrayList<Method>( methods );
|
||||||
methodXCandidates.addAll( context.builtInMethods.getBuiltInMethods() );
|
methodXCandidates.addAll( builtInMethods.getBuiltInMethods() );
|
||||||
|
|
||||||
Assignment conversionYRef = null;
|
Assignment conversionYRef = null;
|
||||||
|
|
||||||
@ -404,7 +405,7 @@ public class MappingResolver {
|
|||||||
|
|
||||||
private <T extends Method> T getBestMatch( List<T> methods, Type sourceType, Type returnType ) {
|
private <T extends Method> T getBestMatch( List<T> methods, Type sourceType, Type returnType ) {
|
||||||
|
|
||||||
List<T> candidates = context.methodSelectors.getMatchingMethods(
|
List<T> candidates = methodSelectors.getMatchingMethods(
|
||||||
mappingMethod,
|
mappingMethod,
|
||||||
methods,
|
methods,
|
||||||
sourceType,
|
sourceType,
|
||||||
@ -423,7 +424,7 @@ public class MappingResolver {
|
|||||||
returnType,
|
returnType,
|
||||||
Strings.join( candidates, ", " ) );
|
Strings.join( candidates, ", " ) );
|
||||||
|
|
||||||
mappingMethod.printMessage( context.messager, Kind.ERROR, errorMsg );
|
mappingMethod.printMessage( mappingContext.getMessager(), Kind.ERROR, errorMsg );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !candidates.isEmpty() ) {
|
if ( !candidates.isEmpty() ) {
|
||||||
@ -453,7 +454,6 @@ public class MappingResolver {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the specified property can be mapped from source to target or not. A mapping if possible if one of
|
* Whether the specified property can be mapped from source to target or not. A mapping if possible if one of
|
||||||
@ -470,32 +470,33 @@ public class MappingResolver {
|
|||||||
*
|
*
|
||||||
* @return {@code true} if the specified property can be mapped, {@code false} otherwise.
|
* @return {@code true} if the specified property can be mapped, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean isPropertyMappable(Type sourceType, Type targetType) {
|
private boolean isPropertyMappable( Type sourceType, Type targetType ) {
|
||||||
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
|
boolean collectionOrMapTargetTypeHasCompatibleConstructor = false;
|
||||||
|
|
||||||
if ( sourceType.isCollectionType() && targetType.isCollectionType() ) {
|
if ( sourceType.isCollectionType() && targetType.isCollectionType() ) {
|
||||||
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
|
collectionOrMapTargetTypeHasCompatibleConstructor = collectionTypeHasCompatibleConstructor(
|
||||||
sourceType,
|
sourceType,
|
||||||
targetType.getImplementationType() != null ?
|
targetType.getImplementationType() != null
|
||||||
targetType.getImplementationType() : targetType
|
? targetType.getImplementationType() : targetType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sourceType.isMapType() && targetType.isMapType() ) {
|
if ( sourceType.isMapType() && targetType.isMapType() ) {
|
||||||
collectionOrMapTargetTypeHasCompatibleConstructor = mapTypeHasCompatibleConstructor(
|
collectionOrMapTargetTypeHasCompatibleConstructor = mapTypeHasCompatibleConstructor(
|
||||||
sourceType,
|
sourceType,
|
||||||
targetType.getImplementationType() != null ?
|
targetType.getImplementationType() != null
|
||||||
targetType.getImplementationType() : targetType
|
? targetType.getImplementationType() : targetType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( ( targetType.isCollectionType() || targetType.isMapType() ) &&
|
if ( ( ( targetType.isCollectionType() || targetType.isMapType() )
|
||||||
collectionOrMapTargetTypeHasCompatibleConstructor ) ) {
|
&& collectionOrMapTargetTypeHasCompatibleConstructor ) ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given target type has a single-argument constructor which accepts the given source type.
|
* Whether the given target type has a single-argument constructor which accepts the given source type.
|
||||||
*
|
*
|
||||||
@ -505,21 +506,21 @@ public class MappingResolver {
|
|||||||
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean collectionTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
|
private boolean collectionTypeHasCompatibleConstructor( Type sourceType, Type targetType ) {
|
||||||
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
||||||
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
|
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead
|
||||||
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
|
// we just check whether the target type is parameterized in a way that it implicitly should have a
|
||||||
// which accepts the source type
|
// constructor which accepts the source type
|
||||||
|
|
||||||
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty() ?
|
TypeMirror sourceElementType = sourceType.getTypeParameters().isEmpty()
|
||||||
typeFactory.getType( Object.class ).getTypeMirror() :
|
? mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror()
|
||||||
sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
: sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
|
|
||||||
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty() ?
|
TypeMirror targetElementType = targetType.getTypeParameters().isEmpty()
|
||||||
typeFactory.getType( Object.class ).getTypeMirror() :
|
? mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror()
|
||||||
targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
: targetType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
|
|
||||||
return typeUtils.isAssignable( sourceElementType, targetElementType );
|
return mappingContext.getTypeUtils().isAssignable( sourceElementType, targetElementType );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -531,20 +532,20 @@ public class MappingResolver {
|
|||||||
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
* @return {@code true} if the target type has a constructor accepting the given source type, {@code false}
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean mapTypeHasCompatibleConstructor(Type sourceType, Type targetType) {
|
private boolean mapTypeHasCompatibleConstructor( Type sourceType, Type targetType ) {
|
||||||
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
// note (issue #127): actually this should check for the presence of a matching constructor, with help of
|
||||||
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead we
|
// Types#asMemberOf(); but this method seems to not work correctly in the Eclipse implementation, so instead
|
||||||
// just check whether the target type is parameterized in a way that it implicitly should have a constructor
|
// we just check whether the target type is parameterized in a way that it implicitly should have a
|
||||||
// which accepts the source type
|
// constructor which accepts the source type
|
||||||
|
|
||||||
TypeMirror sourceKeyType = null;
|
TypeMirror sourceKeyType;
|
||||||
TypeMirror targetKeyType = null;
|
TypeMirror targetKeyType;
|
||||||
TypeMirror sourceValueType = null;
|
TypeMirror sourceValueType;
|
||||||
TypeMirror targetValueType = null;
|
TypeMirror targetValueType;
|
||||||
|
|
||||||
if ( sourceType.getTypeParameters().isEmpty() ) {
|
if ( sourceType.getTypeParameters().isEmpty() ) {
|
||||||
sourceKeyType = typeFactory.getType( Object.class ).getTypeMirror();
|
sourceKeyType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
||||||
sourceValueType = typeFactory.getType( Object.class ).getTypeMirror();
|
sourceValueType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
sourceKeyType = sourceType.getTypeParameters().get( 0 ).getTypeMirror();
|
||||||
@ -552,15 +553,16 @@ public class MappingResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( targetType.getTypeParameters().isEmpty() ) {
|
if ( targetType.getTypeParameters().isEmpty() ) {
|
||||||
targetKeyType = typeFactory.getType( Object.class ).getTypeMirror();
|
targetKeyType = mappingContext.getTypeFactory().getType( Object.class ).getTypeMirror();
|
||||||
targetValueType = typeFactory.getType( Object.class ).getTypeMirror();
|
targetValueType = mappingContext.getTypeFactory().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 typeUtils.isAssignable( sourceKeyType, targetKeyType ) &&
|
return mappingContext.getTypeUtils().isAssignable( sourceKeyType, targetKeyType )
|
||||||
typeUtils.isAssignable( sourceValueType, targetValueType );
|
&& mappingContext.getTypeUtils().isAssignable( sourceValueType, targetValueType );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user