FastJson序列化和反序列化问题记录

序列化与反序列化问题

调用外部接口,http://100.111.55.67:9999/cmdb/v0.2.0/departments?page_size=1000,返回数据格式如下:

{
    "code": 0,
    "content": [
        {
            "id": "4561",
            "level": 1,
            "name": "业务后台",
            "parent_id": "1",
            "parent_name": "信仰科技"
        }
    ],
    "msg": "success"
}

居然是下划线命名的。现在需要将该接口包一层,然后暴露给前端。前后端的开发规范是返回驼峰命名的数据。

直接使用JSONObject解析也行,但是较好的方式是定义一个POJO,并加上注解@JSONField

@Data
public class CmdbModel {
    private Integer id;
    private Integer level;
    private String name;
    @JSONField(name = "parent_id")
    private Integer parentId;
    @JSONField(name = "parent_name")
    private String parentName;
}
@Data
private static class Resp {
    private Integer code;
    private List<CmdbModel> content;
    private String msg;
}

Service层代码就是一个简单的HTTP Get,然后JSONObject反序列化解析定义的POJO class类。

@Override
public List<CmdbModel> listDepartment() {
    String url = cmdbUrl + DEPARTMENTS;
    try {
        Resp resp = JSONObject.parseObject(HttpUtil.doGet(url), Resp.class);
        if (resp != null && resp.getCode() == 0) {
            return resp.getContent();
        }
    } catch (Exception e) {
        log.error("listDepartment failed: ", e);
    }
    return Collections.emptyList();
}

此处返回的数据肯定就是驼峰命名的。

Controller层接口

@RequestMapping("listDepartment")
public String listDepartment() {
    return JSONObject.toJSONString(ServiceUtil.returnSuccessData(cmdbService.listDepartment()));
}

问题:Postman调用此接口,发现数据居然和最原始的外部接口的数据一样,是下划线命名。

使用的依赖及其版本号:

<dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.73</version>
 </dependency>

原因:ServiceUtil.returnSuccessData返回的是Map<String, Object>类型的数据,JSONObject.toJSONString将Map序列化时,发现有@JSONField注解,然后又把驼峰命名转换为下划线命名。

能不能从@JSONField注解入手解决问题?

看看@JSONField源码:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface JSONField {
    int ordinal() default 0;

    String name() default "";

    String format() default "";

    boolean serialize() default true;

    boolean deserialize() default true;

    SerializerFeature[] serialzeFeatures() default {};

    Feature[] parseFeatures() default {};

    String label() default "";

    boolean jsonDirect() default false;

    Class<?> serializeUsing() default Void.class;

    Class<?> deserializeUsing() default Void.class;

    String[] alternateNames() default {};

    boolean unwrapped() default false;

    String defaultValue() default "";
}

期望效果:反序列化时把下划线反序列化为驼峰命名,随后返回前端的String需要经过一次序列化过程,序列化时保留驼峰命名。

实验:
注解加上serialize配置得到:@JSONField(name = "parent_id", serialize = false),直接忽视此字段。

看样子,无法从此注解入手解决问题???

另外,不知道另外一个据说比fastjson更强大,版本发布频率强力碾压fastjson的JSON工具jackson,怎么解决这个"问题"?

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.1</version>
</dependency>

解决方法:再定义一个VO,CmdbVo的字段和CmdbModel的字段一模一样,只是没有@JSONField注解,然后使用BeanUtils进行数据赋值:

List<CmdbVo> cmdbVoList = Lists.newArrayListWithCapacity(resp.getContent().size());
resp.getContent().forEach(x -> {
    CmdbVo vo = new CmdbVo();
    BeanUtils.copyProperties(x, vo);
    cmdbVoList.add(vo);
});
posted @ 2022-01-15 16:34  johnny233  阅读(176)  评论(0编辑  收藏  举报  来源