spring boot 之使用mapstruct

Posted 来自非洲大草原的食人虎

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot 之使用mapstruct相关的知识,希望对你有一定的参考价值。

  最近在阅读swagger源码,当看到 springfox.documentation.swagger2.mappers.ModelMapper 类时,无意中看到该类上面使用的 org.mapstruct.Mapper 注解时,对这个注解一时竟想不出个所意然来。便打开百度搜索了一番,有关这个注解的文章不是很多,从这些文章中了解到,这个注解跟JSR 269 有关,下面列出这个注解相关的文章链接。


 相关的文章链接:

  1.  mapstruct官网 http://mapstruct.org/
  2.  mapstruct github网址:https://github.com/mapstruct/mapstruct
  3. JSR 269: Pluggable Annotation Processing API  https://jcp.org/en/jsr/detail?id=269
  4. 插入式注解处理API(Pluggable Annotation Processing API)  https://blog.csdn.net/yczz/article/details/34116189
  5. MapStruct实体间转换快速入门  https://blog.csdn.net/lx_yoyo/article/details/75061614

  当看完上面的几篇的文章之后,对这个注解到底起何作用,仍然是一知半解。于是参照上面列表中的 MapStruct实体间转换快速入门 ,当我把工程建好,copy完相关的代码之后,根据文章的提示,执行mvn install(mvn compile)命令之后,没有出现文章中提到的在 target\\generated-sources\\annotations 会自动生成PeopleMapperImpl.Java 源文件,反到是控制台打印出的日志信息提示编译失败,错误信息如下所示:

 

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] /F:/java.ws.01/springboot-example/example4/src/main/java/com/github/torlight/sbex/PeopleMapper.java:[21,15] No property named "age" exists in source parameter(s). Did you mean "null"?
[ERROR] /F:/java.ws.01/springboot-example/example4/src/main/java/com/github/torlight/sbex/PeopleMapper.java:[32,10] No property named "user.name" exists in source parameter(s). Did you mean "null"?
[INFO] 2 errors 
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.951 s
[INFO] Finished at: 2018-08-19T10:52:59+08:00
[INFO] Final Memory: 26M/282M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:compile (default-compile) on project example4: Compilation failure: Compilation failure:
[ERROR] /F:/java.ws.01/springboot-example/example4/src/main/java/com/github/torlight/sbex/PeopleMapper.java:[21,15] No property named "age" exists in source parameter(s). Did you mean "null"?
[ERROR] /F:/java.ws.01/springboot-example/example4/src/main/java/com/github/torlight/sbex/PeopleMapper.java:[32,10] No property named "user.name" exists in source parameter(s). Did you mean "null"?
[ERROR] -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:compile (default-compile) on project example4: Compilation failure
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:862)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:286)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:197)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure
    at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:972)
    at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:129)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
    ... 20 more
