Mapstruct 1.2.0 not generating mapper class in springboot 2.0.0.M3 + lombok

19k views Asked by At

I'm trying to put together a sample project combining the following technologies:

  • Spring boot (2.0.0.M3)
  • Mapstruct (1.2.0.CR1)
  • Lombok (1.16.18)

I have defined this mapper:

@Mapper(componentModel = "spring")
public interface SourceToTargetMapper {

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

    @Mappings({ 
        @Mapping(source = "characteristics", target = "description"),
        @Mapping(source = "identifier", target = "id") 
    })
    public Target toTarget(Source source);
}

The problem I am having is that the class implementing the SourceToTargetMapper interface is not being generated.

That 's the trace I'm getting when i run the unit test:

2017-09-04 00:13:24.726 ERROR 1712 --- [           main] o.s.test.context.TestContextManager      : Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@568bf312] to prepare test instance [io.alfredux.demo.MapperTest@5ccbeb64]

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'io.alfredux.demo.MapperTest': Unsatisfied dependency expressed through field 'sourceToTargetMapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.alfredux.demo.mapper.SourceToTargetMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:570) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:356) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:399) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) ~[spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44) ~[spring-boot-test-autoconfigure-2.0.0.M3.jar:2.0.0.M3]
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:242) ~[spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) [spring-test-5.0.0.RC3.jar:5.0.0.RC3]
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'io.alfredux.demo.mapper.SourceToTargetMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1097) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1058) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:567) ~[spring-beans-5.0.0.RC3.jar:5.0.0.RC3]
    ... 29 common frames omitted

I believe there’s something missing or misplaced in the build/plugin section of my pom.xml file

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

The source code for the project can be checked here:

https://github.com/Alfredux79/mapstruct-lombock-springboot/tree/stack-overflow-question

The problem can be reproduced downloading the branch and running the command:

mvn test

Thanks!

5

There are 5 answers

1
Alfredo On

This is how my final version of the pom.xml build section looks like:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>${lombok.version}</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

And with this change the classes are being generated.

The solution was a mix of the answer provided and adding the annotation processor for lombock as well.

2
user3151902 On

You have not configured your compiler correctly. After running mvn clean compile, you should see some files generated by MapStruct under target/generated-sources.

You are missing the maven-compiler-plugin configuration:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.6.2</version>
    <configuration>
        <source>1.7</source>
        <target>1.7</target>
        <annotationProcessorPaths>
            <path>
                <groupId>org.mapstruct</groupId>
                <artifactId>mapstruct-processor</artifactId>
                <version>${org.mapstruct.version}</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

See this example.

0
Prathamesh Beri On

I encountered the same issue while using spring boot.

The issue was, on the maven annotation processor path plugin, I had specified the annotation configuration for the MapStruct path but still maven would give the unstaisfied dependency error. The implementation of the mapstruct mapper was being generated. Also my generated annotations folder was present on the classpath. Still no use.

The fix? It was being caused by project lombok. I had NOT used project lombok in my code, but it still ended up on my dependency tree. I specified an annotation configuration path on the pom.xml file for lombok as well, and finally, the damn thing got packaged.

Came *this* close to checking myself into a mental asylum.

0
Sathiamoorthy On

Add the below changes in pom.xml to make sure to use the latest m2e-apt plugin in maven.

<properties>
  <!-- automatically run annotation processors within the incremental compilation -->
  <m2e.apt.activation>jdt_apt</m2e.apt.activation>
</properties>

For eclipse or spring suite IDE support install the official mapstruct plugin.

https://marketplace.eclipse.org/content/mapstruct-eclipse-plugin#group-external-install-button

0
David Jesus On

Try adding this dependency

<dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-lang3</artifactId>
     <version>3.3.2</version>
     <type>jar</type>
</dependency>