Skip to content

Rework the implementation of nested target mappings #2941

@filiphr

Description

@filiphr

The current implementation of nested target mappings is a bit complex, especially when we start having inbalanced source parameters.

Ideally the implementation can work by passing the multiple source parameters as soon as an inbalance is detected.

e.g. currently for

@Mapper
public interface ChartEntryMapper {

    ChartEntryMapper MAPPER = Mappers.getMapper( ChartEntryMapper.class );

    @Mapping(target = "type", ignore = true)
    @Mapping(target = "name", source = "chartEntry2.chartName")
    @Mapping(target = "song.title", source = "chartEntry1.songTitle" )
    @Mapping(target = "song.artist.name", source = "chartEntry1.artistName" )
    @Mapping(target = "song.artist.label.studio.name", source = "chartEntry1.recordeAt")
    @Mapping(target = "song.artist.label.studio.city", source = "chartEntry1.city" )
    @Mapping(target = "song.positions", source = "chartEntry2.position" )
    Chart map(ChartEntry chartEntry1, ChartEntry chartEntry2);

    default List<Integer> mapPosition(Integer in) {
        if ( in != null ) {
            return new ArrayList<>( Arrays.asList( in ) );
        }
        else {
            return new ArrayList<>();
        }
    }
}

we generate

public class ChartEntryMapperImpl implements ChartEntryMapper {

    @Override
    public Chart map(ChartEntry chartEntry1, ChartEntry chartEntry2) {
        if ( chartEntry1 == null && chartEntry2 == null ) {
            return null;
        }

        Chart chart = new Chart();

        if ( chartEntry1 != null ) {
            if ( chart.getSong() == null ) {
                chart.setSong( new Song() );
            }
            chartEntryToSong1( chartEntry1, chart.getSong() );
        }
        if ( chartEntry2 != null ) {
            if ( chart.getSong() == null ) {
                chart.setSong( new Song() );
            }
            chartEntryToSong2( chartEntry2, chart.getSong() );
            chart.setName( chartEntry2.getChartName() );
        }

        return chart;
    }

    protected void chartEntryToStudio1(ChartEntry chartEntry, Studio mappingTarget) {
        if ( chartEntry == null ) {
            return;
        }

        mappingTarget.setName( chartEntry.getRecordedAt() );
        mappingTarget.setCity( chartEntry.getCity() );
    }

    protected void chartEntryToLabel1(ChartEntry chartEntry, Label mappingTarget) {
        if ( chartEntry == null ) {
            return;
        }

        if ( mappingTarget.getStudio() == null ) {
            mappingTarget.setStudio( new Studio() );
        }
        chartEntryToStudio1( chartEntry, mappingTarget.getStudio() );
    }

    protected void chartEntryToArtist1(ChartEntry chartEntry, Artist mappingTarget) {
        if ( chartEntry == null ) {
            return;
        }

        if ( mappingTarget.getLabel() == null ) {
            mappingTarget.setLabel( new Label() );
        }
        chartEntryToLabel1( chartEntry, mappingTarget.getLabel() );
        mappingTarget.setName( chartEntry.getArtistName() );
    }

    protected void chartEntryToSong1(ChartEntry chartEntry, Song mappingTarget) {
        if ( chartEntry == null ) {
            return;
        }

        if ( mappingTarget.getArtist() == null ) {
            mappingTarget.setArtist( new Artist() );
        }
        chartEntryToArtist1( chartEntry, mappingTarget.getArtist() );
        mappingTarget.setTitle( chartEntry.getSongTitle() );
    }

    protected void chartEntryToSong2(ChartEntry chartEntry, Song mappingTarget) {
        if ( chartEntry == null ) {
            return;
        }

        if ( mappingTarget.getPositions() != null ) {
            List<Integer> list = mapPosition( chartEntry.getPosition() );
            if ( list != null ) {
                mappingTarget.getPositions().clear();
                mappingTarget.getPositions().addAll( list );
            }
            else {
                mappingTarget.setPositions( null );
            }
        }
        else {
            List<Integer> list = mapPosition( chartEntry.getPosition() );
            if ( list != null ) {
                mappingTarget.setPositions( list );
            }
        }
    }

}

Ideally this would look like:

public class ChartEntryMapperImpl implements ChartEntryMapper {

    @Override
    public Chart map(ChartEntry chartEntry1, ChartEntry chartEntry2) {
        if ( chartEntry1 == null && chartEntry2 == null ) {
            return null;
        }

        Chart chart = new Chart();

        chart.setSong( toSong( chartEntry1, chartEntry2 ) );

        if ( chartEntry2 != null ) {
            chart.setName( chartEntry2.getChartName() );
        }

        return chart;
    }

    protected Song toSong(ChartEntry chartEntry1, ChartEntry chartEntry2) {
        if ( chartEntry1 == null && chartEntry2 == null ) {
            return null;
        }

        Song song = new Song();

        if ( chartEntry1 != null ) {
            song.setArtist( toArtist( chartEntry1 ) );
            song.setTitle( chartEntry1.getSongTitle() );
            
        }

        if ( chartEntry2 != null ) {
            
            List<Integer> list = mapPosition( chartEntry2.getPosition() );
            if ( list != null ) {
                song.setPositions( list );
            }
            
        }

        return song;
    }

    protected Artist toArtist(ChartEntry chartEntry) {
        if ( chartEntry == null ) {
            return null;
        }

        Artist artist = new Artist();
        artist.setName( chartEntry.getArtistName() );
        artist.setLabel( toLabel( chartEntry ) );

        return artist;
    }

    protected Label toLabel(ChartEntry chartEntry) {
        if ( chartEntry == null ) {
            return null;
        }

        Label label = new Label();
        label.setStudio( toStudio( chartEntry ) );

        return label;
    }

    protected Studio toStudio(ChartEntry chartEntry) {
        if ( chartEntry == null ) {
            return null;
        }

        Studio studio = new Studio();
        
        studio.setName( chartEntry.getRecordedAt() );
        studio.setCity( chartEntry.getCity() );

        return studio;
    }

}

The proposed code is more readable and more understandable from the currently generated code. I also believe (haven't tried it yet) that the implementation would be simple as well.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions