fastjson与lombok一起用出现序列化问题

文章内部信息已脱敏。

有一次在测试环境调用网易电子签章平台的接口,用来生成印章图片。

首先用postman去测试接口,除了必传的固定请求头,请求体参数如下:

{
    "userId": "***********",
    "templateType": "STAR",
    "color": "RED",
    "hText": "合同专用章",
    "qText": "2023-01-17"   
}

返回的结果是印章图片的base64。转化为图片后是。
在这里插入图片描述

然后在java项目里去调用该接口,用了feign去调第三方平台接口。

但是发现返回的base64转化为图片后,始终是如下图,也就是传入的参数中hText(横向文)与qText(下旋文),这两个字段没有生效。

在这里插入图片描述

代码中的对象属性定义为:

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
public class EsignAddSealDTO {

    private String userId;

    private String templateType;

    private String color;

    private String hText;

    private String qText;
  }

仔细检查了代码,发现对象属性之类的代码并没有问题,那为什么这两个字段会没有生效呢?

由于postman接口可以返回正确的结果,并且java项目调用中也有返回,可以定位到还是传参对象出了问题。

EsignAddSealDTO req = EsignAddSealDTO.builder().userId("*************").templateType("STAR").color("RED")
        .hText("合同专用章").qText("2023-01-17").build();
System.out.println(JSONObject.toJSONString(req));

打印传参对象的json字符串,发现结果为:

{"HText":"合同专用章","QText":"2023-01-17","color":"RED","templateType":"STAR","userId":"*************"}

!! 序列化的json库采用的是fastjson,序列化后的json字符串中hText和qText竟然属性名首字母变为了大写。怪不得这两个字段没有生效。

项目中的fastjson版本是2.0.9。

看一下原因,首先,使用了lombok的@Data注解之后,默认生成的hText属性的get方法名变为了getHText(), qText属性的get方法名变为了getQText()。

而在fastjson中,获取属性名的方法是com.alibaba.fastjson2.util.BeanUtils#getterName。
源码debug如下:

其中mthodName入参为“getQText”,namingStrategy传参为null, 方法中修改设值为“CamelCase”。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这边可以看到源码中,对于get开头的方法名,如getQText,首先取get后的字符串为chars, 这里chars就是[Q, T, e, x, t]。

chars首字母为Q, 这时候做判断,如果第二个字符为大写,则直接返回chars为属性名;如果第二个字符为小写,则将首字母变为小写,再返回。这里由于第二个字符为T,因此这里直接返回QText为属性名。

再举例:如果方法名是getUserId,取chars为[U, s, e, r, I, d], 取首字母为U,因为第二个字符为小写,因此将首字母变为小写,返回userId为属性名。

因此getQText方法得到的属性名就是QText。而不是类定义的属性名qText。

知道原因后,就简单了,可以不使用lombok,而是直接生成get/set方法,

public String gethText() {
    return hText;
}

public void sethText(String hText) {
    this.hText = hText;
}

public String getqText() {
    return qText;
}

public void setqText(String qText) {
    this.qText = qText;
}

就可以返回正确属性名了。

注意:

使用@Data注解,即使在属性hText、qText上加上@JsonProperty注解,依旧不起作用。但是加在其他属性上时生效的,如在color上加注解,可以修改序列化后的属性名。

@Data
@Builder
public class EsignAddSealDTO {

    private String userId;

    private String templateType;

    @JsonProperty(value = "COLOR")
    private String color;

    @JsonProperty(value = "hText")
    private String hText;

    @JsonProperty(value = "qText")
    private String qText;

}

生成的序列化json字符串为:

{"COLOR":"RED","HText":"合同专用章","QText":"2023-01-17","templateType":"STAR","userId":"*************"}

附录: 浏览源码顺序:
com.alibaba.fastjson.JSON#toJSONString(java.lang.Object)
com.alibaba.fastjson2.JSONWriter.Context#getObjectWriter(java.lang.reflect.Type,java.lang.Class)
com.alibaba.fastjson2.writer.ObjectWriterProvider#getObjectWriter(java.lang.reflect.Type,
java.lang.Class, boolean)
com.alibaba.fastjson2.writer.ObjectWriterCreatorASM#createObjectWriter
com.alibaba.fastjson2.util.BeanUtils#getterName

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
fastjson2 中,可以通过以下方式来实现枚举的序列化以及反序列化: 1. 枚举的序列化 枚举类型默认会被序列化为该枚举常量的名称,可以通过实现 fastjson 序列化器接口来自定义枚举的序列化方式。例如,以下是一个将枚举类型序列化为枚举常量值的示例: ```java public class EnumSerializer implements ObjectSerializer { @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { if (object == null) { serializer.getWriter().writeNull(); return; } Enum<?> e = (Enum<?>) object; serializer.getWriter().writeValue(e.ordinal()); } } ``` 然后,在序列化时,可以将该序列化器指定给需要自定义序列化的枚举类型,例如: ```java SerializeConfig config = new SerializeConfig(); config.put(MyEnum.class, new EnumSerializer()); String json = JSON.toJSONString(myEnum, config); ``` 2. 枚举的反序列化 fastjson2 默认会将枚举类型反序列化为该枚举常量的名称,可以通过实现 fastjson序列化器接口来自定义枚举的反序列化方式。例如,以下是一个将枚举类型反序列化为枚举常量值的示例: ```java public class EnumDeserializer implements ObjectDeserializer { @Override public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { JSONObject jsonObject = parser.parseObject(); int ordinal = jsonObject.getIntValue("ordinal"); return (T) MyEnum.values()[ordinal]; } @Override public int getFastMatchToken() { return JSONToken.LBRACE; } } ``` 然后,在反序列化时,可以将该反序列化器指定给需要自定义反序列化的枚举类型,例如: ```java ParserConfig config = new ParserConfig(); config.putDeserializer(MyEnum.class, new EnumDeserializer()); MyEnum myEnum = JSON.parseObject(json, MyEnum.class, config); ``` 这样就可以实现枚举类型的自定义序列化以及反序列化了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值