Robert van der Spek
Robert van der Spek

Reputation: 1227

How to instruct Mapstruct to use lombok builder?

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.

Upvotes: 13

Views: 25357

Answers (3)

Philippe Simo
Philippe Simo

Reputation: 1469

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();
 } 

Upvotes: 1

Swoot
Swoot

Reputation: 1382

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>

Upvotes: 1

Jeroen Steenbeeke
Jeroen Steenbeeke

Reputation: 4048

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>
    

Upvotes: 19

Related Questions