How to instruct Mapstruct to use lombok builder?
Asked Answered
D

3

12

MapStruct is unable to create an implementation when I'm trying to map object with a private default constructor, but with a (lombok generated) builder.

SomeMapperImpl.java:[20,27] SomeDto() is not public in com.example.mapstructdemo.dto.SomeDto; cannot be accessed from outside package

Dto:

@Value
@Builder
public class SomeDto {
}

Model:

@Value
@Builder
public class SomeModel {
}

Mapper interface:

@Mapper
public interface SomeMapper {
    SomeDto map(SomeModel someModel);
    SomeModel map(SomeDto someDto);
}

fragment from Pom.xml:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${compiler-plugin.version}</version>
        <configuration>
            <annotationProcessorPaths>
                <path>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <version>1.18.16</version>
                </path>
                <path>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok-mapstruct-binding</artifactId>
                    <version>0.2.0</version>
                </path>
                <path>
                    <groupId>org.mapstruct</groupId>
                    <artifactId>mapstruct-processor</artifactId>
                    <version>1.4.1.Final</version>
                </path>
            </annotationProcessorPaths>
        </configuration>
    </plugin>

The generated implementation:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-01-29T13:47:46+0100",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 11.0.9.1 (Ubuntu)"
)
public class SomeMapperImpl implements SomeMapper {

    @Override
    public SomeDto map(SomeModel someModel) {
        if ( someModel == null ) {
            return null;
        }

        SomeDto someDto = new SomeDto();

        return someDto;
    }

    @Override
    public SomeModel map(SomeDto someDto) {
        if ( someDto == null ) {
            return null;
        }

        SomeModel someModel = new SomeModel();

        return someModel;
    }
}

What can I do to help mapstruct find the builder?

To reproduce the problem, clone this repo https://github.com/rmvanderspek/mapstruct-demo and mvn verify.

Dustindustman answered 29/1, 2021 at 13:1 Comment(2)
Try to lower the version of lombok-mapstruct-binding to 0.1.0.Unction
Downgrading 'lombok-mapstruct-binding' to '0.1.0' did not have any (noticeable) effect.Dustindustman
T
19

I've played around with your demo sources, and it turns out that placing Mapstruct first in the compiler plugin sources fixes the issue. I don't know why this works, it feels counterintuitive to me, but this is what one of the developers of Mapstruct suggested in a similar issue posted on Lombok's Github.

So in your case:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${compiler-plugin.version}</version>
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>${org.mapstruct.mapstruct-processor.version}</version>
            </path>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${org.projectlombok.lombok.version}</version>
            </path>
            <path>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok-mapstruct-binding</artifactId>
                <version>${org.projectlombok.ombok-mapstruct-binding.version}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>
    
Totally answered 29/1, 2021 at 13:33 Comment(5)
Thanks a lot Jeroen. It's so weird that this is the solution, but I'm thankful for it either way ;-).Dustindustman
I could reproduce and this fixes the error. +1Unction
this is the correct answer according to the mapstruct documentation : mapstruct.org/documentation/stable/reference/html/#_set_upPallmall
Oh my. I just turn them the other way because I had problem with mapstruct not recognizing some field.Sigismond
If you already have "lombok-mapstruct-binding", "mapstruct" and "lombok" can be in any order.Hairdresser
S
1

I put the lombok artifact below the mapstruct and mapstruct-processor artifact in the dependencies and it started working.

    <dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${mapstruct.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok-mapstruct-binding</artifactId>
            <version>${lombok-mapstruct-binding.version}</version>
        </dependency>
    </dependencies>
Servomotor answered 22/4, 2021 at 10:57 Comment(0)
D
1

I've spent a couple of hours figuring this out:

Just in case you are not using Lombok @Builder to set up the builder pattern for your object.

Make sure your builder method is public and static:

 public static SectionBuilder builder() {
        return new SectionBuilder();
 } 
Dirt answered 20/12, 2022 at 19:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.