前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Java类型转换利器!MapStruct有个大坑,太容易掉进去了

Java类型转换利器!MapStruct有个大坑,太容易掉进去了

作者头像
大风写全栈
发布2024-11-12 17:08:42
发布2024-11-12 17:08:42
34400
代码可运行
举报
文章被收录于专栏:锤子代码
运行总次数:0
代码可运行

类型转换常见的方式

一般类型转换常用的两种方式:

1、BeanUtils(Spring、Apache、Hutool)各种实现都有,相对来说速度略慢;

2、MapStruct(速度相比BeanUtil快)。

BeanUtils的坑

接上,Spring BeanUtils之前遇到过一个最大的坑就是用copyProperties()方法,如果source和target中,某个属性的类型不一致,该属性就会被忽略。

但很多时候,这个问题很容易被忽略。

所以,用BeanUtils的时候一定要注意这个问题。

MapStruct的坑

相比BeanUtils,MapStruct提升了处理速度。

异常提示很友好,如果两个字段类型不一致,MapStruct会抛出异常。

一目了然,就会去填坑了。

MapStruct的坑-续

假设有下面这样一段代码:

代码语言:javascript
代码运行次数:0
复制
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;


@Mapper
public interface OrderConvert {

  OrderConvert INSTANCE = Mappers.getMapper(OrderConvert.class);

  @Mappings(
      value = {
        @Mapping(source = "conName", target = "name"),
        @Mapping(source = "orgCode", target = "orgId"),
        @Mapping(
            target = "payFee",
            expression = "java(payFeeFormat(orderVo.getConMoney()))"),
      })
  ThirdOrderVo toThirdOrderVo(ConOrderVo orderVo);

  default String payFeeFormat(String number) {
    var multiplied = NumberUtil.mul(Double.parseDouble(number), 100);
    return NumberUtil.round(multiplied, 0).toPlainString();
  }
}

预期应该是:

只有payFee属性应用了payFeeFormat方法。

实际是,所有类型为String的属性都应用了payFeeFormat方法,导致payFeeFormat方法里面的转换double抛出异常(不抛异常得多久才能发现...)。

MapStruct填坑

那怎么处理?

目前我采用了修改payFeeFormat的入参,比如我在expression中提前将number转换为double类型。

修改后的片段:

代码语言:javascript
代码运行次数:0
复制
   @Mappings(
      value = {
        @Mapping(source = "conName", target = "name"),
        @Mapping(source = "orgCode", target = "orgId"),
        @Mapping(
            target = "payFee",
            expression = "java(payFeeFormat(Double.parseDouble(orderVo.getConMoney())))"),
      })
  ThirdOrderVo toThirdOrderVo(ConOrderVo orderVo);

  default String payFeeFormat(double number) {
    var multiplied = NumberUtil.mul(number, 100);
    return NumberUtil.round(multiplied, 0).toPlainString();
  }

目前看是能正常使用了,假如有多个double类型字段怎么办?

别走!转角遇到惊喜

千辛万苦(千载难逢),在官方找到了这个issue(①):

具体解决方案就是,在自定义方法上面增加@Named注解,仅限特定属性使用就可以了。

完整代码如下:

代码语言:javascript
代码运行次数:0
复制
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;

@Mapper
public interface OrderConvert {

  @Mappings(
      value = {
        @Mapping(source = "conName", target = "name"),
        @Mapping(source = "orgCode", target = "orgId"),
        @Mapping(
            target = "payFee",
            expression = "java(payFeeFormat(orderVo.getConMoney()))"),
      })
  ThirdOrderVo toThirdOrderVo(ConOrderVo orderVo);

  @Named("payFee")
  default String payFeeFormat(double number) {
    var multiplied = NumberUtil.mul(number, 100);
    return NumberUtil.round(multiplied, 0).toPlainString();
  }

}

这个办法好,Java好啊,Java还是得学啊。

[手动脑补表情图(英语好啊,这英语得学)]

总结一下,根据issue的内容:

官方认为,如果你定义了一个入参及返回值,与某个属性一致的方法,MapStruct就会"物尽其用"。

只是,这"物尽其用"让人有点哭笑不得😂


①:官方issue

https://github.com/mapstruct/mapstruct/issues/3548

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 锤子代码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档