如何调试(debug)maven插件

我在自己的项目中引入了 MapStruct【https://mapstruct.org/】用于完成对象间映射转换。

MapStruct框架的作用不过多解释了,想要了解的可以看下它的官网介绍。主要作用就是可以通过配置,定义对象和对象之间的映射,减轻编码负担。

MapStruct性能很高。之所以快,是因为它没有用反射。之所以能不用反射,是因为它是在程序编译期间,直接生成了对象转换的类文件。

这段比较抽象,但用过lombok的话就好理解了。它和lombok很相似,主要工作是在编译期完成,不是运行时。

1. 问题

下面是我遇到的问题,具体逻辑可以不用太纠结,大概知道我要干啥就行了。

首先,我使用MaStruct定义了如下的接口:

@Mapper(uses = {JsonStrMapper.class, PrimitiveNullMapper.class},
        componentModel = "spring",
        nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
public interface UserPropertyMapper {
    @SuccessResponse
    @Mapping(target = "basic", qualifiedByName = {"JsonStrMapper", "BeanMapToStrMap"})
    @Mapping(target = "credit", qualifiedByName = {"JsonStrMapper", "BeanMapToStrMap"})
    @Mapping(target = "growth", qualifiedByName = {"JsonStrMapper", "BeanMapToStrMap"})
    @Mapping(target = "tag", qualifiedByName = {"JsonStrMapper", "BeanMapToStrMap"})
    GetUserPropertyResponse entityToGetResponse(UserPropertyEntity entity) throws MapperException;
}

MapStruct生成的源代码如下:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-01-26T11:24:54+0800",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_272 (AdoptOpenJDK)"
)
@Component
public class UserPropertyMapperImpl implements UserPropertyMapper {
    @Override
    public GetUserPropertyResponse entityToGetResponse(UserPropertyEntity entity) throws MapperException {

        GetUserPropertyResponse getUserPropertyResponse = new GetUserPropertyResponse();

        if ( entity != null ) {
            getUserPropertyResponse.setBasic( jsonStrMapper.toJson( entity.getBasic() ) );
            getUserPropertyResponse.setCredit( jsonStrMapper.toJson( entity.getCredit() ) );
            getUserPropertyResponse.setGrowth( jsonStrMapper.toJson( entity.getGrowth() ) );
            getUserPropertyResponse.setTag( jsonStrMapper.toJson( entity.getTag() ) );
            if ( entity.getUserId() != null ) {
                getUserPropertyResponse.setUserId( entity.getUserId() );
            }
            if ( entity.getScore() != null ) {
                getUserPropertyResponse.setScore( entity.getScore() );
            }
            if ( entity.getLevel() != null ) {
                getUserPropertyResponse.setLevel( entity.getLevel() );
            }
            getUserPropertyResponse.setResult( userPropertyEntityToResult( entity ) );
        }

        return getUserPropertyResponse;
    }
}

但其实,我想要生成的代码是类似于下面这个样子的:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2021-01-26T11:24:54+0800",
    comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_272 (AdoptOpenJDK)"
)
@Component
public class UserPropertyMapperImpl implements UserPropertyMapper {
    @Override
    public GetUserPropertyResponse entityToGetResponse(UserPropertyEntity entity) throws MapperException {

        GetUserPropertyResponse getUserPropertyResponse = new GetUserPropertyResponse();

        if ( entity != null ) {
            getUserPropertyResponse.setBasic( jsonStrMapper.toJson( entity.getBasic() ) );
            getUserPropertyResponse.setCredit( jsonStrMapper.toJson( entity.getCredit() ) );
            getUserPropertyResponse.setGrowth( jsonStrMapper.toJson( entity.getGrowth() ) );
            getUserPropertyResponse.setTag( jsonStrMapper.toJson( entity.getTag() ) );
            if ( entity.getUserId() != null ) {
                getUserPropertyResponse.setUserId( entity.getUserId() );
            }
            if ( entity.getScore() != null ) {
                getUserPropertyResponse.setScore( entity.getScore() );
            }
            if ( entity.getLevel() != null ) {
                getUserPropertyResponse.setLevel( entity.getLevel() );
            }
        }

        getUserPropertyResponse.setResult( userPropertyEntityToResult( entity ) );
        return getUserPropertyResponse;
    }
}

