Skip to content

Multi-module Project, Record, Interface Behaviour #3661

@hk-2keys

Description

@hk-2keys

Expected behavior

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2024-08-12T10:53:53-0400",
    comments = "version: 1.5.5.Final, compiler: javac, environment: Java 21.0.4 (Ubuntu)"
)
class RecordInterfaceIssueMapperImpl implements RecordInterfaceIssueMapper {

    @Override
    public TargetRootRecord map(SourceRootRecord source) {
        if ( source == null ) {
            return null;
        }

        TargetNestedRecord nested = null;

        nested = sourceNestedRecordToTargetNestedRecord( source.nested() );

        TargetRootRecord targetRootRecord = new TargetRootRecord( nested );

        return targetRootRecord;
    }

    @Override
    public SourceRootRecord map(TargetRootRecord target) {
        if ( target == null ) {
            return null;
        }

        SourceNestedRecord nested = null;

        nested = targetNestedRecordToSourceNestedRecord( target.nested() );

        SourceRootRecord sourceRootRecord = new SourceRootRecord( nested );

        return sourceRootRecord;
    }

    protected TargetNestedRecord sourceNestedRecordToTargetNestedRecord(SourceNestedRecord sourceNestedRecord) {
        if ( sourceNestedRecord == null ) {
            return null;
        }

        String field = null;

        field = sourceNestedRecord.field();

        TargetNestedRecord targetNestedRecord = new TargetNestedRecord( field );

        return targetNestedRecord;
    }

    protected SourceNestedRecord targetNestedRecordToSourceNestedRecord(TargetNestedRecord targetNestedRecord) {
        if ( targetNestedRecord == null ) {
            return null;
        }

        String field = null;

        field = targetNestedRecord.field();

        SourceNestedRecord sourceNestedRecord = new SourceNestedRecord( field );

        return sourceNestedRecord;
    }
}

Actual behavior

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2024-08-12T10:55:11-0400",
    comments = "version: 1.5.5.Final, compiler: javac, environment: Java 21.0.4 (Ubuntu)"
)
class RecordInterfaceIssueMapperImpl implements RecordInterfaceIssueMapper {

    @Override
    public TargetRootRecord map(SourceRootRecord source) {
        if ( source == null ) {
            return null;
        }

        TargetNestedRecord nested = null;

        nested = nestedInterfaceToTargetNestedRecord( source.nested() );

        TargetRootRecord targetRootRecord = new TargetRootRecord( nested );

        return targetRootRecord;
    }

    @Override
    public SourceRootRecord map(TargetRootRecord target) {
        if ( target == null ) {
            return null;
        }

        SourceNestedRecord nested = null;

        nested = targetNestedRecordToSourceNestedRecord( target.nested() );

        SourceRootRecord sourceRootRecord = new SourceRootRecord( nested );

        return sourceRootRecord;
    }

    protected TargetNestedRecord nestedInterfaceToTargetNestedRecord(NestedInterface nestedInterface) {
        if ( nestedInterface == null ) {
            return null;
        }

        String field = null;

        TargetNestedRecord targetNestedRecord = new TargetNestedRecord( field );

        return targetNestedRecord;
    }

    protected SourceNestedRecord targetNestedRecordToSourceNestedRecord(TargetNestedRecord targetNestedRecord) {
        if ( targetNestedRecord == null ) {
            return null;
        }

        String field = null;

        field = targetNestedRecord.field();

        SourceNestedRecord sourceNestedRecord = new SourceNestedRecord( field );

        return sourceNestedRecord;
    }
}

Steps to reproduce the problem

This occurs when the following 3 things are combined:

  1. Source and Target types are in difference modules (e.g. a multi-module Maven project)
  2. Records are used for the Source and Target types
  3. The Source records implement interfaces

Example

Module 1

interface RootInterface {
    NestedInterface nested();
}

interface NestedInterface {
    String field();
}

record SourceRootRecord(
        SourceNestedRecord nested
) implements RootInterface { }

record SourceNestedRecord(
        String field
) implements NestedInterface { }

Module 2 (depends on Module 1)

@Mapper
interface RecordInterfaceIssueMapper {

    TargetRootRecord map(SourceRootRecord source);

    SourceRootRecord map(TargetRootRecord target);
}

record TargetRootRecord(
        TargetNestedRecord nested
) { }

record TargetNestedRecord(
        String field
) { }

Test

class RecordInterfaceIssueTest {

    RecordInterfaceIssueMapper mapper;
    SourceRootRecord source;
    TargetRootRecord target;

    @BeforeEach
    void setUp() {
        mapper = Mappers.getMapper(RecordInterfaceIssueMapper.class);
        source = new SourceRootRecord(new SourceNestedRecord("field"));
        target = new TargetRootRecord(new TargetNestedRecord("field"));
    }

    @Test
    void testMap_Source() {
        // This fails
        assertThat(mapper.map(source)).isEqualTo(target);
    }

    @Test
    void testMap_Target() {
        // This succeeds
        assertThat(mapper.map(target)).isEqualTo(source);
    }
}

MapStruct Version

1.5.5.Final

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions