简体   繁体   English

MapStruct 实现在 Spring Boot Web 应用程序中不起作用

[英]MapStruct implementation is not working in Spring Boot Web Application

I am a newbie to Spring Boot and MapStruct Tool.我是 Spring Boot 和MapStruct工具的新手。

Earlier, A Project(written by other team using these technologies) is not starting up.早些时候,一个项目(由其他团队使用这些技术编写)没有启动。 Then, I had made some changes in Mapper Abstract Class but now mapper object is coming as null on application startup.然后,我在 Mapper 抽象类中做了一些更改,但现在映射器对象在应用程序启动时变为 null。

Mapper Abstract Class:映射器抽象类:

@Mapper(componentModel = "spring")
public abstract class UserAndEmployeeMapper {

    public UserAndEmployeeMapper INSTANCE = Mappers.getMapper( UserAndEmployeeMapper.class );

    @Mapping(source = "username", target = "name")
    @Mapping(source = "ssn", target = "ssn", defaultValue = "xxxxxx" )
    @Mapping(target = "salary", constant = "34.67")
    @Mapping(target = "dob", dateFormat = "dd/MM/yyyy", constant = "10/12/2002")
    public abstract Employee mapToEmployee(User user);

    public abstract List<Employee> mapToEmployee(List<User> users);

    @Mapping(source = "name", target = "username")
    public abstract User mapToUser(Employee employee);

    public abstract List<User> mapToUser(List<Employee> employees);

}

LoginServiceImpl class LoginServiceImpl 类

@Service("loginService")
public class LoginServiceImpl implements LoginService{

    private static final AtomicLong counter = new AtomicLong();

    @Autowired
    private EmployeeDao employeeDao;

    private UserAndEmployeeMapper userAndEmployeeMapper;
...

}

pom.xml pom.xml

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

After I added @Autowired in LoginServiceImpl, application is not starting and following error log is showing在 LoginServiceImpl 中添加 @Autowired 后,应用程序未启动并显示以下错误日志

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

Description:

Field userAndEmployeeMapper in org.service.impl.LoginServiceImpl required a bean of type 'org.mapper.UserAndEmployeeMapper' that could not be found.


Action:

Consider defining a bean of type 'org.mapper.UserAndEmployeeMapper' in your configuration.

Any suggestions ?有什么建议么 ?

First of all, public UserAndEmployeeMapper INSTANCE = Mappers.getMapper( UserAndEmployeeMapper.class );首先, public UserAndEmployeeMapper INSTANCE = Mappers.getMapper( UserAndEmployeeMapper.class ); should only be used with the default component model, otherwise you risk to have the UserAndEmployeeMapper not correctly initialized.只能与默认组件模型一起使用,否则可能会导致UserAndEmployeeMapper未正确初始化。

The UserAndEmployeeMapper in your LoginServiceImpl must be annotated with @Autowired , otherwise it cannot be injected by Spring, and that's why it is null . LoginServiceImpl中的UserAndEmployeeMapper必须使用@Autowired注解,否则 Spring 无法将其注入,这就是它为null的原因。

I don't know your package structure.我不知道你的包结构。 If your Spring Boot application class in the package org then it will pick up the UserAndEmployeeMapperImpl .如果您的 Spring Boot 应用程序类在包org中,那么它将获取UserAndEmployeeMapperImpl Otherwise make sure that the spring configuration picks up the UserAndEmployeeMapperImpl .否则,请确保 spring 配置选择UserAndEmployeeMapperImpl

If everything from above is correctly setup and you are starting the application via an IDE make sure that target/generated-sources or the alternative for Gradle is part of your sources and is picked up.如果上面的所有内容都正确设置并且您正在通过 IDE 启动应用程序,请确保target/generated-sources或 Gradle 的替代项是您的源的一部分并被拾取。 Have a look at the IDE Support to make sure that you have correctly setup the Annotation processor discovery for an IDE.查看IDE 支持以确保您已正确设置 IDE 的注释处理器发现。 For example, IntelliJ will not invoke the MapStruct Annotation Processor with your current setup, it doesn't pick up the annotationProcessorPaths from the maven compiler.例如,IntelliJ 不会使用您当前的设置调用 MapStruct 注释处理器,它不会从 maven 编译器中获取annotationProcessorPaths

将抽象类作为接口对我有用。

public interface UserAndEmployeeMapper {

I ran into this issue too, and changing the mapper from abstract class to an interface didn't work for me. 我也遇到了这个问题,将mapper从抽象类更改为接口对我来说不起作用。

I ended up: 我结束了:

  • Removing the INSTANCE property from the mapper interface 从映射器接口中删除INSTANCE属性
  • Creating a class implementing the interface, implementing the mappes methods 创建一个实现接口的类,实现mappes方法
  • Adding an instance of this class as an @Autowired property in classes which need the mapper, and calling that instead. 在需要映射器的类中添加此类的实例作为@Autowired属性,并调用它。

WebAppMapper.java WebAppMapper.java

