mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
When having multiple source properties and only target is defined then the same rules should be applied as if there was no mapping: * First we check for a matching property in any of the source type * Second we check if the parameter name matches
This commit is contained in:
parent
a5f49e591e
commit
53a5c34ed6
@ -1070,8 +1070,36 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
SourceReference sourceRef = mappingRef.getSourceReference();
|
||||
// sourceRef is not defined, check if a source property has the same name
|
||||
if ( sourceRef == null && method.getSourceParameters().size() == 1 ) {
|
||||
sourceRef = getSourceRefByTargetName( method.getSourceParameters().get( 0 ), targetPropertyName );
|
||||
if ( sourceRef == null ) {
|
||||
// Here we follow the same rules as when we implicitly map
|
||||
// When we implicitly map we first do property name based mapping
|
||||
// i.e. look for matching properties in the source types
|
||||
// and then do parameter name based mapping
|
||||
for ( Parameter sourceParameter : method.getSourceParameters() ) {
|
||||
SourceReference matchingSourceRef = getSourceRefByTargetName(
|
||||
sourceParameter,
|
||||
targetPropertyName
|
||||
);
|
||||
if ( matchingSourceRef != null ) {
|
||||
if ( sourceRef != null ) {
|
||||
errorOccured = true;
|
||||
// This can only happen when the target property matches multiple properties
|
||||
// within the different source parameters
|
||||
ctx.getMessager()
|
||||
.printMessage(
|
||||
method.getExecutable(),
|
||||
mappingRef.getMapping().getMirror(),
|
||||
Message.BEANMAPPING_SEVERAL_POSSIBLE_SOURCES,
|
||||
targetPropertyName
|
||||
);
|
||||
break;
|
||||
}
|
||||
// We can't break here since it is possible that the same property exists in multiple
|
||||
// source parameters
|
||||
sourceRef = matchingSourceRef;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( sourceRef == null ) {
|
||||
|
@ -15,11 +15,18 @@ public interface Issue2125Mapper {
|
||||
|
||||
Issue2125Mapper INSTANCE = Mappers.getMapper( Issue2125Mapper.class );
|
||||
|
||||
// In this case the issueId from the Comment is used
|
||||
Comment clone(Comment comment, Integer issueId);
|
||||
|
||||
// When source is not defined then we will use the issueId from the Comment,
|
||||
// same as when there was no mapping
|
||||
@Mapping(target = "issueId", qualifiedByName = "mapIssueNumber")
|
||||
Comment cloneWithQualifier(Comment comment, Integer issueId);
|
||||
|
||||
// When source is defined then we will source the parameter name
|
||||
@Mapping(target = "issueId", source = "issueId", qualifiedByName = "mapIssueNumber")
|
||||
Comment cloneWithQualifierExplicitSource(Comment comment, Integer issueId);
|
||||
|
||||
@Named("mapIssueNumber")
|
||||
default Integer mapIssueNumber(Integer issueNumber) {
|
||||
return issueNumber != null ? issueNumber + 1 : null;
|
||||
|
@ -43,6 +43,14 @@ public class Issue2125Test {
|
||||
1000
|
||||
);
|
||||
|
||||
assertThat( comment ).isNotNull();
|
||||
assertThat( comment.getIssueId() ).isEqualTo( 2126 );
|
||||
|
||||
comment = Issue2125Mapper.INSTANCE.cloneWithQualifierExplicitSource(
|
||||
new Comment( 2125, "Fix issue" ),
|
||||
1000
|
||||
);
|
||||
|
||||
assertThat( comment ).isNotNull();
|
||||
assertThat( comment.getIssueId() ).isEqualTo( 1001 );
|
||||
}
|
||||
@ -59,12 +67,6 @@ public class Issue2125Test {
|
||||
alternativeLine = 17, // For some reason javac reports the error on the method instead of the annotation
|
||||
message = "The type of parameter \"repository\" has no property named \"issueId\". Please define the " +
|
||||
"source property explicitly."),
|
||||
@Diagnostic(type = Issue2125ErroneousMapper.class,
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
line = 19,
|
||||
alternativeLine = 21, // For some reason javac reports the error on the method instead of the annotation
|
||||
message = "No property named \"issueId\" exists in source parameter(s). Please define the source " +
|
||||
"explicitly.")
|
||||
})
|
||||
public void shouldReportErrorWhenMultipleSourcesMatch() {
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.defaultvalue;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface CountryMapperMultipleSources {
|
||||
|
||||
CountryMapperMultipleSources INSTANCE = Mappers.getMapper( CountryMapperMultipleSources.class );
|
||||
|
||||
@Mapping(target = "code", defaultValue = "CH")
|
||||
@Mapping(target = "region", source = "regionCode")
|
||||
CountryDts map(CountryEntity entity, String regionCode);
|
||||
}
|
@ -159,4 +159,38 @@ public class DefaultValueTest {
|
||||
public void errorOnDefaultValueAndExpression() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey("2214")
|
||||
@WithClasses({
|
||||
CountryMapperMultipleSources.class,
|
||||
Region.class,
|
||||
})
|
||||
public void shouldBeAbleToDetermineDefaultValueBasedOnOnlyTargetType() {
|
||||
CountryEntity entity = new CountryEntity();
|
||||
CountryDts target = CountryMapperMultipleSources.INSTANCE.map( entity, "ZH" );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getCode() ).isEqualTo( "CH" );
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey("2220")
|
||||
@WithClasses({
|
||||
ErroneousMissingSourceMapper.class,
|
||||
Region.class,
|
||||
})
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(
|
||||
type = ErroneousMissingSourceMapper.class,
|
||||
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||
line = 17,
|
||||
message = "The type of parameter \"tenant\" has no property named \"type\"." +
|
||||
" Please define the source property explicitly."),
|
||||
}
|
||||
)
|
||||
public void errorWhenOnlyTargetDefinedAndSourceDoesNotHaveProperty() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.ap.test.defaultvalue;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper
|
||||
public interface ErroneousMissingSourceMapper {
|
||||
|
||||
@Mapping(target = "type", defaultValue = "STANDARD")
|
||||
Tenant map(TenantDto tenant);
|
||||
|
||||
class Tenant {
|
||||
|
||||
private final String id;
|
||||
private final String type;
|
||||
|
||||
public Tenant(String id, String type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
class TenantDto {
|
||||
|
||||
private final String id;
|
||||
|
||||
public TenantDto(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user