mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#87 Supporting iterable mapping methods where the target element type is the same as or a super-type of the source element type; Raising an error if iterable or map mapping methods can't be generated
This commit is contained in:
parent
22da3becab
commit
f9bfc4572e
@ -188,6 +188,8 @@ public class Type extends AbstractModelElement implements Comparable<Type> {
|
||||
*
|
||||
* @return {@code true} if and only if this type is assignable to the given other type.
|
||||
*/
|
||||
// TODO This doesn't yet take wild card types into account; e.g. ? extends Integer wouldn't be assignable to Number
|
||||
// atm.
|
||||
public boolean isAssignableTo(Type other) {
|
||||
if ( equals( other ) ) {
|
||||
return true;
|
||||
|
@ -27,6 +27,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
@ -490,9 +491,25 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
||||
)
|
||||
);
|
||||
|
||||
MappingMethodReference elementMappingMethod =
|
||||
getMappingMethodReference( methods, sourceElementType, targetElementType );
|
||||
|
||||
if ( !sourceElementType.isAssignableTo( targetElementType ) && conversion == null &&
|
||||
elementMappingMethod == null ) {
|
||||
messager.printMessage(
|
||||
Kind.ERROR,
|
||||
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.getExecutable()
|
||||
);
|
||||
}
|
||||
|
||||
return new IterableMappingMethod(
|
||||
method,
|
||||
getMappingMethodReference( methods, sourceElementType, targetElementType ),
|
||||
elementMappingMethod,
|
||||
conversion
|
||||
);
|
||||
}
|
||||
@ -524,6 +541,31 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Metho
|
||||
targetValueType
|
||||
);
|
||||
|
||||
if ( !sourceKeyType.isAssignableTo( targetKeyType ) && keyConversion == null && keyMappingMethod == null ) {
|
||||
messager.printMessage(
|
||||
Kind.ERROR,
|
||||
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.getExecutable()
|
||||
);
|
||||
}
|
||||
|
||||
if ( !sourceValueType.isAssignableTo( targetValueType ) && valueConversion == null &&
|
||||
valueMappingMethod == null ) {
|
||||
messager.printMessage(
|
||||
Kind.ERROR,
|
||||
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.getExecutable()
|
||||
);
|
||||
}
|
||||
|
||||
return new MapMappingMethod( method, keyMappingMethod, keyConversion, valueMappingMethod, valueConversion );
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ public <@includeModel object=returnType/> ${name}(<#list parameters as param><@i
|
||||
for ( <@includeModel object=sourceParameter.type.typeParameters[0]/> ${loopVariableName} : ${sourceParameter.name} ) {
|
||||
<#if elementMappingMethod??>
|
||||
${resultName}.add( <@includeModel object=elementMappingMethod input="${loopVariableName}"/> );
|
||||
<#else>
|
||||
<#elseif conversion??>
|
||||
<#if (conversion.exceptionTypes?size == 0) >
|
||||
${resultName}.add( <@includeModel object=conversion/> );
|
||||
<#else>
|
||||
@ -47,6 +47,8 @@ public <@includeModel object=returnType/> ${name}(<#list parameters as param><@i
|
||||
}
|
||||
</#list>
|
||||
</#if>
|
||||
<#else>
|
||||
${resultName}.add( ${loopVariableName} );
|
||||
</#if>
|
||||
}
|
||||
<#if returnType.name != "void">
|
||||
|
@ -24,6 +24,7 @@ import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.MapperTestBase;
|
||||
@ -287,4 +288,14 @@ public class CollectionMappingTest extends MapperTestBase {
|
||||
|
||||
assertThat( source.getStringLongMap() ).hasSize( 2 );
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey("87")
|
||||
public void shouldMapIntegerSetToNumberSet() {
|
||||
Set<Number> numbers = SourceTargetMapper.INSTANCE
|
||||
.integerSetToNumberSet( new HashSet<Integer>( Arrays.asList( 123, 456 ) ) );
|
||||
|
||||
assertThat( numbers ).isNotNull();
|
||||
assertThat( numbers ).containsOnly( 123, 456 );
|
||||
}
|
||||
}
|
||||
|
@ -46,4 +46,6 @@ public interface SourceTargetMapper {
|
||||
Set<String> colourSetToStringSet(Set<Colour> colours);
|
||||
|
||||
Set<Colour> stringSetToColourSet(Set<String> colours);
|
||||
|
||||
Set<Number> integerSetToNumberSet(Set<Integer> integers);
|
||||
}
|
||||
|
@ -147,4 +147,19 @@ public class MapMappingTest extends MapperTestBase {
|
||||
entry( 121L, new GregorianCalendar( 2013, 6, 20 ).getTime() )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey("87")
|
||||
public void shouldCreateMapMethodImplementationWithoutConversionOrElementMappingMethod() {
|
||||
Map<String, String> values = createStringStringMap();
|
||||
|
||||
Map<Object, Object> target = SourceTargetMapper.INSTANCE.stringStringMapToObjectObjectMap( values );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target ).hasSize( 2 );
|
||||
assertThat( target ).includes(
|
||||
entry( "42", "01.01.1980" ),
|
||||
entry( "121", "20.07.2013" )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -47,4 +47,6 @@ public interface SourceTargetMapper {
|
||||
Target sourceToTarget(Source source);
|
||||
|
||||
Source targetToSource(Target target);
|
||||
|
||||
Map<Object, Object> stringStringMapToObjectObjectMap(Map<String, String> source);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user