Hi guys I'm having issues with the mapstruct mappe...
# spring
a
Hi guys I'm having issues with the mapstruct mapper in springboot
Copy code
@Mapper
@Component
interface UserMapper {
    fun toUserDTO(user: User): UserDTO
    fun toListOfUserDTO(users: List<User>) : List<UserDTO>
    fun toUser(userDTO: UserDTO) : User
    fun toListOfUser(userDTOs: List<UserDTO>) : List<User>
}
and i'm using it in my contoller
Copy code
@Autowired
lateinit var userMapper: UserMapper
It gives this error, please help
***************************
APPLICATION FAILED TO START *************************** Description: Field userMapper in com.scienta.backend_rated_ng.controller.AuthController required a bean of type 'com.scienta.backend_rated_ng.mapper.UserMapper' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'com.scienta.backend_rated_ng.mapper.UserMapper' in your configuration. I have all my dependencies right
t
marking the interface as
@Component
will probably not do much. You need to configure mapstruct to generate spring annotations
a
Please how do I do that?
t
had to look it up in a past project...
@Mapper(componentModel = "spring")
This will add
@Component
to the generated class and in case you add dependencies to other mappers with
uses
, those will be autowired.
Just some hints though when working with mapstruct and kotlin: • Be aware that Mapstruct doesn't consider kotlin nullability • In Kotlin there is a difference between Collections and MutableCollections, which may lead to unexpected generics when using the non-mutable versions • kapt (the generator) only runs with gradle, so when running out of intellij, mappers will not be generated.
a
what do you mean byt doeant consider kotlin nullability'?
i'm on a maven project not a gradle project
t
The generated Mapper class is written in java. If you're mapping between a nullable and a non-null field, the java code will look just fine, but you may get a runtime error when trying to set a null value to a non-null field
and it's the same with maven. It will work with maven, but not when running directly with intellij (and not delegating the build to your build tool)
a
so how will mappers be generated? I already enabled annotation processing in intellij
t
One more point: I personally find it to be good practice to have immutable values in my Kotlin data classes and set everything in the constructor. Unfortunately this doesn't work with mapstruct
Intellij annotation processing only supports java classes. You have to define it in your maven project and build with maven
a
okay I have annotation processing plugin in my pom.xml already
still the same error even after i included
@Mapper(componentModel = "spring")
t
did you build it with maven or with intellij?
a
intellij
i also ran maven clean and install
t
like i said, building with intellij won't generate the classes. But if you built it with maven before, it should pick up the generated classes when also running from intellij
a
you build with maven through maven install right?
t
afaik mvn install does more than just build, but build should be included. I'm not sure, but maybe you can even run mvn kapt
Unfortunatly I'm not really a mvn expert, but if you want you can post you pom here and maybe I can see something
And on a different note: I used to be a fan of Mapstruct, but when my last project grew and became more complex, so did the mapper definitions, until we reached a point where we said that putting all values in the constructor of our classes and writing mappers manually was actually easier to understand, provides more compile time safety, eliminates the kapt+intellij issue and isn't really much more effort. So, personally, I don't recommend Mapstruct anymore
☝️ 1
You said you "have annotation processing plugin in my pom.xml already". I'm not sure if that's what you meant, but you don't need an additional plugin, you need the kapt execution step in the kotlin plugin (like described in the link i posted above)
a
message has been deleted
Copy code
<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
      <groupId>com.twilio.sdk</groupId>
      <artifactId>twilio</artifactId>
      <version>7.55.0</version>
   </dependency>
   <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-kotlin</artifactId>
   </dependency>
   <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-reflect</artifactId>
   </dependency>
   <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.1</version>
   </dependency>
   <dependency>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.7.0</version>
   </dependency>
   <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct</artifactId>
      <version>1.3.1.Final</version>
   </dependency>
   <dependency>
      <groupId>org.jetbrains.kotlin</groupId>
      <artifactId>kotlin-stdlib-jdk8</artifactId>
   </dependency>

   <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
   </dependency>
   <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <scope>runtime</scope>
   </dependency>
   <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct-processor</artifactId>
      <version>1.3.1.Final</version>
      <scope>provided</scope>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
         <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
         </exclusion>
      </exclusions>
   </dependency>
   <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-test</artifactId>
      <scope>test</scope>
   </dependency>
</dependencies>



<build>
   <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
   <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
   <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.7.0</version>
               <configuration>
                   <source>1.8</source>
                   <target>1.8</target>
                   <annotationProcessorPaths>
                       <path>
                           <groupId>org.projectlombok</groupId>
                           <artifactId>lombok</artifactId>
                           <version>${lombok.version}</version>
                       </path>
                       <path>
                           <groupId>org.mapstruct</groupId>
                           <artifactId>mapstruct-processor</artifactId>
                           <version>1.3.1.Final</version>
                       </path>
                   </annotationProcessorPaths>
                   <compilerArgs>
                       <compilerArg>
                           -Amapstruct.defaultComponentModel=spring
                       </compilerArg>
                   </compilerArgs>
               </configuration>
           </plugin>
      <plugin>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <version>2.22.2</version>
         <configuration>
            <testFailureIgnore>true</testFailureIgnore>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.jetbrains.kotlin</groupId>
         <artifactId>kotlin-maven-plugin</artifactId>
         <configuration>
            <args>
               <arg>-Xjsr305=strict</arg>
            </args>
            <compilerPlugins>
               <plugin>spring</plugin>
               <plugin>jpa</plugin>
            </compilerPlugins>
         </configuration>
         <dependencies>
            <dependency>
               <groupId>org.jetbrains.kotlin</groupId>
               <artifactId>kotlin-maven-allopen</artifactId>
               <version>${kotlin.version}</version>
            </dependency>
            <dependency>
               <groupId>org.jetbrains.kotlin</groupId>
               <artifactId>kotlin-maven-noarg</artifactId>
               <version>${kotlin.version}</version>
            </dependency>
         </dependencies>
      </plugin>
   </plugins>
</build>
t
Ok, so you defined your annotation processors in the maven-compiler-plugin. If you want them to pick up kotlin classes, they have to be registered in the kapt execution step
a
how please?
t
i posted the link already in this thread 👆🏻
there you can also find a link to an example repository if you need more context