[ERROR] 
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

 

  当出现上面的错误之后,先是在网上找了一下,但没有找到相关的资料,没办法只能靠自己解决了。查看工程的pom.xml文件,有用到maven-compiler-plugin 插件,看到该插件的配置项中mapstruct-processor ,心里也清楚当maven执行maven-compiler-plugin 插件中相关类的方法时,肯定会执行mapstruct-processor 中相关类的方法。可是不清楚具体会先从那个类的方法开始执行。

  没办法,只能根据上面的异常提示信息,在maven源码工程中一路跟踪下来,发现错误源是当执行SourceReference类的getSourceEntries方法时触发的。No property named "age" exists in source parameter(s). Did you mean "null"?  在被转换的实体中找不到age属性,可是在PeopleEntity 实体中本来就存在age属性。原来报错是因为getSourceEntries方法是通过反射读取实体的get方法来获取属性,然后再进行属性比较,怪不得会报错。当找到报错的原因之后,我把目光停留在源码中的注释 //constructor, getters, setters etc.  来实体中的getter,setter 方法都被省略了。

 

 1 package com.github.torlight.sbex;
 2 
 3 public class PeopleEntity {
 4     private Integer age;
 5     private String name;
 6     private String callNumber;
 7     private String address;
 8     private String email;
 9     
10     public PeopleEntity() {
11         
12     }
13 
14     public PeopleEntity(Integer age, String name, String callNumber, String address, String email) {
15         this.age = age;
16         this.name = name;
17         this.callNumber = callNumber;
18         this.address = address;
19         this.email = email;
20     }
21     
22   //constructor, getters, setters etc.
23 
24 }

 

 


 修改之后的代码:

 1 package com.github.torlight.sbex;
 2 
 3 public class PeopleDTO {
 4     
 5     private String phoneNumber;
 6     private String address;
 7     private String email;
 8     private User  user;
 9     
10     public PeopleDTO() {
11     
12     }
13 
14     public PeopleDTO(String phoneNumber, String address, String email, User user) {
15         this.phoneNumber = phoneNumber;
16         this.address = address;
17         this.email = email;
18         this.user = user;
19     }
20 
21     public String getPhoneNumber() {
22         return phoneNumber;
23     }
24 
25     public void setPhoneNumber(String phoneNumber) {
26         this.phoneNumber = phoneNumber;
27     }
28 
29     public String getAddress() {
30         return address;
31     }
32 
33     public void setAddress(String address) {
34         this.address = address;
35     }
36 
37     public String getEmail() {
38         return email;
39     }
40 
41     public void setEmail(String email) {
42         this.email = email;
43     }
44 
45     public User getUser() {
46         return user;
47     }
48 
49     public void setUser(User user) {
50         this.user = user;
51     }
52     
53 }

 

 1 package com.github.torlight.sbex;
 2 
 3 public class PeopleEntity {
 4     private Integer age;
 5     private String name;
 6     private String callNumber;
 7     private String address;
 8     private String email;
 9     
10     public PeopleEntity() {
11         
12     }
13 
14     public PeopleEntity(Integer age, String name, String callNumber, String address, String email) {
15         this.age = age;
16         this.name = name;
17         this.callNumber = callNumber;
18         this.address = address;
19         this.email = email;
20     }
21 
22     public Integer getAge() {
23         return age;
24     }
25 
26     public void setAge(Integer age) {
27         this.age = age;
28     }
29 
30     public String getName() {
31         return name;
32     }
33 
34     public void setName(String name) {
35         this.name = name;
36     }
37 
38     public String getCallNumber() {
39         return callNumber;
40     }
41 
42     public void setCallNumber(String callNumber) {
43         this.callNumber = callNumber;
44     }
45 
46     public String getAddress() {
47         return address;
48     }
49 
50     public void setAddress(String address) {
51         this.address = address;
52     }
53 
54     public String getEmail() {
55         return email;
56     }
57 
58     public void setEmail(String email) {
59         this.email = email;
60     }
61 
62 }   

 

package com.github.torlight.sbex;

public class User {
    private Integer age;
    private String name;
    
    public User() {

    }

    public User(Integer age, String name) {
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

  


 

  执行mvn install(mvn compile)命令之后,控制台没有提示报错,但在 \\target\\generated-sources\\annotations\\ 文件夹下面还是空的,奇怪了? 先执行mvn clean 然后再执行 mvn install(mvn compile)之后,终于出现了PeopleMapperImpl.java 源文件。要确保 target\\class 文件夹下面为空时,执行mvn install(mvn compile)命令才能生成java源文件。

 


 

示例代码: https://github.com/gittorlight/springboot-example/tree/master/example4

以上是关于spring boot 之使用mapstruct的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot MapStruct

Spring Boot | 集成MapStruct实现不同类型Java对象间的自动转换

小代学Spring Boot之数据源

加入mapstruct后出现 找不到符号 符号: 方法 setXX 的解决方法

使用 kotlin 在 Spring Boot 中映射结构接口错误

Spring boot 梳理 -@SpringBootApplication@EnableAutoConfiguration与(@EnableWebMVCWebMvcConfigurationSu(代