Skip to content

BeanMapping ignoreByDefault not propagated to generated sub methods (1.5.5.Final) #3316

@neumannm

Description

@neumannm

Expected behavior

import javax.annotation.processing.Generated;
import org.springframework.stereotype.Component;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2023-06-27T13:15:05+0200",
    comments = "version: 1.5.5.Final, compiler: javac, environment: Java 17.0.7 (Eclipse Adoptium)"
)
@Component
public class MapstructTestImpl implements MapstructTest {

    @Override
    public void processDataToProcessData(Processdata source, Processdata target) {
        if ( source == null ) {
            return;
        }

        if ( source.getProcessdates() != null ) {
            if ( target.getProcessdates() == null ) {
                target.setProcessdates( new Processdates() );
            }
            processdatesToProcessdates( source.getProcessdates(), target.getProcessdates() );
        }
        if ( source.getFoo() != null ) {
            target.setFoo( source.getFoo() );
        }
    }

    protected void processdatesToProcessdates(Processdates processdates, Processdates mappingTarget) {
        if ( processdates == null ) {
            return;
        }

        if ( processdates.getBegin() != null ) {
            mappingTarget.setBegin( processdates.getBegin() );
        }
        if ( processdates.getEnd() != null ) {
            mappingTarget.setEnd( processdates.getEnd() );
        }
    }
}

Actual behavior

import javax.annotation.processing.Generated;
import org.springframework.stereotype.Component;

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2023-06-27T13:15:05+0200",
    comments = "version: 1.5.5.Final, compiler: javac, environment: Java 17.0.7 (Eclipse Adoptium)"
)
@Component
public class MapstructTestImpl implements MapstructTest {

    @Override
    public void processDataToProcessData(Processdata source, Processdata target) {
        if ( source == null ) {
            return;
        }

        if ( source.getProcessdates() != null ) {
            if ( target.getProcessdates() == null ) {
                target.setProcessdates( new Processdates() );
            }
            processdatesToProcessdates( source.getProcessdates(), target.getProcessdates() );
        }
        if ( source.getFoo() != null ) {
            target.setFoo( source.getFoo() );
        }
    }

    protected void processdatesToProcessdates(Processdates processdates, Processdates mappingTarget) {
        if ( processdates == null ) {
            return;
        }

        if ( processdates.getBegin() != null ) {
            mappingTarget.setBegin( processdates.getBegin() );
        }
        if ( processdates.getEnd() != null ) {
            mappingTarget.setEnd( processdates.getEnd() );
        }
        if ( processdates.getSomeOtherDate() != null ) {
            mappingTarget.setSomeOtherDate( processdates.getSomeOtherDate() );
        }
    }
}

Steps to reproduce the problem

I want to utilize @BeanMapping(ignoreByDefault = true) to be able to update only the fields explicitly defined via Mapping.

import org.mapstruct.BeanMapping;
import org.mapstruct.Builder;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;

@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = true))
public interface MapstructTest {

	@BeanMapping(ignoreByDefault = true, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
	@Mapping(target = "foo", source = "foo")
	@Mapping(target = "processdates.begin", source = "processdates.begin")
	@Mapping(target = "processdates.end", source = "processdates.end")
	void processDataToProcessData(Processdata source, @MappingTarget Processdata target);
}

This does not seem to be propagated to sub-methods. For example, I want to define that of the field processdates in ProcessData, only the two fields begin and end are mapped to the target, but not someOtherDate. But Mapstruct seems to only apply the annotation to the highest level of the object hierarchy.

The only way I get it to work is when I explicitly define a second mapping method for the Processdates object like this:

import org.mapstruct.BeanMapping;
import org.mapstruct.Builder;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;

@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = true))
public interface MapstructTest {

	@BeanMapping(ignoreByDefault = true, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
	@Mapping(target = "foo", source = "foo")
	@Mapping(target = "processdates", source = "processdates")
	void processDataToProcessData(Processdata source, @MappingTarget Processdata target);

	@BeanMapping(ignoreByDefault = true, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
	@Mapping(target = "begin", source = "begin")
	@Mapping(target = "end", source = "end")
	void processDatesToProcessDates(Processdates source, @MappingTarget Processdates target);
}

But this is not very elegant.

Is it a bug or a feature?

MapStruct Version

1.5.5.Final

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions