4

I have the following parts in my gradle file:

apply plugin: 'kotlin-kapt'
...
    compile("org.mapstruct:mapstruct:1.3.0.Final")
    kapt("org.mapstruct:mapstruct-processor:1.3.0.Final")

And am also using JUnit 5.

My mapper looks like:

@Mapper(componentModel = "spring")
interface ModelMapper {
    fun convertToDto(forms: Model): DTO

    @InheritInverseConfiguration
    fun convertToModel(dto: DTO): Model
}

And I'm trying to autowire it similar to such:

@Service
@Transactional
class MyService @Autowired constructor(
    private val repository: MyRepository,
    private val mapper: ModelMapper
) {
...
}

But when I try to run a test/do a build, I get an error:

...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '....ModelMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Does anyone know why Spring Boot isn't working with this kind of setup?

ben l
  • 95
  • 1
  • 8
  • This might help: https://stackoverflow.com/questions/44458089/mapstruct-implementation-is-not-working-in-spring-boot-web-application – Chris Sep 16 '19 at 19:53
  • I've already seen that. The "solution" is to use an interface, which is exactly what I've done. The "top" answer was basically the person hand-writing the mappings. That isn't utilizing MapStruct at all. I do want to emphasize that I'm using Kotlin, and not Java - and although they use the same JVM, Kotlin seems to require workarounds to get things to work. – ben l Sep 16 '19 at 21:37
  • The exception you're getting basically says: I don't know which class I should autowire, please create one with type xyz. Although it doesn't make much sense, you could annotate the mapper with @component, which usually solves this problem. – Chris Sep 17 '19 at 05:05
  • And regarding the other post: I was referring to the answer by Minnow – Chris Sep 17 '19 at 05:10
  • I understand that. And I have tried Minnow's solution (or at least a few gradle variants), and none of it worked. – ben l Sep 17 '19 at 05:44
  • Did you ever figure out a solution to this? – Jodiug Nov 05 '19 at 10:32
  • No, I did not. I did find more information that may have helped, such as using a mapstruct kotlin library that utilized builders instead. In the end it just didn't seem worth the time and I just hard coded a toModel/toDto method. – ben l Nov 06 '19 at 18:21
  • I have the same issue. Problem is the Impl class with implementation for mapper interface is not generated. Therefore spring has no candidate for autowiring – squirrelInTheBarel Sep 21 '22 at 13:47

5 Answers5

0

Try passing Spring's annotation processor to kapt in build.gradle:

kapt("org.springframework.boot:spring-boot-configuration-processor:${springBootVersion}")

or try keeping javac annotation processors:

kapt {
    keepJavacAnnotationProcessors = true
}
Georgian
  • 8,795
  • 8
  • 46
  • 87
0

this helped me, add this in your build.gradle.kts:

    implementation("org.mapstruct:mapstruct")
    kapt("org.mapstruct:mapstruct-processor")

    compileOnly(group = "org.springframework.boot", name = "spring-boot-configuration-processor")
    kapt(group = "org.springframework.boot", name = "spring-boot-configuration-processor")
meiskalt7
  • 606
  • 7
  • 13
0

So here is the solution.

Just the pom.xml has to contains some more info:

<executions>
 <execution>
     <id>compile</id>
     <phase>process-sources</phase>
     <goals>
         <goal>compile</goal>
     </goals>
 </execution>
 <execution>
     <id>test-compile</id>
     <phase>test-compile</phase>
     <goals>
         <goal>test-compile</goal>
     </goals>
 </execution>
 <execution>
     <id>kapt</id>
     <goals>
         <goal>kapt</goal>
     </goals>
     <configuration>
         <sourceDirs>
             <sourceDir>src/main/kotlin</sourceDir>
             <sourceDir>src/main/java</sourceDir>
         </sourceDirs>
         <annotationProcessorPaths>
             <annotationProcessorPath>
                 <groupId>org.mapstruct</groupId>
                 <artifactId>mapstruct-processor</artifactId>
                 <version>${mapstruct.version}</version>
             </annotationProcessorPath>
         </annotationProcessorPaths>
     </configuration>
 </execution>

And then it works

0

If you have a @Transactional class{} then you must have all of its methods open open fun(){} to enable bean Autowiring,,

kotlin spring boot plugin changes the default behavior of kotlin which opens all classes and methods by defauls

Just add kotlin spring boot plugin in your project's build.gradle

groovy:

plugins {
    ....
    id 'org.jetbrains.kotlin.plugin.spring' version '1.8.22'
}

kotlin

plugins {
    ....
    kotlin("plugin.spring") version "1.8.22"
}
-1

Try to add

kapt("org.mapstruct:mapstruct-jdk8:1.3.1.Final")

I'm using mapstruct in springboot using kotlin and gradle. And everything works fine with autowiring, that's all what i have:

apply plugin: "kotlin-kapt"

compile "org.mapstruct:mapstruct:1.3.1.Final"

kapt("org.mapstruct:mapstruct-processor:1.3.1.Final")
kapt("org.mapstruct:mapstruct-jdk8:1.3.1.Final")

And configuration for the interface:

@Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)