    @Mapper(componentModel = "spring")
    public interface WebAppMapper {
        CatalogData createCatalogRequestToData(CreateCatalogRequest createCatalogRequest);
    }

WebAppMapperImpl.java WebAppMapperImpl.java

@Component
public class WebAppMapperImpl implements WebAppMapper {
    @Override
    public CatalogData createCatalogRequestToData(CreateCatalogRequest createCatalogRequest) {
        CatalogData catalogData = new CatalogData();
        catalogData.setId(createCatalogRequest.getId());
        catalogData.setName(createCatalogRequest.getName());
        return catalogData;
    }
}

CatalogController.java CatalogController.java

@Autowired
WebAppMapper webAppMapper;

webAppMapper.createCatalogRequestToData(createCatalogRequest);

This worked for me. 这对我有用。

springfox-swagger2 dependency is loading older version of mapstruct after excluding it and adding specific version of mapstruct dependency in pom.xml it started generating sources springfox-swagger2 依赖项在排除它并在 pom.xml 中添加特定版本的 mapstruct 依赖项后加载旧版本的 mapstruct 它开始生成源

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
<exclusions>
 <exclusion>
 <groupId>org.mapstruct</groupId>
  <artifactId>mapstruct</artifactId>
 </exclusion>
</exclusions>

Added below map struct dependency在地图结构依赖项下方添加

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Beta1</version>

For making all mapper classes to qualify as spring bean add following compilerArgs to your maven-compiler-plugin.为了使所有映射器类都符合 Spring bean 的要求,请将以下 compilerArgs 添加到您的 maven-compiler-plugin。

<compilerArgs>
<arg>-Amapstruct.suppressGeneratorTimestamp=true</arg>
<arg>-Amapstruct.defaultComponentModel=spring</arg>
</compilerArgs> 

if using maven-processor-plugin add following options如果使用 maven-processor-plugin 添加以下选项

<options>                       
<mapstruct.suppressGeneratorTimestamp>
true
</mapstruct.suppressGeneratorTimestamp>                      
<mapstruct.defaultComponentModel>
spring
</mapstruct.defaultComponentModel>
</options>

try this in pom.xml:在 pom.xml 中试试这个:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>17</source>
                <target>17</target>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.4.2.Final</version>
                    </path>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>1.18.22</version>
                    </path>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok-mapstruct-binding</artifactId>
                        <version>0.2.0</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>

and reload Maven (ALT+F5)并重新加载 Maven (ALT+F5)

In my case, I believe the error was due to an incomplete build.gradle.就我而言,我认为错误是由于 build.gradle 不完整造成的。

Before

dependencies {
    compile group: 'org.mapstruct', name: 'mapstruct-processor', version: '1.2.0.Final'
}

After

apply plugin: 'net.ltgt.apt'

dependencies {
    compile group: 'org.mapstruct', name: 'mapstruct-processor', version: '1.2.0.Final'
    compile group: 'org.mapstruct', name: 'mapstruct-jdk8', version: '1.2.0.Final'
    apt 'org.mapstruct:mapstruct-processor:1.2.0.Final'
}


buildscript {
    repositories {
        mavenCentral()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath("net.ltgt.gradle:gradle-apt-plugin:0.9")
    }
}

Ensure you have configured your build.gradle properly, as described in the docs.确保您已正确配置 build.gradle,如 文档中所述。

If using Eclipse, you may have to install the m2e-apt plugin.如果使用 Eclipse,您可能需要安装m2e-apt插件。

It will enable the annotation processor for MapStruct in the IDE.它将在 IDE 中为 MapStruct 启用注释处理器。

Its simple first you need to create interface as below,首先很简单,您需要创建如下界面,

@Mapper(componentModel = "spring")
public interface CompanyMapper {
     @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
     void updateCustomerFromDto(CompanyDto dto, @MappingTarget CompanyBean entity);
}

Now when you run the application it will generate its implementation file it self in the target/generated-source folder现在,当您运行应用程序时,它将在 target/generated-source 文件夹中自行生成其实现文件

So whenever you want to use CompanyMapper than you only need to autowired it as we use @Mapper(componentModel = "spring") so spring boot can able to inject this.因此,每当您想使用 CompanyMapper 时,您只需要像我们使用@Mapper(componentModel = "spring")那样自动装配它,这样 spring boot 就可以注入它。

And also you need to enable the Maven annotation processing by following steps in eclipse :您还需要通过 eclipse 中的以下步骤启用 Maven 注释处理:

Step1 :- Right click on the project Step1 :- 右键单击​​项目
Step2 :- Go to Properties Step2 :- 转到属性
Step3 : Expand Maven from sidebar Step3 : 从侧边栏展开 Maven
Step4 :- Select Annotation Processing Step4 :- 选择注释处理
Step5 :- Checked Enable Project Specific settings第 5 步:- 选中启用项目特定设置
Step6 :- Select Experemental Radio button Step6 :- 选择实验单选按钮
Step7 :- Apply and Close Step7 :- 申请并关闭

Its Done !完成 ! I hope its helpful to someone.我希望它对某人有帮助。

Make sure you put annotation processor path in the dependency.确保将注释处理器路径放在依赖项中。

<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>${java.version}</source> <!-- depending on your project -->
                <target>${java.version}</target> <!-- depending on your project -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                    <!-- other annotation processors -->
                </annotationProcessorPaths>
            </configuration>
        </plugin>

POM.XML 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 https://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.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.customer-service</groupId>
    <artifactId>customer-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>customer-service</name>
    <description>Microservice Client-Facture avec Spring Boot</description>
    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
         <org.mapstruct.version>1.4.2.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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</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.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.5.2</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

     <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.16</version>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
             
                <configuration>
                    <source>17</source> <!-- depending on your project -->
                    <target>17</target> <!-- depending on your project -->
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>1.18.16</version>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                        <!-- other annotation processors -->
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM