序列化与反序列化问题
调用外部接口,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);
});