mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#19 Map into existing instances.
- Either defined explicitly with @MappingTarget, or implicitly as last parameter in a void method.
This commit is contained in:
parent
ba90702392
commit
466a640ced
36
core/src/main/java/org/mapstruct/MappingTarget.java
Normal file
36
core/src/main/java/org/mapstruct/MappingTarget.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2013 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;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares a parameter of a mapping method to be the target of the mapping.
|
||||||
|
* <p>
|
||||||
|
* Not more than one parameter can be declared as {@code MappingTarget}.
|
||||||
|
* <p>
|
||||||
|
* For methods with return type {@code void}, the last parameter of the method is regarded as {@code MappingTarget},
|
||||||
|
* unless another parameter carries this annotation.
|
||||||
|
*
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*/
|
||||||
|
@Target( ElementType.PARAMETER )
|
||||||
|
public @interface MappingTarget {
|
||||||
|
}
|
@ -43,6 +43,7 @@ import org.mapstruct.IterableMapping;
|
|||||||
import org.mapstruct.MapMapping;
|
import org.mapstruct.MapMapping;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
import org.mapstruct.Mappings;
|
import org.mapstruct.Mappings;
|
||||||
import org.mapstruct.ap.model.Options;
|
import org.mapstruct.ap.model.Options;
|
||||||
import org.mapstruct.ap.model.ReportingPolicy;
|
import org.mapstruct.ap.model.ReportingPolicy;
|
||||||
@ -76,7 +77,8 @@ import org.mapstruct.ap.processor.ModelElementProcessor.ProcessorContext;
|
|||||||
@GeneratePrism(value = Mapping.class, publicAccess = true),
|
@GeneratePrism(value = Mapping.class, publicAccess = true),
|
||||||
@GeneratePrism(value = Mappings.class, publicAccess = true),
|
@GeneratePrism(value = Mappings.class, publicAccess = true),
|
||||||
@GeneratePrism(value = IterableMapping.class, publicAccess = true),
|
@GeneratePrism(value = IterableMapping.class, publicAccess = true),
|
||||||
@GeneratePrism(value = MapMapping.class, publicAccess = true)
|
@GeneratePrism(value = MapMapping.class, publicAccess = true),
|
||||||
|
@GeneratePrism(value = MappingTarget.class, publicAccess = true)
|
||||||
})
|
})
|
||||||
@SupportedOptions({
|
@SupportedOptions({
|
||||||
MappingProcessor.SUPPRESS_GENERATOR_TIMESTAMP,
|
MappingProcessor.SUPPRESS_GENERATOR_TIMESTAMP,
|
||||||
|
@ -21,6 +21,8 @@ package org.mapstruct.ap.model;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one
|
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one
|
||||||
* bean type to another, optionally configured by one or more
|
* bean type to another, optionally configured by one or more
|
||||||
@ -32,9 +34,10 @@ public class BeanMappingMethod extends MappingMethod {
|
|||||||
|
|
||||||
private final List<PropertyMapping> propertyMappings;
|
private final List<PropertyMapping> propertyMappings;
|
||||||
|
|
||||||
public BeanMappingMethod(String name, String parameterName, Type sourceType, Type targetType,
|
public BeanMappingMethod(String name, List<Parameter> parameters, List<Parameter> sourceParameters,
|
||||||
|
Type resultType, String resultName, Type returnType,
|
||||||
List<PropertyMapping> propertyMappings) {
|
List<PropertyMapping> propertyMappings) {
|
||||||
super( name, parameterName, sourceType, targetType );
|
super( name, parameters, sourceParameters, resultType, resultName, returnType );
|
||||||
this.propertyMappings = propertyMappings;
|
this.propertyMappings = propertyMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one iterable type to another. The collection
|
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one iterable type to another. The collection
|
||||||
* elements are mapped either by a {@link TypeConversion} or another mapping method.
|
* elements are mapped either by a {@link TypeConversion} or another mapping method.
|
||||||
@ -31,9 +34,10 @@ public class IterableMappingMethod extends MappingMethod {
|
|||||||
private final MappingMethodReference elementMappingMethod;
|
private final MappingMethodReference elementMappingMethod;
|
||||||
private final TypeConversion conversion;
|
private final TypeConversion conversion;
|
||||||
|
|
||||||
public IterableMappingMethod(String name, String parameterName, Type sourceType, Type targetType,
|
public IterableMappingMethod(String name, List<Parameter> parameters, List<Parameter> sourceParameters,
|
||||||
|
Type resultType, String resultName, Type returnType,
|
||||||
MappingMethodReference elementMappingMethod, TypeConversion conversion) {
|
MappingMethodReference elementMappingMethod, TypeConversion conversion) {
|
||||||
super( name, parameterName, sourceType, targetType );
|
super( name, parameters, sourceParameters, resultType, resultName, returnType );
|
||||||
this.elementMappingMethod = elementMappingMethod;
|
this.elementMappingMethod = elementMappingMethod;
|
||||||
this.conversion = conversion;
|
this.conversion = conversion;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one {@code Map} type to another. Keys and
|
* A {@link MappingMethod} implemented by a {@link Mapper} class which maps one {@code Map} type to another. Keys and
|
||||||
* values are mapped either by a {@link TypeConversion} or another mapping method if required.
|
* values are mapped either by a {@link TypeConversion} or another mapping method if required.
|
||||||
@ -33,10 +36,11 @@ public class MapMappingMethod extends MappingMethod {
|
|||||||
private final MappingMethodReference valueMappingMethod;
|
private final MappingMethodReference valueMappingMethod;
|
||||||
private final TypeConversion valueConversion;
|
private final TypeConversion valueConversion;
|
||||||
|
|
||||||
public MapMappingMethod(String name, String parameterName, Type sourceType, Type targetType,
|
public MapMappingMethod(String name, List<Parameter> parameters, List<Parameter> sourceParameters, Type resultType,
|
||||||
|
String resultName, Type returnType,
|
||||||
MappingMethodReference keyMappingMethod, TypeConversion keyConversion,
|
MappingMethodReference keyMappingMethod, TypeConversion keyConversion,
|
||||||
MappingMethodReference valueMappingMethod, TypeConversion valueConversion) {
|
MappingMethodReference valueMappingMethod, TypeConversion valueConversion) {
|
||||||
super( name, parameterName, sourceType, targetType );
|
super( name, parameters, sourceParameters, resultType, resultName, returnType );
|
||||||
|
|
||||||
this.keyMappingMethod = keyMappingMethod;
|
this.keyMappingMethod = keyMappingMethod;
|
||||||
this.keyConversion = keyConversion;
|
this.keyConversion = keyConversion;
|
||||||
@ -68,8 +72,4 @@ public class MapMappingMethod extends MappingMethod {
|
|||||||
|
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getReturnValueName() {
|
|
||||||
return "map";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,11 @@
|
|||||||
package org.mapstruct.ap.model;
|
package org.mapstruct.ap.model;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A method implemented or referenced by a {@link Mapper} class.
|
* A method implemented or referenced by a {@link Mapper} class.
|
||||||
*
|
*
|
||||||
@ -29,38 +32,62 @@ import java.util.Set;
|
|||||||
public abstract class MappingMethod extends AbstractModelElement {
|
public abstract class MappingMethod extends AbstractModelElement {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String parameterName;
|
private final List<Parameter> parameters;
|
||||||
private final Type sourceType;
|
private final List<Parameter> sourceParameters;
|
||||||
private final Type targetType;
|
private final Type resultType;
|
||||||
|
private final String resultName;
|
||||||
|
private final Type returnType;
|
||||||
|
private final boolean existingInstanceMapping;
|
||||||
|
|
||||||
protected MappingMethod(String name, String parameterName, Type sourceType, Type targetType) {
|
protected MappingMethod(String name, List<Parameter> parameters, List<Parameter> sourceParameters, Type resultType,
|
||||||
|
String resultName, Type returnType) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.parameterName = parameterName;
|
this.parameters = parameters;
|
||||||
this.sourceType = sourceType;
|
this.sourceParameters = sourceParameters;
|
||||||
this.targetType = targetType;
|
this.resultType = resultType;
|
||||||
|
this.resultName = resultName;
|
||||||
|
this.returnType = returnType;
|
||||||
|
this.existingInstanceMapping =
|
||||||
|
( null != parameters && null != sourceParameters && parameters.size() > sourceParameters.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParameterName() {
|
public List<Parameter> getParameters() {
|
||||||
return parameterName;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getSourceType() {
|
public List<Parameter> getSourceParameters() {
|
||||||
return sourceType;
|
return sourceParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getTargetType() {
|
public Type getResultType() {
|
||||||
return targetType;
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResultName() {
|
||||||
|
return resultName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExistingInstanceMapping() {
|
||||||
|
return existingInstanceMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Type> getImportTypes() {
|
public Set<Type> getImportTypes() {
|
||||||
Set<Type> types = new HashSet<Type>();
|
Set<Type> types = new HashSet<Type>();
|
||||||
types.add( getSourceType() );
|
|
||||||
types.add( getTargetType() );
|
for ( Parameter param : getParameters() ) {
|
||||||
|
types.add( param.getType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
types.add( getReturnType() );
|
||||||
|
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
@ -69,7 +96,7 @@ public abstract class MappingMethod extends AbstractModelElement {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "MappingMethod {" +
|
return "MappingMethod {" +
|
||||||
"\n name='" + name + "\'," +
|
"\n name='" + name + "\'," +
|
||||||
"\n parameterName='" + parameterName + "\'," +
|
"\n parameters='" + parameters + "\'," +
|
||||||
"\n}";
|
"\n}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,8 @@ public class MappingMethodReference extends MappingMethod {
|
|||||||
|
|
||||||
private final Type declaringMapper;
|
private final Type declaringMapper;
|
||||||
|
|
||||||
public MappingMethodReference(Type declaringMapper, String name, String parameterName, Type sourceType,
|
public MappingMethodReference(Type declaringMapper, String name) {
|
||||||
Type targetType) {
|
super( name, null, null, null, null, null );
|
||||||
super( name, parameterName, sourceType, targetType );
|
|
||||||
this.declaringMapper = declaringMapper;
|
this.declaringMapper = declaringMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,10 +40,6 @@ public class MappingMethodReference extends MappingMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Set<Type> getReferencedTypes() {
|
public Set<Type> getReferencedTypes() {
|
||||||
Set<Type> types = new HashSet<Type>();
|
return new HashSet<Type>();
|
||||||
types.add( getSourceType() );
|
|
||||||
types.add( getTargetType() );
|
|
||||||
|
|
||||||
return types;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ package org.mapstruct.ap.model;
|
|||||||
* The options passed to the code generator.
|
* The options passed to the code generator.
|
||||||
*
|
*
|
||||||
* @author Andreas Gudian
|
* @author Andreas Gudian
|
||||||
* @autor Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class Options {
|
public class Options {
|
||||||
private final boolean suppressGeneratorTimestamp;
|
private final boolean suppressGeneratorTimestamp;
|
||||||
|
@ -38,6 +38,10 @@ import org.mapstruct.ap.util.Strings;
|
|||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
*/
|
*/
|
||||||
public class Type extends AbstractModelElement implements Comparable<Type> {
|
public class Type extends AbstractModelElement implements Comparable<Type> {
|
||||||
|
/**
|
||||||
|
* Type representing {@code void}
|
||||||
|
*/
|
||||||
|
public static final Type VOID = new Type( "void" );
|
||||||
|
|
||||||
private static final Set<String> PRIMITIVE_TYPE_NAMES = new HashSet<String>(
|
private static final Set<String> PRIMITIVE_TYPE_NAMES = new HashSet<String>(
|
||||||
Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" )
|
Arrays.asList( "boolean", "char", "byte", "short", "int", "long", "float", "double" )
|
||||||
@ -61,6 +65,7 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
DEFAULT_MAP_IMPLEMENTATION_TYPES.put( Map.class.getName(), forClass( HashMap.class ) );
|
DEFAULT_MAP_IMPLEMENTATION_TYPES.put( Map.class.getName(), forClass( HashMap.class ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final String canonicalName;
|
||||||
private final String packageName;
|
private final String packageName;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final List<Type> typeParameters;
|
private final List<Type> typeParameters;
|
||||||
@ -77,6 +82,7 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
|
|
||||||
if ( pakkage != null ) {
|
if ( pakkage != null ) {
|
||||||
return new Type(
|
return new Type(
|
||||||
|
clazz.getCanonicalName(),
|
||||||
pakkage.getName(),
|
pakkage.getName(),
|
||||||
clazz.getSimpleName(),
|
clazz.getSimpleName(),
|
||||||
clazz.isEnum(),
|
clazz.isEnum(),
|
||||||
@ -92,15 +98,16 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Type(String name) {
|
public Type(String name) {
|
||||||
this( null, name, false, false, false, false, Collections.<Type>emptyList() );
|
this( name, null, name, false, false, false, false, Collections.<Type>emptyList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type(String packageName, String name) {
|
public Type(String packageName, String name) {
|
||||||
this( packageName, name, false, false, false, false, Collections.<Type>emptyList() );
|
this( packageName + "." + name, packageName, name, false, false, false, false, Collections.<Type>emptyList() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type(String packageName, String name, boolean isEnumType, boolean isCollectionType,
|
public Type(String canonicalName, String packageName, String name, boolean isEnumType, boolean isCollectionType,
|
||||||
boolean isIterableType, boolean isMapType, List<Type> typeParameters) {
|
boolean isIterableType, boolean isMapType, List<Type> typeParameters) {
|
||||||
|
this.canonicalName = canonicalName;
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.isEnumType = isEnumType;
|
this.isEnumType = isEnumType;
|
||||||
@ -126,6 +133,7 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
if ( isMapType ) {
|
if ( isMapType ) {
|
||||||
Type mapType = DEFAULT_MAP_IMPLEMENTATION_TYPES.get( packageName + "." + name );
|
Type mapType = DEFAULT_MAP_IMPLEMENTATION_TYPES.get( packageName + "." + name );
|
||||||
mapImplementationType = mapType != null ? new Type(
|
mapImplementationType = mapType != null ? new Type(
|
||||||
|
mapType.getPackageName() + "." + mapType.getName(),
|
||||||
mapType.getPackageName(),
|
mapType.getPackageName(),
|
||||||
mapType.getName(),
|
mapType.getName(),
|
||||||
mapType.isEnumType(),
|
mapType.isEnumType(),
|
||||||
@ -140,6 +148,10 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCanonicalName() {
|
||||||
|
return canonicalName;
|
||||||
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
return packageName;
|
return packageName;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.model.source;
|
package org.mapstruct.ap.model.source;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
@ -34,23 +37,28 @@ public class Method {
|
|||||||
|
|
||||||
private final Type declaringMapper;
|
private final Type declaringMapper;
|
||||||
private final ExecutableElement executable;
|
private final ExecutableElement executable;
|
||||||
private final String parameterName;
|
private final List<Parameter> parameters;
|
||||||
private final Type sourceType;
|
private final List<Parameter> sourceParameters;
|
||||||
private final Type targetType;
|
private final String resultName;
|
||||||
|
private final Type resultType;
|
||||||
|
private final Type returnType;
|
||||||
private Map<String, Mapping> mappings;
|
private Map<String, Mapping> mappings;
|
||||||
private IterableMapping iterableMapping;
|
private IterableMapping iterableMapping;
|
||||||
private MapMapping mapMapping;
|
private MapMapping mapMapping;
|
||||||
|
|
||||||
public static Method forMethodRequiringImplementation(ExecutableElement executable, String parameterName,
|
public static Method forMethodRequiringImplementation(ExecutableElement executable, List<Parameter> parameters,
|
||||||
Type sourceType, Type targetType,
|
List<Parameter> sourceParameters, Type resultType,
|
||||||
|
String resultName, Type targetType,
|
||||||
Map<String, Mapping> mappings,
|
Map<String, Mapping> mappings,
|
||||||
IterableMapping iterableMapping, MapMapping mapMapping) {
|
IterableMapping iterableMapping, MapMapping mapMapping) {
|
||||||
|
|
||||||
return new Method(
|
return new Method(
|
||||||
null,
|
null,
|
||||||
executable,
|
executable,
|
||||||
parameterName,
|
parameters,
|
||||||
sourceType,
|
sourceParameters,
|
||||||
|
resultType,
|
||||||
|
resultName,
|
||||||
targetType,
|
targetType,
|
||||||
mappings,
|
mappings,
|
||||||
iterableMapping,
|
iterableMapping,
|
||||||
@ -64,8 +72,10 @@ public class Method {
|
|||||||
return new Method(
|
return new Method(
|
||||||
declaringMapper,
|
declaringMapper,
|
||||||
executable,
|
executable,
|
||||||
parameterName,
|
Arrays.asList( new Parameter( parameterName, sourceType ) ),
|
||||||
sourceType,
|
Arrays.asList( new Parameter( parameterName, sourceType ) ),
|
||||||
|
targetType,
|
||||||
|
null,
|
||||||
targetType,
|
targetType,
|
||||||
Collections.<String, Mapping>emptyMap(),
|
Collections.<String, Mapping>emptyMap(),
|
||||||
null,
|
null,
|
||||||
@ -73,14 +83,18 @@ public class Method {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Method(Type declaringMapper, ExecutableElement executable, String parameterName, Type sourceType,
|
private Method(Type declaringMapper, ExecutableElement executable, List<Parameter> parameters,
|
||||||
Type targetType, Map<String, Mapping> mappings, IterableMapping iterableMapping,
|
List<Parameter> sourceParameters, Type resultType, String resultName,
|
||||||
|
Type returnType,
|
||||||
|
Map<String, Mapping> mappings, IterableMapping iterableMapping,
|
||||||
MapMapping mapMapping) {
|
MapMapping mapMapping) {
|
||||||
this.declaringMapper = declaringMapper;
|
this.declaringMapper = declaringMapper;
|
||||||
this.executable = executable;
|
this.executable = executable;
|
||||||
this.parameterName = parameterName;
|
this.parameters = parameters;
|
||||||
this.sourceType = sourceType;
|
this.sourceParameters = sourceParameters;
|
||||||
this.targetType = targetType;
|
this.resultType = resultType;
|
||||||
|
this.resultName = resultName;
|
||||||
|
this.returnType = returnType;
|
||||||
this.mappings = mappings;
|
this.mappings = mappings;
|
||||||
this.iterableMapping = iterableMapping;
|
this.iterableMapping = iterableMapping;
|
||||||
this.mapMapping = mapMapping;
|
this.mapMapping = mapMapping;
|
||||||
@ -105,16 +119,24 @@ public class Method {
|
|||||||
return executable.getSimpleName().toString();
|
return executable.getSimpleName().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getParameterName() {
|
public List<Parameter> getParameters() {
|
||||||
return parameterName;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getSourceType() {
|
public String getResultName() {
|
||||||
return sourceType;
|
return resultName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getTargetType() {
|
public List<Parameter> getSourceParameters() {
|
||||||
return targetType;
|
return sourceParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getResultType() {
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getReturnType() {
|
||||||
|
return returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Mapping> getMappings() {
|
public Map<String, Mapping> getMappings() {
|
||||||
@ -143,16 +165,20 @@ public class Method {
|
|||||||
|
|
||||||
public boolean reverses(Method method) {
|
public boolean reverses(Method method) {
|
||||||
return
|
return
|
||||||
equals( sourceType, method.getTargetType() ) &&
|
equals( getSingleSourceType(), method.getReturnType() )
|
||||||
equals( targetType, method.getSourceType() );
|
&& equals( returnType, method.getSingleSourceType() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getSingleSourceType() {
|
||||||
|
return sourceParameters.size() == 1 ? sourceParameters.get( 0 ).getType() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIterableMapping() {
|
public boolean isIterableMapping() {
|
||||||
return sourceType.isIterableType() && targetType.isIterableType();
|
return getSingleSourceType().isIterableType() && resultType.isIterableType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMapMapping() {
|
public boolean isMapMapping() {
|
||||||
return sourceType.isMapType() && targetType.isMapType();
|
return getSingleSourceType().isMapType() && resultType.isMapType();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean equals(Object o1, Object o2) {
|
private boolean equals(Object o1, Object o2) {
|
||||||
@ -161,6 +187,19 @@ public class Method {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return targetType + " " + getName() + "(" + sourceType + " " + parameterName + ")";
|
return returnType + " " + getName() + "(" + getParamsList() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getParamsList() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for ( Iterator<Parameter> it = parameters.iterator(); it.hasNext(); ) {
|
||||||
|
Parameter param = it.next();
|
||||||
|
sb.append( param.getType() ).append( " " ).append( param.getName() );
|
||||||
|
if ( it.hasNext() ) {
|
||||||
|
sb.append( ", " );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,16 @@ public class Parameter {
|
|||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Type type;
|
private final Type type;
|
||||||
|
private final boolean mappingTarget;
|
||||||
|
|
||||||
public Parameter(String name, Type type) {
|
public Parameter(String name, Type type, boolean mappingTarget) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.mappingTarget = mappingTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Parameter(String name, Type type) {
|
||||||
|
this( name, type, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -43,8 +49,12 @@ public class Parameter {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMappingTarget() {
|
||||||
|
return mappingTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return type.toString() + " " + name;
|
return ( mappingTarget ? "@MappingTarget " : "" ) + type.toString() + " " + name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ import org.mapstruct.ap.model.Type;
|
|||||||
import org.mapstruct.ap.model.TypeConversion;
|
import org.mapstruct.ap.model.TypeConversion;
|
||||||
import org.mapstruct.ap.model.source.Mapping;
|
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.Parameter;
|
||||||
import org.mapstruct.ap.util.Executables;
|
import org.mapstruct.ap.util.Executables;
|
||||||
import org.mapstruct.ap.util.Filters;
|
import org.mapstruct.ap.util.Filters;
|
||||||
import org.mapstruct.ap.util.Strings;
|
import org.mapstruct.ap.util.Strings;
|
||||||
@ -200,19 +201,14 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
|
|
||||||
Map<String, Mapping> mappings = method.getMappings();
|
Map<String, Mapping> mappings = method.getMappings();
|
||||||
|
|
||||||
TypeElement returnTypeElement = (TypeElement) typeUtils.asElement( method.getExecutable().getReturnType() );
|
TypeElement resultTypeElement = elementUtils.getTypeElement( method.getResultType().getCanonicalName() );
|
||||||
TypeElement parameterElement = (TypeElement) typeUtils.asElement(
|
TypeElement parameterElement = elementUtils.getTypeElement( method.getSingleSourceType().getCanonicalName() );
|
||||||
method.getExecutable()
|
|
||||||
.getParameters()
|
|
||||||
.get( 0 )
|
|
||||||
.asType()
|
|
||||||
);
|
|
||||||
|
|
||||||
List<ExecutableElement> sourceGetters = Filters.getterMethodsIn(
|
List<ExecutableElement> sourceGetters = Filters.getterMethodsIn(
|
||||||
elementUtils.getAllMembers( parameterElement )
|
elementUtils.getAllMembers( parameterElement )
|
||||||
);
|
);
|
||||||
List<ExecutableElement> targetSetters = Filters.setterMethodsIn(
|
List<ExecutableElement> targetSetters = Filters.setterMethodsIn(
|
||||||
elementUtils.getAllMembers( returnTypeElement )
|
elementUtils.getAllMembers( resultTypeElement )
|
||||||
);
|
);
|
||||||
|
|
||||||
Set<String> sourceProperties = executables.getPropertyNames(
|
Set<String> sourceProperties = executables.getPropertyNames(
|
||||||
@ -257,9 +253,11 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
|
|
||||||
return new BeanMappingMethod(
|
return new BeanMappingMethod(
|
||||||
method.getName(),
|
method.getName(),
|
||||||
method.getParameterName(),
|
method.getParameters(),
|
||||||
method.getSourceType(),
|
method.getSourceParameters(),
|
||||||
method.getTargetType(),
|
method.getResultType(),
|
||||||
|
method.getResultName(),
|
||||||
|
method.getReturnType(),
|
||||||
propertyMappings
|
propertyMappings
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -302,7 +300,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
String.format(
|
String.format(
|
||||||
"Unknown property \"%s\" in parameter type %s.",
|
"Unknown property \"%s\" in parameter type %s.",
|
||||||
mappedProperty.getSourceName(),
|
mappedProperty.getSourceName(),
|
||||||
method.getSourceType()
|
method.getSingleSourceType()
|
||||||
),
|
),
|
||||||
method.getExecutable(),
|
method.getExecutable(),
|
||||||
mappedProperty.getMirror(),
|
mappedProperty.getMirror(),
|
||||||
@ -315,7 +313,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
String.format(
|
String.format(
|
||||||
"Unknown property \"%s\" in return type %s.",
|
"Unknown property \"%s\" in return type %s.",
|
||||||
mappedProperty.getTargetName(),
|
mappedProperty.getTargetName(),
|
||||||
method.getTargetType()
|
method.getResultType()
|
||||||
),
|
),
|
||||||
method.getExecutable(),
|
method.getExecutable(),
|
||||||
mappedProperty.getMirror(),
|
mappedProperty.getMirror(),
|
||||||
@ -328,19 +326,20 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
private PropertyMapping getPropertyMapping(List<Method> methods, Method method, ExecutableElement getterMethod,
|
private PropertyMapping getPropertyMapping(List<Method> methods, Method method, ExecutableElement getterMethod,
|
||||||
ExecutableElement setterMethod, String dateFormat) {
|
ExecutableElement setterMethod, String dateFormat) {
|
||||||
Type sourceType = executables.retrieveReturnType( getterMethod );
|
Type sourceType = executables.retrieveReturnType( getterMethod );
|
||||||
Type targetType = executables.retrieveParameter( setterMethod ).getType();
|
Type targetType = executables.retrieveSingleParameter( setterMethod ).getType();
|
||||||
|
|
||||||
MappingMethodReference propertyMappingMethod = getMappingMethodReference( methods, sourceType, targetType );
|
MappingMethodReference propertyMappingMethod = getMappingMethodReference( methods, sourceType, targetType );
|
||||||
TypeConversion conversion = getConversion(
|
TypeConversion conversion = getConversion(
|
||||||
sourceType,
|
sourceType,
|
||||||
targetType,
|
targetType,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
method.getParameterName() + "." + getterMethod.getSimpleName().toString() + "()"
|
method.getSourceParameters().get( 0 ).getName() + "."
|
||||||
|
+ getterMethod.getSimpleName().toString() + "()"
|
||||||
);
|
);
|
||||||
|
|
||||||
PropertyMapping property = new PropertyMapping(
|
PropertyMapping property = new PropertyMapping(
|
||||||
method.getParameterName(),
|
method.getSourceParameters().get( 0 ).getName(),
|
||||||
Introspector.decapitalize( method.getTargetType().getName() ),
|
method.getResultName(),
|
||||||
executables.getPropertyName( getterMethod ),
|
executables.getPropertyName( getterMethod ),
|
||||||
getterMethod.getSimpleName().toString(),
|
getterMethod.getSimpleName().toString(),
|
||||||
sourceType,
|
sourceType,
|
||||||
@ -360,8 +359,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MappingMethod getIterableMappingMethod(List<Method> methods, Method method) {
|
private MappingMethod getIterableMappingMethod(List<Method> methods, Method method) {
|
||||||
Type sourceElementType = method.getSourceType().getTypeParameters().get( 0 );
|
Type sourceElementType = method.getSourceParameters().get( 0 ).getType().getTypeParameters().get( 0 );
|
||||||
Type targetElementType = method.getTargetType().getTypeParameters().get( 0 );
|
Type targetElementType = method.getResultType().getTypeParameters().get( 0 );
|
||||||
|
|
||||||
TypeConversion conversion = getConversion(
|
TypeConversion conversion = getConversion(
|
||||||
sourceElementType,
|
sourceElementType,
|
||||||
@ -372,19 +371,24 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
|
|
||||||
return new IterableMappingMethod(
|
return new IterableMappingMethod(
|
||||||
method.getName(),
|
method.getName(),
|
||||||
method.getParameterName(),
|
method.getParameters(),
|
||||||
method.getSourceType(),
|
method.getSourceParameters(),
|
||||||
method.getTargetType(),
|
method.getResultType(),
|
||||||
|
method.getResultName(),
|
||||||
|
method.getReturnType(),
|
||||||
getMappingMethodReference( methods, sourceElementType, targetElementType ),
|
getMappingMethodReference( methods, sourceElementType, targetElementType ),
|
||||||
conversion
|
conversion
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingMethod getMapMappingMethod(List<Method> methods, Method method) {
|
private MappingMethod getMapMappingMethod(List<Method> methods, Method method) {
|
||||||
Type sourceKeyType = method.getSourceType().getTypeParameters().get( 0 );
|
List<Type> sourceTypeParams = method.getSourceParameters().get( 0 ).getType().getTypeParameters();
|
||||||
Type sourceValueType = method.getSourceType().getTypeParameters().get( 1 );
|
Type sourceKeyType = sourceTypeParams.get( 0 );
|
||||||
Type targetKeyType = method.getTargetType().getTypeParameters().get( 0 );
|
Type sourceValueType = sourceTypeParams.get( 1 );
|
||||||
Type targetValueType = method.getTargetType().getTypeParameters().get( 1 );
|
|
||||||
|
List<Type> resultTypeParams = method.getResultType().getTypeParameters();
|
||||||
|
Type targetKeyType = resultTypeParams.get( 0 );
|
||||||
|
Type targetValueType = resultTypeParams.get( 1 );
|
||||||
|
|
||||||
String keyDateFormat = method.getMapMapping() != null ? method.getMapMapping().getKeyFormat() : null;
|
String keyDateFormat = method.getMapMapping() != null ? method.getMapMapping().getKeyFormat() : null;
|
||||||
String valueDateFormat = method.getMapMapping() != null ? method.getMapMapping().getValueFormat() : null;
|
String valueDateFormat = method.getMapMapping() != null ? method.getMapMapping().getValueFormat() : null;
|
||||||
@ -406,9 +410,11 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
|
|
||||||
return new MapMappingMethod(
|
return new MapMappingMethod(
|
||||||
method.getName(),
|
method.getName(),
|
||||||
method.getParameterName(),
|
method.getParameters(),
|
||||||
method.getSourceType(),
|
method.getSourceParameters(),
|
||||||
method.getTargetType(),
|
method.getResultType(),
|
||||||
|
method.getResultName(),
|
||||||
|
method.getReturnType(),
|
||||||
keyMappingMethod,
|
keyMappingMethod,
|
||||||
keyConversion,
|
keyConversion,
|
||||||
valueMappingMethod,
|
valueMappingMethod,
|
||||||
@ -429,13 +435,13 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
|||||||
private MappingMethodReference getMappingMethodReference(Iterable<Method> methods, Type parameterType,
|
private MappingMethodReference getMappingMethodReference(Iterable<Method> methods, Type parameterType,
|
||||||
Type returnType) {
|
Type returnType) {
|
||||||
for ( Method oneMethod : methods ) {
|
for ( Method oneMethod : methods ) {
|
||||||
if ( oneMethod.getSourceType().equals( parameterType ) && oneMethod.getTargetType().equals( returnType ) ) {
|
Parameter singleSourceParam = oneMethod.getSourceParameters().get( 0 );
|
||||||
|
|
||||||
|
if ( singleSourceParam.getType().equals( parameterType ) &&
|
||||||
|
oneMethod.getReturnType().equals( returnType ) ) {
|
||||||
return new MappingMethodReference(
|
return new MappingMethodReference(
|
||||||
oneMethod.getDeclaringMapper(),
|
oneMethod.getDeclaringMapper(),
|
||||||
oneMethod.getName(),
|
oneMethod.getName()
|
||||||
oneMethod.getParameterName(),
|
|
||||||
oneMethod.getSourceType(),
|
|
||||||
oneMethod.getTargetType()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.processor;
|
package org.mapstruct.ap.processor;
|
||||||
|
|
||||||
|
import java.beans.Introspector;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -115,19 +116,26 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Method getMethod(TypeElement element, ExecutableElement method, boolean implementationRequired) {
|
private Method getMethod(TypeElement element, ExecutableElement method, boolean implementationRequired) {
|
||||||
Parameter parameter = executables.retrieveParameter( method );
|
List<Parameter> parameters = executables.retrieveParameters( method );
|
||||||
Type returnType = executables.retrieveReturnType( method );
|
Type returnType = executables.retrieveReturnType( method );
|
||||||
|
|
||||||
//add method with property mappings if an implementation needs to be generated
|
//add method with property mappings if an implementation needs to be generated
|
||||||
if ( implementationRequired ) {
|
if ( implementationRequired ) {
|
||||||
boolean isValid = checkParameterAndReturnType( method, parameter.getType(), returnType );
|
List<Parameter> sourceParameters = extractSourceParameters( parameters );
|
||||||
|
Parameter targetParameter = extractTargetParameter( parameters );
|
||||||
|
Type resultType = selectResultType( returnType, targetParameter );
|
||||||
|
|
||||||
|
boolean isValid =
|
||||||
|
checkParameterAndReturnType( method, sourceParameters, targetParameter, resultType, returnType );
|
||||||
|
|
||||||
if ( isValid ) {
|
if ( isValid ) {
|
||||||
return
|
return
|
||||||
Method.forMethodRequiringImplementation(
|
Method.forMethodRequiringImplementation(
|
||||||
method,
|
method,
|
||||||
parameter.getName(),
|
parameters,
|
||||||
parameter.getType(),
|
sourceParameters,
|
||||||
|
resultType,
|
||||||
|
selectResultName( targetParameter, resultType ),
|
||||||
returnType,
|
returnType,
|
||||||
getMappings( method ),
|
getMappings( method ),
|
||||||
IterableMapping.fromPrism( IterableMappingPrism.getInstanceOn( method ) ),
|
IterableMapping.fromPrism( IterableMappingPrism.getInstanceOn( method ) ),
|
||||||
@ -139,20 +147,102 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//otherwise add reference to existing mapper method
|
//otherwise add reference to existing mapper method
|
||||||
else {
|
else if ( parameters.size() == 1 ) {
|
||||||
return
|
return
|
||||||
Method.forReferencedMethod(
|
Method.forReferencedMethod(
|
||||||
typeUtil.getType( typeUtils.getDeclaredType( element ) ),
|
typeUtil.getType( typeUtils.getDeclaredType( element ) ),
|
||||||
method,
|
method,
|
||||||
parameter.getName(),
|
parameters.get( 0 ).getName(),
|
||||||
parameter.getType(),
|
parameters.get( 0 ).getType(),
|
||||||
returnType
|
returnType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkParameterAndReturnType(ExecutableElement method, Type parameterType, Type returnType) {
|
private Parameter extractTargetParameter(List<Parameter> parameters) {
|
||||||
if ( parameterType.isIterableType() && !returnType.isIterableType() ) {
|
for ( Parameter param : parameters ) {
|
||||||
|
if ( param.isMappingTarget() ) {
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Parameter> extractSourceParameters(List<Parameter> parameters) {
|
||||||
|
List<Parameter> sourceParameters = new ArrayList<Parameter>( parameters.size() );
|
||||||
|
for ( Parameter param : parameters ) {
|
||||||
|
if ( !param.isMappingTarget() ) {
|
||||||
|
sourceParameters.add( param );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String selectResultName(Parameter targetParameter, Type resultType) {
|
||||||
|
if ( null != targetParameter ) {
|
||||||
|
return targetParameter.getName();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Introspector.decapitalize( resultType.getName() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type selectResultType(Type returnType, Parameter targetParameter) {
|
||||||
|
if ( null != targetParameter ) {
|
||||||
|
return targetParameter.getType();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkParameterAndReturnType(ExecutableElement method, List<Parameter> sourceParameters,
|
||||||
|
Parameter targetParameter, Type resultType, Type returnType) {
|
||||||
|
if ( sourceParameters.isEmpty() ) {
|
||||||
|
messager.printMessage( Kind.ERROR, "Can't generate mapping method with no input arguments.", method );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( sourceParameters.size() > 1 ) {
|
||||||
|
messager.printMessage(
|
||||||
|
Kind.ERROR,
|
||||||
|
"Mappings from more than one source objects are not yet supported.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( targetParameter != null && ( sourceParameters.size() + 1 != method.getParameters().size() ) ) {
|
||||||
|
messager.printMessage(
|
||||||
|
Kind.ERROR,
|
||||||
|
"Can't generate mapping method with more than one @MappingTarget parameter.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( resultType == Type.VOID ) {
|
||||||
|
messager.printMessage( Kind.ERROR, "Can't generate mapping method with return type void.", method );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( returnType != Type.VOID && !typeUtil.isAssignable( resultType, returnType ) ) {
|
||||||
|
messager.printMessage(
|
||||||
|
Kind.ERROR,
|
||||||
|
"The result type is not assignable to the the return type.",
|
||||||
|
method
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type parameterType = sourceParameters.get( 0 ).getType();
|
||||||
|
|
||||||
|
if ( parameterType.isIterableType() && !resultType.isIterableType() ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
Kind.ERROR,
|
Kind.ERROR,
|
||||||
"Can't generate mapping method from iterable type to non-iterable type.",
|
"Can't generate mapping method from iterable type to non-iterable type.",
|
||||||
@ -161,7 +251,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !parameterType.isIterableType() && returnType.isIterableType() ) {
|
if ( !parameterType.isIterableType() && resultType.isIterableType() ) {
|
||||||
messager.printMessage(
|
messager.printMessage(
|
||||||
Kind.ERROR,
|
Kind.ERROR,
|
||||||
"Can't generate mapping method from non-iterable type to iterable type.",
|
"Can't generate mapping method from non-iterable type to iterable type.",
|
||||||
@ -175,7 +265,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( returnType.isPrimitive() ) {
|
if ( resultType.isPrimitive() ) {
|
||||||
messager.printMessage( Kind.ERROR, "Can't generate mapping method with primitive return type.", method );
|
messager.printMessage( Kind.ERROR, "Can't generate mapping method with primitive return type.", method );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,16 @@
|
|||||||
package org.mapstruct.ap.util;
|
package org.mapstruct.ap.util;
|
||||||
|
|
||||||
import java.beans.Introspector;
|
import java.beans.Introspector;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.MappingTargetPrism;
|
||||||
import org.mapstruct.ap.model.Type;
|
import org.mapstruct.ap.model.Type;
|
||||||
import org.mapstruct.ap.model.source.Parameter;
|
import org.mapstruct.ap.model.source.Parameter;
|
||||||
|
|
||||||
@ -105,7 +108,7 @@ public class Executables {
|
|||||||
return propertyNames;
|
return propertyNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Parameter retrieveParameter(ExecutableElement method) {
|
public Parameter retrieveSingleParameter(ExecutableElement method) {
|
||||||
List<? extends VariableElement> parameters = method.getParameters();
|
List<? extends VariableElement> parameters = method.getParameters();
|
||||||
|
|
||||||
if ( parameters.size() != 1 ) {
|
if ( parameters.size() != 1 ) {
|
||||||
@ -117,10 +120,42 @@ public class Executables {
|
|||||||
|
|
||||||
return new Parameter(
|
return new Parameter(
|
||||||
parameter.getSimpleName().toString(),
|
parameter.getSimpleName().toString(),
|
||||||
typeUtil.retrieveType( parameter.asType() )
|
typeUtil.retrieveType( parameter.asType() ),
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Parameter> retrieveParameters(ExecutableElement method) {
|
||||||
|
List<? extends VariableElement> parameters = method.getParameters();
|
||||||
|
List<Parameter> result = new ArrayList<Parameter>( parameters.size() );
|
||||||
|
|
||||||
|
boolean mappingTargetDefined = false;
|
||||||
|
for ( Iterator<? extends VariableElement> it = parameters.iterator(); it.hasNext(); ) {
|
||||||
|
VariableElement parameter = it.next();
|
||||||
|
|
||||||
|
boolean isExplicitMappingTarget = null != MappingTargetPrism.getInstanceOn( parameter );
|
||||||
|
mappingTargetDefined |= isExplicitMappingTarget;
|
||||||
|
|
||||||
|
result
|
||||||
|
.add(
|
||||||
|
new Parameter(
|
||||||
|
parameter.getSimpleName().toString(),
|
||||||
|
typeUtil.retrieveType( parameter.asType() ),
|
||||||
|
// the parameter is a mapping target, if it was either defined explicitly or if if this is the
|
||||||
|
// last parameter in a multi-argument void method
|
||||||
|
isExplicitMappingTarget
|
||||||
|
|| ( !mappingTargetDefined && isMultiArgVoidMethod( method ) && !it.hasNext() )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMultiArgVoidMethod(ExecutableElement method) {
|
||||||
|
return method.getParameters().size() > 1 && Type.VOID == retrieveReturnType( method );
|
||||||
|
}
|
||||||
|
|
||||||
public Type retrieveReturnType(ExecutableElement method) {
|
public Type retrieveReturnType(ExecutableElement method) {
|
||||||
return typeUtil.retrieveType( method.getReturnType() );
|
return typeUtil.retrieveType( method.getReturnType() );
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
@ -56,6 +57,7 @@ public class TypeUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Type(
|
return new Type(
|
||||||
|
( (TypeElement) type.asElement() ).getQualifiedName().toString(),
|
||||||
elementUtils.getPackageOf( type.asElement() ).toString(),
|
elementUtils.getPackageOf( type.asElement() ).toString(),
|
||||||
type.asElement().getSimpleName().toString(),
|
type.asElement().getSimpleName().toString(),
|
||||||
type.asElement().getKind() == ElementKind.ENUM,
|
type.asElement().getKind() == ElementKind.ENUM,
|
||||||
@ -85,8 +87,42 @@ public class TypeUtil {
|
|||||||
else if ( mirror.getKind() == TypeKind.DECLARED ) {
|
else if ( mirror.getKind() == TypeKind.DECLARED ) {
|
||||||
return getType( ( (DeclaredType) mirror ) );
|
return getType( ( (DeclaredType) mirror ) );
|
||||||
}
|
}
|
||||||
|
else if ( mirror.getKind() == TypeKind.VOID ) {
|
||||||
|
return Type.VOID;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return new Type( mirror.toString() );
|
return new Type( mirror.toString() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type1 first type
|
||||||
|
* @param type2 second type
|
||||||
|
*
|
||||||
|
* @return {@code true} if and only if the first type is assignable to the second
|
||||||
|
*/
|
||||||
|
public boolean isAssignable(Type type1, Type type2) {
|
||||||
|
if ( type1.equals( type2 ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeMirror mirror1 = toTypeMirror( type1 );
|
||||||
|
TypeMirror mirror2 = toTypeMirror( type2 );
|
||||||
|
return null != mirror1 && null != mirror2 && typeUtils.isAssignable( mirror1, mirror2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeMirror toTypeMirror(Type type) {
|
||||||
|
TypeElement rawType = elementUtils.getTypeElement( type.getCanonicalName() );
|
||||||
|
|
||||||
|
if ( null == rawType ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeMirror[] parameters = new TypeMirror[type.getTypeParameters().size()];
|
||||||
|
for ( int i = 0; i < type.getTypeParameters().size(); i++ ) {
|
||||||
|
parameters[i] = toTypeMirror( type.getTypeParameters().get( i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeUtils.getDeclaredType( rawType, parameters );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,19 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
@Override
|
@Override
|
||||||
public ${targetType.name} ${name}(${sourceType.name} ${parameterName}) {
|
public ${returnType.name} ${name}(<#list parameters as param>${param.type.name} ${param.name}<#if param_has_next>, </#if></#list>) {
|
||||||
if ( ${parameterName} == null ) {
|
if ( ${sourceParameters[0].name} == null ) {
|
||||||
return null;
|
return<#if returnType.name != "void"> null</#if>;
|
||||||
}
|
}
|
||||||
|
<#if !existingInstanceMapping>
|
||||||
${targetType.name} ${targetType.name?uncap_first} = new ${targetType.name}();
|
${resultType.name} ${resultName} = new ${resultType.name}();
|
||||||
|
</#if>
|
||||||
|
|
||||||
<#list propertyMappings as propertyMapping>
|
<#list propertyMappings as propertyMapping>
|
||||||
<@includeModel object=propertyMapping/>
|
<@includeModel object=propertyMapping/>
|
||||||
</#list>
|
</#list>
|
||||||
|
<#if returnType.name != "void">
|
||||||
|
|
||||||
return ${targetType.name?uncap_first};
|
return ${resultName};
|
||||||
|
</#if>
|
||||||
}
|
}
|
||||||
|
@ -19,23 +19,27 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
@Override
|
@Override
|
||||||
public <@includeModel object=targetType/> ${name}(<@includeModel object=sourceType/> ${parameterName}) {
|
public <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param.type/> ${param.name}<#if param_has_next>, </#if></#list>) {
|
||||||
if ( ${parameterName} == null ) {
|
if ( ${sourceParameters[0].name} == null ) {
|
||||||
return null;
|
return<#if returnType.name != "void"> null</#if>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<#if existingInstanceMapping>
|
||||||
|
${resultName}.clear();
|
||||||
|
<#else>
|
||||||
<#-- Use the interface type on the left side, except it is java.lang.Iterable; use the implementation type - if present - on the right side -->
|
<#-- Use the interface type on the left side, except it is java.lang.Iterable; use the implementation type - if present - on the right side -->
|
||||||
<#if targetType.name == "Iterable" && targetType.packageName == "java.lang">${targetType.iterableImplementationType.name}<#else>${targetType.name}</#if><<@includeModel object=targetType.typeParameters[0]/>> ${targetType.name?uncap_first} = new <#if targetType.iterableImplementationType??>${targetType.iterableImplementationType.name}<#else>${targetType.name}</#if><<@includeModel object=targetType.typeParameters[0]/>>();
|
<#if resultType.name == "Iterable" && resultType.packageName == "java.lang">${resultType.iterableImplementationType.name}<#else>${resultType.name}</#if><<@includeModel object=resultType.typeParameters[0]/>> ${resultName} = new <#if resultType.iterableImplementationType??>${resultType.iterableImplementationType.name}<#else>${resultType.name}</#if><<@includeModel object=resultType.typeParameters[0]/>>();
|
||||||
|
</#if>
|
||||||
|
|
||||||
for ( <@includeModel object=sourceType.typeParameters[0]/> ${sourceType.typeParameters[0].name?uncap_first} : ${parameterName} ) {
|
for ( <@includeModel object=sourceParameters[0].type.typeParameters[0]/> ${sourceParameters[0].type.typeParameters[0].name?uncap_first} : ${sourceParameters[0].name} ) {
|
||||||
<#if elementMappingMethod??>
|
<#if elementMappingMethod??>
|
||||||
${targetType.name?uncap_first}.add( <@includeModel object=elementMappingMethod input="${sourceType.typeParameters[0].name?uncap_first}"/> );
|
${resultName}.add( <@includeModel object=elementMappingMethod input="${sourceParameters[0].type.typeParameters[0].name?uncap_first}"/> );
|
||||||
<#else>
|
<#else>
|
||||||
<#if (conversion.exceptionTypes?size == 0) >
|
<#if (conversion.exceptionTypes?size == 0) >
|
||||||
${targetType.name?uncap_first}.add( <@includeModel object=conversion/> );
|
${resultName}.add( <@includeModel object=conversion/> );
|
||||||
<#else>
|
<#else>
|
||||||
try {
|
try {
|
||||||
${targetType.name?uncap_first}.add( <@includeModel object=conversion/> );
|
${resultName}.add( <@includeModel object=conversion/> );
|
||||||
}
|
}
|
||||||
<#list conversion.exceptionTypes as exceptionType>
|
<#list conversion.exceptionTypes as exceptionType>
|
||||||
catch( ${exceptionType.name} e ) {
|
catch( ${exceptionType.name} e ) {
|
||||||
@ -45,6 +49,8 @@
|
|||||||
</#if>
|
</#if>
|
||||||
</#if>
|
</#if>
|
||||||
}
|
}
|
||||||
|
<#if returnType.name != "void">
|
||||||
|
|
||||||
return ${targetType.name?uncap_first};
|
return ${resultName};
|
||||||
|
</#if>
|
||||||
}
|
}
|
||||||
|
@ -19,23 +19,27 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
@Override
|
@Override
|
||||||
public <@includeModel object=targetType /> ${name}(<@includeModel object=sourceType /> ${parameterName}) {
|
public <@includeModel object=returnType /> ${name}(<#list parameters as param><@includeModel object=param.type/> ${param.name}<#if param_has_next>, </#if></#list>) {
|
||||||
if ( ${parameterName} == null ) {
|
if ( ${sourceParameters[0].name} == null ) {
|
||||||
return null;
|
return<#if returnType.name != "void"> null</#if>;
|
||||||
}
|
}
|
||||||
|
|
||||||
<@includeModel object=targetType /> ${returnValueName} = new <#if targetType.mapImplementationType??><@includeModel object=targetType.mapImplementationType /><#else><@includeModel object=targetType /></#if>();
|
<#if existingInstanceMapping>
|
||||||
|
${resultName}.clear();
|
||||||
|
<#else>
|
||||||
|
<@includeModel object=resultType /> ${resultName} = new <#if resultType.mapImplementationType??><@includeModel object=resultType.mapImplementationType /><#else><@includeModel object=resultType /></#if>();
|
||||||
|
</#if>
|
||||||
|
|
||||||
for ( Map.Entry<<#list sourceType.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>> entry : ${parameterName}.entrySet() ) {
|
for ( Map.Entry<<#list sourceParameters[0].type.typeParameters as typeParameter><@includeModel object=typeParameter /><#if typeParameter_has_next>, </#if></#list>> entry : ${sourceParameters[0].name}.entrySet() ) {
|
||||||
|
|
||||||
<#-- key -->
|
<#-- key -->
|
||||||
<#if keyMappingMethod??>
|
<#if keyMappingMethod??>
|
||||||
<@includeModel object=targetType.typeParameters[0]/> key = <@includeModel object=keyMappingMethod input="entry.getKey()"/>;
|
<@includeModel object=resultType.typeParameters[0]/> key = <@includeModel object=keyMappingMethod input="entry.getKey()"/>;
|
||||||
<#elseif keyConversion??>
|
<#elseif keyConversion??>
|
||||||
<#if (keyConversion.exceptionTypes?size == 0) >
|
<#if (keyConversion.exceptionTypes?size == 0) >
|
||||||
<@includeModel object=targetType.typeParameters[0]/> key = <@includeModel object=keyConversion/>;
|
<@includeModel object=resultType.typeParameters[0]/> key = <@includeModel object=keyConversion/>;
|
||||||
<#else>
|
<#else>
|
||||||
<@includeModel object=targetType.typeParameters[0]/> key;
|
<@includeModel object=resultType.typeParameters[0]/> key;
|
||||||
try {
|
try {
|
||||||
key = <@includeModel object=keyConversion/>;
|
key = <@includeModel object=keyConversion/>;
|
||||||
}
|
}
|
||||||
@ -46,16 +50,16 @@
|
|||||||
</#list>
|
</#list>
|
||||||
</#if>
|
</#if>
|
||||||
<#else>
|
<#else>
|
||||||
<@includeModel object=targetType.typeParameters[0]/> key = entry.getKey();
|
<@includeModel object=resultType.typeParameters[0]/> key = entry.getKey();
|
||||||
</#if>
|
</#if>
|
||||||
<#-- value -->
|
<#-- value -->
|
||||||
<#if valueMappingMethod??>
|
<#if valueMappingMethod??>
|
||||||
<@includeModel object=targetType.typeParameters[1]/> value = <@includeModel object=valueMappingMethod input="entry.getValue()"/>;
|
<@includeModel object=resultType.typeParameters[1]/> value = <@includeModel object=valueMappingMethod input="entry.getValue()"/>;
|
||||||
<#elseif valueConversion??>
|
<#elseif valueConversion??>
|
||||||
<#if (valueConversion.exceptionTypes?size == 0) >
|
<#if (valueConversion.exceptionTypes?size == 0) >
|
||||||
<@includeModel object=targetType.typeParameters[1]/> value = <@includeModel object=valueConversion/>;
|
<@includeModel object=resultType.typeParameters[1]/> value = <@includeModel object=valueConversion/>;
|
||||||
<#else>
|
<#else>
|
||||||
<@includeModel object=targetType.typeParameters[1]/> value;
|
<@includeModel object=resultType.typeParameters[1]/> value;
|
||||||
try {
|
try {
|
||||||
value = <@includeModel object=valueConversion/>;
|
value = <@includeModel object=valueConversion/>;
|
||||||
}
|
}
|
||||||
@ -66,11 +70,13 @@
|
|||||||
</#list>
|
</#list>
|
||||||
</#if>
|
</#if>
|
||||||
<#else>
|
<#else>
|
||||||
<@includeModel object=targetType.typeParameters[1]/> value = entry.getValue();
|
<@includeModel object=resultType.typeParameters[1]/> value = entry.getValue();
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
${returnValueName}.put( key, value );
|
${resultName}.put( key, value );
|
||||||
}
|
}
|
||||||
|
<#if returnType.name != "void">
|
||||||
|
|
||||||
return ${returnValueName};
|
return ${resultName};
|
||||||
|
</#if>
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.test.collection.defaultimplementation;
|
package org.mapstruct.ap.test.collection.defaultimplementation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
import org.mapstruct.ap.testutil.MapperTestBase;
|
import org.mapstruct.ap.testutil.MapperTestBase;
|
||||||
@ -41,7 +43,7 @@ public class DefaultCollectionImplementationTest extends MapperTestBase {
|
|||||||
@IssueKey("6")
|
@IssueKey("6")
|
||||||
public void shouldUseDefaultImplementationForList() {
|
public void shouldUseDefaultImplementationForList() {
|
||||||
Source source = new Source();
|
Source source = new Source();
|
||||||
source.setFooList( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) );
|
source.setFooList( createSourceFooList() );
|
||||||
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
@ -52,7 +54,7 @@ public class DefaultCollectionImplementationTest extends MapperTestBase {
|
|||||||
@IssueKey("6")
|
@IssueKey("6")
|
||||||
public void shouldUseDefaultImplementationForSet() {
|
public void shouldUseDefaultImplementationForSet() {
|
||||||
Source source = new Source();
|
Source source = new Source();
|
||||||
source.setFooSet( new HashSet<SourceFoo>( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) ) );
|
source.setFooSet( new HashSet<SourceFoo>( createSourceFooList() ) );
|
||||||
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
@ -63,7 +65,7 @@ public class DefaultCollectionImplementationTest extends MapperTestBase {
|
|||||||
@IssueKey("6")
|
@IssueKey("6")
|
||||||
public void shouldUseDefaultImplementationForCollection() {
|
public void shouldUseDefaultImplementationForCollection() {
|
||||||
Source source = new Source();
|
Source source = new Source();
|
||||||
source.setFooCollection( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) );
|
source.setFooCollection( createSourceFooList() );
|
||||||
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
@ -74,10 +76,49 @@ public class DefaultCollectionImplementationTest extends MapperTestBase {
|
|||||||
@IssueKey("6")
|
@IssueKey("6")
|
||||||
public void shouldUseDefaultImplementationForIterable() {
|
public void shouldUseDefaultImplementationForIterable() {
|
||||||
Source source = new Source();
|
Source source = new Source();
|
||||||
source.setFooIterable( Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) ) );
|
source.setFooIterable( createSourceFooList() );
|
||||||
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
assertThat( target.getFooIterable() ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
|
Iterable<TargetFoo> fooIterable = target.getFooIterable();
|
||||||
|
assertResultList( fooIterable );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertResultList(Iterable<TargetFoo> fooIterable) {
|
||||||
|
assertThat( fooIterable ).isNotNull();
|
||||||
|
assertThat( fooIterable ).containsOnly( new TargetFoo( "Bob" ), new TargetFoo( "Alice" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SourceFoo> createSourceFooList() {
|
||||||
|
return Arrays.asList( new SourceFoo( "Bob" ), new SourceFoo( "Alice" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void existingMapping1() {
|
||||||
|
List<TargetFoo> target = new ArrayList<TargetFoo>();
|
||||||
|
SourceTargetMapper.INSTANCE.sourceFoosToTargetFoos1( createSourceFooList(), target );
|
||||||
|
|
||||||
|
assertResultList( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void existingMapping2() {
|
||||||
|
List<TargetFoo> target = new ArrayList<TargetFoo>();
|
||||||
|
SourceTargetMapper.INSTANCE.sourceFoosToTargetFoos2( target, createSourceFooList() );
|
||||||
|
|
||||||
|
assertResultList( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void existingMapping3() {
|
||||||
|
List<TargetFoo> target = new ArrayList<TargetFoo>();
|
||||||
|
Iterable<TargetFoo> result =
|
||||||
|
SourceTargetMapper.INSTANCE.sourceFoosToTargetFoos3( createSourceFooList(), target );
|
||||||
|
|
||||||
|
assertThat( target == result ).isTrue();
|
||||||
|
assertResultList( target );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mappers;
|
import org.mapstruct.Mappers;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface SourceTargetMapper {
|
public interface SourceTargetMapper {
|
||||||
@ -41,4 +42,11 @@ public interface SourceTargetMapper {
|
|||||||
Collection<TargetFoo> sourceFoosToTargetFoos(Collection<SourceFoo> foos);
|
Collection<TargetFoo> sourceFoosToTargetFoos(Collection<SourceFoo> foos);
|
||||||
|
|
||||||
Iterable<TargetFoo> sourceFoosToTargetFoos(Iterable<SourceFoo> foos);
|
Iterable<TargetFoo> sourceFoosToTargetFoos(Iterable<SourceFoo> foos);
|
||||||
|
|
||||||
|
void sourceFoosToTargetFoos1(Iterable<SourceFoo> sourceFoos, List<TargetFoo> targetFoos);
|
||||||
|
|
||||||
|
void sourceFoosToTargetFoos2(@MappingTarget List<TargetFoo> targetFoos, Iterable<SourceFoo> sourceFoos);
|
||||||
|
|
||||||
|
Iterable<TargetFoo> sourceFoosToTargetFoos3(Iterable<SourceFoo> sourceFoos,
|
||||||
|
@MappingTarget List<TargetFoo> targetFoos);
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,55 @@ public class MapMappingTest extends MapperTestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldCreateReverseMapMethodImplementation() {
|
public void shouldCreateReverseMapMethodImplementation() {
|
||||||
Map<String, String> values = new HashMap<String, String>();
|
Map<String, String> values = createStringStringMap();
|
||||||
values.put( "42", "01.01.1980" );
|
|
||||||
values.put( "121", "20.07.2013" );
|
|
||||||
|
|
||||||
Map<Long, Date> target = SourceTargetMapper.INSTANCE.stringStringMapToLongDateMap( values );
|
Map<Long, Date> target = SourceTargetMapper.INSTANCE.stringStringMapToLongDateMap( values );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void shouldCreateReverseMapMethodImplementation1() {
|
||||||
|
Map<String, String> values = createStringStringMap();
|
||||||
|
|
||||||
|
Map<Long, Date> target = new HashMap<Long, Date>();
|
||||||
|
target.put( 66L, new GregorianCalendar( 2013, 7, 16 ).getTime() );
|
||||||
|
|
||||||
|
SourceTargetMapper.INSTANCE.stringStringMapToLongDateMap( values, target );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void shouldCreateReverseMapMethodImplementation2() {
|
||||||
|
Map<String, String> values = createStringStringMap();
|
||||||
|
|
||||||
|
Map<Long, Date> target = new HashMap<Long, Date>();
|
||||||
|
target.put( 66L, new GregorianCalendar( 2013, 7, 16 ).getTime() );
|
||||||
|
|
||||||
|
SourceTargetMapper.INSTANCE.stringStringMapToLongDateMap2( target, values );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void shouldCreateReverseMapMethodImplementation3() {
|
||||||
|
Map<String, String> values = createStringStringMap();
|
||||||
|
|
||||||
|
Map<Long, Date> target = new HashMap<Long, Date>();
|
||||||
|
target.put( 66L, new GregorianCalendar( 2013, 7, 16 ).getTime() );
|
||||||
|
|
||||||
|
Map<Long, Date> returnedTarget = SourceTargetMapper.INSTANCE.stringStringMapToLongDateMap3( values, target );
|
||||||
|
|
||||||
|
assertThat( target ).isSameAs( returnedTarget );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertResult(Map<Long, Date> target) {
|
||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
assertThat( target ).hasSize( 2 );
|
assertThat( target ).hasSize( 2 );
|
||||||
assertThat( target ).includes(
|
assertThat( target ).includes(
|
||||||
@ -72,6 +115,13 @@ public class MapMappingTest extends MapperTestBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> createStringStringMap() {
|
||||||
|
Map<String, String> values = new HashMap<String, String>();
|
||||||
|
values.put( "42", "01.01.1980" );
|
||||||
|
values.put( "121", "20.07.2013" );
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldInvokeMapMethodImplementationForMapTypedProperty() {
|
public void shouldInvokeMapMethodImplementationForMapTypedProperty() {
|
||||||
Map<Long, Date> values = new HashMap<Long, Date>();
|
Map<Long, Date> values = new HashMap<Long, Date>();
|
||||||
@ -94,9 +144,7 @@ public class MapMappingTest extends MapperTestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldInvokeReverseMapMethodImplementationForMapTypedProperty() {
|
public void shouldInvokeReverseMapMethodImplementationForMapTypedProperty() {
|
||||||
Map<String, String> values = new HashMap<String, String>();
|
Map<String, String> values = createStringStringMap();
|
||||||
values.put( "42", "01.01.1980" );
|
|
||||||
values.put( "121", "20.07.2013" );
|
|
||||||
|
|
||||||
Target target = new Target();
|
Target target = new Target();
|
||||||
target.setValues( values );
|
target.setValues( values );
|
||||||
|
@ -24,6 +24,7 @@ import java.util.Map;
|
|||||||
import org.mapstruct.MapMapping;
|
import org.mapstruct.MapMapping;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mappers;
|
import org.mapstruct.Mappers;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
|
||||||
@Mapper(uses = CustomNumberMapper.class)
|
@Mapper(uses = CustomNumberMapper.class)
|
||||||
public interface SourceTargetMapper {
|
public interface SourceTargetMapper {
|
||||||
@ -35,6 +36,15 @@ public interface SourceTargetMapper {
|
|||||||
|
|
||||||
Map<Long, Date> stringStringMapToLongDateMap(Map<String, String> source);
|
Map<Long, Date> stringStringMapToLongDateMap(Map<String, String> source);
|
||||||
|
|
||||||
|
@MapMapping(valueDateFormat = "dd.MM.yyyy")
|
||||||
|
void stringStringMapToLongDateMap(Map<String, String> source, Map<Long, Date> target);
|
||||||
|
|
||||||
|
@MapMapping(valueDateFormat = "dd.MM.yyyy")
|
||||||
|
void stringStringMapToLongDateMap2(@MappingTarget Map<Long, Date> target, Map<String, String> source);
|
||||||
|
|
||||||
|
@MapMapping(valueDateFormat = "dd.MM.yyyy")
|
||||||
|
Map<Long, Date> stringStringMapToLongDateMap3(Map<String, String> source, @MappingTarget Map<Long, Date> target);
|
||||||
|
|
||||||
Target sourceToTarget(Source source);
|
Target sourceToTarget(Source source);
|
||||||
|
|
||||||
Source targetToSource(Target target);
|
Source targetToSource(Target target);
|
||||||
|
@ -36,17 +36,61 @@ public class InheritanceTest extends MapperTestBase {
|
|||||||
@Test
|
@Test
|
||||||
@IssueKey("17")
|
@IssueKey("17")
|
||||||
public void shouldMapAttributeFromSuperType() {
|
public void shouldMapAttributeFromSuperType() {
|
||||||
SourceExt source = new SourceExt();
|
SourceExt source = createSource();
|
||||||
source.setFoo( 42 );
|
|
||||||
source.setBar( 23L );
|
|
||||||
|
|
||||||
TargetExt target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
TargetExt target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void existingMapping1() {
|
||||||
|
SourceExt source = createSource();
|
||||||
|
|
||||||
|
TargetExt target = new TargetExt();
|
||||||
|
SourceTargetMapper.INSTANCE.sourceToTarget1( source, target );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void existingMapping2() {
|
||||||
|
SourceExt source = createSource();
|
||||||
|
|
||||||
|
TargetExt target = new TargetExt();
|
||||||
|
SourceTargetMapper.INSTANCE.sourceToTarget2( target, source );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@IssueKey("19")
|
||||||
|
public void existingMapping3() {
|
||||||
|
SourceExt source = createSource();
|
||||||
|
|
||||||
|
TargetExt target = new TargetExt();
|
||||||
|
TargetBase result = SourceTargetMapper.INSTANCE.sourceToTarget3( source, target );
|
||||||
|
|
||||||
|
assertThat( target ).isSameAs( result );
|
||||||
|
|
||||||
|
assertResult( target );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertResult(TargetExt target) {
|
||||||
assertThat( target ).isNotNull();
|
assertThat( target ).isNotNull();
|
||||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
||||||
assertThat( target.getBar() ).isEqualTo( 23 );
|
assertThat( target.getBar() ).isEqualTo( 23 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SourceExt createSource() {
|
||||||
|
SourceExt source = new SourceExt();
|
||||||
|
source.setFoo( 42 );
|
||||||
|
source.setBar( 23L );
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@IssueKey("17")
|
@IssueKey("17")
|
||||||
public void shouldReverseMapAttributeFromSuperType() {
|
public void shouldReverseMapAttributeFromSuperType() {
|
||||||
|
@ -20,6 +20,7 @@ package org.mapstruct.ap.test.inheritance;
|
|||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mappers;
|
import org.mapstruct.Mappers;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface SourceTargetMapper {
|
public interface SourceTargetMapper {
|
||||||
@ -28,5 +29,11 @@ public interface SourceTargetMapper {
|
|||||||
|
|
||||||
TargetExt sourceToTarget(SourceExt source);
|
TargetExt sourceToTarget(SourceExt source);
|
||||||
|
|
||||||
|
void sourceToTarget1(SourceExt source, TargetExt target);
|
||||||
|
|
||||||
|
void sourceToTarget2(@MappingTarget TargetExt target, SourceExt source);
|
||||||
|
|
||||||
|
TargetBase sourceToTarget3(SourceExt source, @MappingTarget TargetExt target);
|
||||||
|
|
||||||
SourceExt targetToSource(TargetExt target);
|
SourceExt targetToSource(TargetExt target);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user