意思是:无论传入的对象是不是null,我都希望返回的对象中,result属性是有值的。

2. 思路

这个问题该怎么解呢?

首先翻阅了一遍MapStruct的文档,通篇了解下来,没有发现特别有价值的说明。其中的NullValueMappingStrategy,看起来也达不到我想要的效果:

public enum NullValueMappingStrategy {

    /**
     * If {@code null} is passed to a mapping method, {@code null} will be returned. That's the default behavior if no
     * alternative strategy is configured globally, for given mapper or method.
     */
    RETURN_NULL,

    /**
     * If {@code null} is passed to a mapping method, a default value will be returned. The value depends on the kind of
     * the annotated method:
     * <ul>
     * <li>For bean mapping methods the target type will be instantiated and returned. Any properties of the target type
     * which are mapped via {@link Mapping#expression()} or {@link Mapping#constant()} will be populated based on the
     * given expression or constant. Note that expressions must be prepared to deal with {@code null} values in this
     * case.</li>
     * <li>For iterable mapping methods an empty collection will be returned.</li>
     * <li>For map mapping methods an empty map will be returned.</li>
     * </ul>
     */
    RETURN_DEFAULT;
}

那既然无法从文档层面上找到解决方案,下一步正确的姿势就是要去看源码了。

然而,MapStruct的源码是作用在编译期的,常规的debug方案肯定没办法解决这个问题。这时候,就需要去debug源代码编译过程了。

3. 测试

那该怎么debug编译过程呢?

在网上搜了下相关内容,可以使用mvnDebug clean compile命令启动远程调试过程。

所以,先在terminal上运行上述命令:

(base) ➜  insight-core git:(jingxuan_dev) ✗ mvnDebug clean compile
Preparing to execute Maven in debug mode
Listening for transport dt_socket at address: 8000

嗯,8000端口已经处于监听状态了。下面得想办法启动远端8000端口的服务。

在IDEA中,打开配置页面:

选择Remote模板,创建配置项:

按照下面的设置,增加设置,主要要设置8000端口:

点击图中的debug按钮:

这时,等在terminal中mvnDebug就开始跑了:

[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ insight-core ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 94 source files to /Users/jingxuan/workspace/RED/insight/insight-core/target/classes
[INFO] /Users/jingxuan/workspace/RED/insight/insight-core/src/main/java/com/xiaohongshu/risk/platform/insight/schema/support/AbstractMapToEntityConverter.java: 某些输入文件使用了未经检查或不安全的操作。
[INFO] /Users/jingxuan/workspace/RED/insight/insight-core/src/main/java/com/xiaohongshu/risk/platform/insight/schema/support/AbstractMapToEntityConverter.java: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.278 s
[INFO] Finished at: 2021-01-26T12:14:49+08:00
[INFO] ------------------------------------------------------------------------

可是,它就这么直接跑完了,没断点啊!

3. 断点

首先,看下pom.xml中插件的配置:

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>${maven-compiler-plugin.version}</version>
  <configuration>
    <source>${jdk.version}</source>
    <target>${jdk.version}</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>${org.mapstruct.version}</version>
      </path>
    </annotationProcessorPaths>
    <compilerArgs>
      <compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
    </compilerArgs>
  </configuration>
</plugin>

这里面的mapstruct-processor就是MapStruct用于生成映射源文件的包。但是,plugin中的包是不会引入到maven依赖中的。所以,我们还要手动将这个包加入到依赖中:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>${org.mapstruct.version}</version>
</dependency>

这个时候,不出意外就能在依赖包中找到这个jar文件了:

找到处理类,增加断点。再次按照前面说的方法运行一遍,就能顺利开始debug了:

到这一步,只要能开始debug看源码,那距离解决问题就不远了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

镜悬xhs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值