Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public static class Builder extends AbstractMappingMethodBuilder<Builder, BeanMa
private Map<String, Accessor> unprocessedTargetProperties;
private Map<String, Accessor> unprocessedSourceProperties;
private Set<String> missingIgnoredSourceProperties;
private Set<String> redundantIgnoredSourceProperties;
private Set<String> targetProperties;
private final List<PropertyMapping> propertyMappings = new ArrayList<>();
private final Set<Parameter> unprocessedSourceParameters = new HashSet<>();
Expand Down Expand Up @@ -278,11 +279,23 @@ else if ( !method.isUpdateMethod() ) {

// get bean mapping (when specified as annotation )
this.missingIgnoredSourceProperties = new HashSet<>();
if ( beanMapping != null ) {
this.redundantIgnoredSourceProperties = new HashSet<>();
if ( beanMapping != null && !beanMapping.getIgnoreUnmappedSourceProperties().isEmpty() ) {
// Get source properties explicitly mapped using @Mapping annotations
Set<String> mappedSourceProperties = method.getOptions().getMappings().stream()
.map( MappingOptions::getSourceName )
.filter( Objects::nonNull )
.collect( Collectors.toSet() );

for ( String ignoreUnmapped : beanMapping.getIgnoreUnmappedSourceProperties() ) {
// Track missing ignored properties (i.e. not in source class)
if ( unprocessedSourceProperties.remove( ignoreUnmapped ) == null ) {
missingIgnoredSourceProperties.add( ignoreUnmapped );
}
// Track redundant ignored properties (actually mapped despite being ignored)
if ( mappedSourceProperties.contains( ignoreUnmapped ) ) {
redundantIgnoredSourceProperties.add( ignoreUnmapped );
}
}
}

Expand Down Expand Up @@ -331,6 +344,7 @@ else if ( !method.isUpdateMethod() ) {
}
reportErrorForMissingIgnoredSourceProperties();
reportErrorForUnusedSourceParameters();
reportErrorForRedundantIgnoredSourceProperties();

// mapNullToDefault
boolean mapNullToDefault = method.getOptions()
Expand Down Expand Up @@ -1898,6 +1912,34 @@ private void reportErrorForMissingIgnoredSourceProperties() {
}
}

private void reportErrorForRedundantIgnoredSourceProperties() {
if ( !redundantIgnoredSourceProperties.isEmpty() ) {
ReportingPolicyGem unmappedSourcePolicy = getUnmappedSourcePolicy();
if ( unmappedSourcePolicy == ReportingPolicyGem.IGNORE ) { //don't show warning
return;
}

Message message = Message.BEANMAPPING_REDUNDANT_IGNORED_SOURCES_WARNING;
if ( unmappedSourcePolicy.getDiagnosticKind() == Diagnostic.Kind.ERROR ) {
message = Message.BEANMAPPING_REDUNDANT_IGNORED_SOURCES_ERROR;
}

Object[] args = new Object[] {
MessageFormat.format(
"{0,choice,1#property|1<properties} \"{1}\" {0,choice,1#is|1<are}",
redundantIgnoredSourceProperties.size(),
Strings.join( redundantIgnoredSourceProperties, ", " )
)
};

ctx.getMessager().printMessage(
method.getExecutable(),
message,
args
);
}
}

private void reportErrorForUnusedSourceParameters() {
for ( Parameter sourceParameter : unprocessedSourceParameters ) {
Type parameterType = sourceParameter.getType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public enum Message {
BEANMAPPING_UNMAPPED_FORGED_SOURCES_WARNING( "Unmapped source %s. Mapping from %s to %s.", Diagnostic.Kind.WARNING ),
BEANMAPPING_UNMAPPED_FORGED_SOURCES_ERROR( "Unmapped source %s. Mapping from %s to %s." ),
BEANMAPPING_MISSING_IGNORED_SOURCES_ERROR( "Ignored unknown source %s." ),
BEANMAPPING_REDUNDANT_IGNORED_SOURCES_ERROR( "Source %s mapped despite being listed in ignoreUnmappedSourceProperties." ),
BEANMAPPING_REDUNDANT_IGNORED_SOURCES_WARNING( "Source %s mapped despite being listed in ignoreUnmappedSourceProperties.", Diagnostic.Kind.WARNING ),
BEANMAPPING_CYCLE_BETWEEN_PROPERTIES( "Cycle(s) between properties given via dependsOn(): %s." ),
BEANMAPPING_UNKNOWN_PROPERTY_IN_DEPENDS_ON( "\"%s\" is no property of the method return type." ),
BEANMAPPING_IGNORE_BY_DEFAULT_WITH_MAPPING_TARGET_THIS( "Using @BeanMapping( ignoreByDefault = true ) with @Mapping( target = \".\", ... ) is not allowed. You'll need to explicitly ignore the target properties that should be ignored instead." ),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* 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.ignoreunmapped;

import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapper;
import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapperWithWarnSourcePolicy;
import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapperWithWarnPolicyInMapperConfig;
import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapperWithWarnSourcePolicyInMapper;
import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapperWithoutBeanMapping;
import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapperWithIgnorePolicyInMapperConfig;
import org.mapstruct.ap.test.ignoreunmapped.mapper.UserMapperWithIgnoreSourcePolicy;
import org.mapstruct.ap.test.ignoreunmapped.mapper.erroneous.UserMapperWithErrorPolicyInMapperConfig;
import org.mapstruct.ap.test.ignoreunmapped.mapper.erroneous.UserMapperWithErrorSourcePolicy;
import org.mapstruct.ap.test.ignoreunmapped.mapper.erroneous.UserMapperWithErrorSourcePolicyInMapper;
import org.mapstruct.ap.test.ignoreunmapped.mapper.erroneous.UserMapperWithMultiMapping;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;

import javax.tools.Diagnostic.Kind;

/**
* Verifies that mapped properties listed in ignoreUnmappedSourceProperties trigger a warning.
*
* @author Ritesh Chopade(codeswithritesh)
*/
@IssueKey("3837")
@WithClasses({UserEntity.class, UserDto.class})
public class IgnoredMappedPropertyTest {

@ProcessorTest
@WithClasses({
UserMapper.class,
UserMapperWithIgnoreSourcePolicy.class,
UserMapperWithoutBeanMapping.class,
UserMapperWithIgnorePolicyInMapperConfig.class
})
@ExpectedCompilationOutcome(
value = CompilationResult.SUCCEEDED
)
public void shouldNotWarnAboutRedundantIgnore() {
}

@ProcessorTest
@WithClasses({
UserMapperWithErrorSourcePolicy.class,
UserMapperWithErrorSourcePolicyInMapper.class,
UserMapperWithErrorPolicyInMapperConfig.class
})
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(
type = UserMapperWithErrorSourcePolicy.class,
kind = Kind.ERROR,
line = 20,
message = "Source property \"email\" is mapped despite being " +
"listed in ignoreUnmappedSourceProperties."
),
@Diagnostic(
type = UserMapperWithErrorSourcePolicyInMapper.class,
kind = Kind.ERROR,
line = 19,
message = "Source property \"email\" is mapped despite being " +
"listed in ignoreUnmappedSourceProperties."
),
@Diagnostic(
type = UserMapperWithErrorPolicyInMapperConfig.class,
kind = Kind.ERROR,
line = 23,
message = "Source property \"email\" is mapped despite being " +
"listed in ignoreUnmappedSourceProperties."
)
}
)
public void shouldWarnAboutRedundantIgnoreWithErrorPolicy() {
}

@ProcessorTest
@WithClasses({
UserMapperWithWarnSourcePolicy.class,
UserMapperWithWarnSourcePolicyInMapper.class,
UserMapperWithWarnPolicyInMapperConfig.class
})
@ExpectedCompilationOutcome(
value = CompilationResult.SUCCEEDED,
diagnostics = {
@Diagnostic(
type = UserMapperWithWarnSourcePolicy.class,
kind = Kind.WARNING,
line = 20,
message = "Source property \"email\" is mapped despite being " +
"listed in ignoreUnmappedSourceProperties."
),
@Diagnostic(
type = UserMapperWithWarnSourcePolicyInMapper.class,
kind = Kind.WARNING,
line = 19,
message = "Source property \"email\" is mapped despite being " +
"listed in ignoreUnmappedSourceProperties."
),
@Diagnostic(
type = UserMapperWithWarnPolicyInMapperConfig.class,
kind = Kind.WARNING,
line = 23,
message = "Source property \"email\" is mapped despite being " +
"listed in ignoreUnmappedSourceProperties."
)
}
)
public void shouldWarnAboutRedundantIgnoreWithWarnPolicy() {
}

@ProcessorTest
@WithClasses({UserMapperWithMultiMapping.class})
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(
type = UserMapperWithMultiMapping.class,
kind = Kind.ERROR,
line = 21,
message = "Source properties \"email, username\" are mapped despite " +
"being listed in ignoreUnmappedSourceProperties."
)
}
)
public void shouldWarnAboutRedundantIgnoreWithMultiMapping() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.ignoreunmapped;

/**
* @author Ritesh Chopade(codeswithritesh)
*/
public class UserDto {

private String username;
private String email;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.ignoreunmapped;

/**
* @author Ritesh Chopade(codeswithritesh)
*/
public class UserEntity {

private String username;
private String email;
private String password;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* 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.ignoreunmapped.mapper;

import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ap.test.ignoreunmapped.UserDto;
import org.mapstruct.ap.test.ignoreunmapped.UserEntity;

@Mapper
public interface UserMapper {
@BeanMapping(ignoreUnmappedSourceProperties = {"password", "email"})
@Mapping(source = "email", target = "email")
UserDto map(UserEntity user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.ignoreunmapped.mapper;

import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MapperConfig;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.ap.test.ignoreunmapped.UserDto;
import org.mapstruct.ap.test.ignoreunmapped.UserEntity;

@MapperConfig(unmappedSourcePolicy = ReportingPolicy.IGNORE)
interface IgnorePolicyConfig { }

@Mapper(config = IgnorePolicyConfig.class)
public interface UserMapperWithIgnorePolicyInMapperConfig {
@BeanMapping(ignoreUnmappedSourceProperties = {"password", "email"})
@Mapping(source = "email", target = "email")
UserDto map(UserEntity user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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.ignoreunmapped.mapper;

import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.ap.test.ignoreunmapped.UserDto;
import org.mapstruct.ap.test.ignoreunmapped.UserEntity;

@Mapper
public interface UserMapperWithIgnoreSourcePolicy {

@BeanMapping(ignoreUnmappedSourceProperties = {"password", "email"}, unmappedSourcePolicy = ReportingPolicy.IGNORE)
@Mapping(source = "email", target = "email")
UserDto map(UserEntity user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.ignoreunmapped.mapper;

import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MapperConfig;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.ap.test.ignoreunmapped.UserDto;
import org.mapstruct.ap.test.ignoreunmapped.UserEntity;

@MapperConfig(unmappedSourcePolicy = ReportingPolicy.WARN)
interface WarnPolicyConfig { }

@Mapper(config = WarnPolicyConfig.class)
public interface UserMapperWithWarnPolicyInMapperConfig {
@BeanMapping(ignoreUnmappedSourceProperties = {"password", "email"})
@Mapping(source = "email", target = "email")
UserDto map(UserEntity user);
}
Loading