如何调试(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看源码,那距离解决问题就不远了。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要在Maven项目中使用GraalVM进行调试,需要使用GraalVM自带的调试器`jsadebugd`。下面是具体步骤: 1. 在POM文件中添加以下依赖项: ```xml <dependency> <groupId>org.graalvm.sdk</groupId> <artifactId>graal-sdk</artifactId> <version>${graalvm.version}</version> <scope>provided</scope> </dependency> ``` 2. 在Maven命令行中运行以下命令: ``` mvn package -DskipTests -Pnative ``` 3. 运行以下命令来启动调试器: ``` jsadebugd --port 8000 --jvmcpuset <cpu-set> --graalvm-home <graalvm-home> ``` 其中,`<cpu-set>`是CPU集合的列表,`<graalvm-home>`是GraalVM的根目录。例如: ``` jsadebugd --port 8000 --jvmcpuset 0,1 --graalvm-home /usr/local/graalvm-ce-21.0.0 ``` 4. 在`pom.xml`文件中添加以下插件配置: ```xml <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>debug</id> <phase>test</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>native-image</executable> <workingDirectory>${project.basedir}</workingDirectory> <arguments> <argument>--debug-attach=<hostname>:8000</argument> <argument>--no-fallback</argument> <argument>--allow-incomplete-classpath</argument> <argument>--report-unsupported-elements-at-runtime</argument> <argument>--initialize-at-build-time</argument> <argument>--no-server</argument> <argument>--verbose</argument> <argument>--class-path</argument> <classpath/> <argument>--enable-all-security-services</argument> <argument>--enable-url-protocols=http,https</argument> <argument>--enable-https</argument> <argument>--initialize-at-run-time=org.apache.maven.cli.MavenCli,org.codehaus.plexus.classworlds.launcher.Launcher</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.classworlds.realm.ClassRealm</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.configuration.PlexusConfigurationException</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.configuration.xml.XmlPlexusConfigurationReader</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.util.xml.XmlStreamReaderException</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.util.xml.pull.XmlPullParserException</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.util.xml.pull.XmlPullParserFactory</argument> <argument>--initialize-at-run-time=org.codehaus.plexus.util.xml.pull.XmlSerializer</argument> <argument>--initialize-at-run-time=org.sonatype.aether.RepositorySystem</argument> <argument>--initialize-at-run-time=org.sonatype.aether.RepositorySystemSession</argument> <argument>--initialize-at-run-time=org.sonatype.aether.artifact.Artifact</argument> <argument>--initialize-at-run-time=org.sonatype.aether.graph.Dependency</argument> <argument>--initialize-at-run-time=org.sonatype.aether.graph.DependencyNode</argument> <argument>--initialize-at-run-time=org.sonatype.aether.repository.ArtifactRepository</argument> <argument>--initialize-at-run-time=org.sonatype.aether.repository.LocalRepository</argument> <argument>--initialize-at-run-time=org.sonatype.aether.repository.RemoteRepository</argument> <argument>--initialize-at-run-time=org.sonatype.aether.resolution.ArtifactResolutionException</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.artifact.DefaultArtifact</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.graph.DefaultDependencyNode</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.graph.manager.DependencyManagerUtils</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.graph.manager.SessionDependencyManager</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.repository.DefaultAuthenticationSelector</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.repository.DefaultMirrorSelector</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.repository.DefaultProxySelector</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.repository.SimpleArtifactDescriptorPolicy</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.DefaultXmlProcessor</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.Xpp3DomBuilder</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.Xpp3DomUtils</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.pull.MXParser</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.pull.XmlPullParser</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.pull.XmlPullParserException</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.pull.XmlPullParserFactory</argument> <argument>--initialize-at-run-time=org.sonatype.aether.util.xml.pull.XmlSerializer</argument> <argument>--initialize-at-run-time=org.sonatype.aether.version.Version</argument> <argument>--initialize-at-run-time=org.sonatype.aether.version.VersionConstraint</argument> <argument>--initialize-at-run-time=org.sonatype.aether.version.VersionRange</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> ``` 5. 运行以下命令来启动调试: ``` mvn test ``` 这将启动本地服务器,等待调试器连接。打开您的IDE调试器,并将其连接到本地服务器。这样,您就可以调试Maven项目了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

镜悬xhs

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

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

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

打赏作者

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

抵扣说明:

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

余额充值