Search code examples
springautowiredspring-restcontrollermappermapstruct

I can't add mapstruct in my Spring project


I try to add mapstruct mapper in my Spring project.

I have a User entity. I need to show a list of users in the admin panel. For this, I did DTO UserForAdmin, mapper UserMapper and rest controller AdminRestController. When I try to get UserMapper I get errors.

I try two ways:

  1. Mappers.getMapper(UserMapper.class)

I get error

java.lang.ClassNotFoundException: Cannot find implementation for ru.project.mapper.UserMapper

  1. Autowired

I get error

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2019-07-17 15:47:07.886 ERROR 13652 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :

*************************** APPLICATION FAILED TO START


Description:

Field userMapper in ru.project.controller.rest.AdminRestController required a bean of type 'ru.project.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 'ru.project.mapper.UserMapper' in your configuration.

Here my source code.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>ru.project</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>project</name>
    <description>The project is project of resourse for investors.</description>

    <properties>
        <java.version>12</java.version>
        <org.mapstruct.version>1.3.0.Final</org.mapstruct.version>
    </properties>

    <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-mail</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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>2.3.5</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
    </dependencies>

    <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>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>                 
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

My interface UserMapper:

package ru.project.mapper;

import java.util.List;

import org.mapstruct.Mapper;
import ru.project.domain.User;
import ru.project.dto.UserForAdmin;

@Mapper
//@Mapper(componentModel = "spring")
public interface UserMapper {

    UserForAdmin UserToUserForAdmin(User user);

    List<UserForAdmin> UserListToUserForAdminList(List<User> user);


}

My RestController:

package ru.project.controller.rest;

import java.util.List;

import org.mapstruct.factory.Mappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import ru.project.dto.UserForAdmin;
import ru.project.mapper.UserMapper;
import ru.project.service.UserService;

@RestController
public class AdminRestController {

    @Autowired
    private UserService userService;

    //@Autowired
    //private UserMapper userMapper;

    @GetMapping("/admin/users")
    public List<UserForAdmin> findAllUsers(){

        UserMapper userMapper = Mappers.getMapper(UserMapper.class);

        return userMapper.UserListToUserForAdminList(userService.findAll()); 
    }

}

I would like to use Awtowired.


Solution

  • You need to use @Mapper(componentModel="spring")

    package ru.project.mapper;
    
        import java.util.List;
    
        import org.mapstruct.Mapper;
        import ru.project.domain.User;
        import ru.project.dto.UserForAdmin;
    
            @Mapper(componentModel = "spring")
            public interface UserMapper {
    
                UserForAdmin UserToUserForAdmin(User user);
    
                List<UserForAdmin> UserListToUserForAdminList(List<User> user);
    
            }
    

    and use below in AdminRestController

    @Autowired  
    private UserMapper userMapper;
    

    And i am assuming that User and UserForAdmin have same field names After this run mvn clean compile and sources will be generated