解决json字符串序列化后的顺序问题

1、应用场景:

如果项目中用到json字符串转为jsonObject的需求,并且,需要保证字符串的顺序转之前和转成jsonObject之后输出的结果完全一致。可能有点绕口,下面举一个应用场景的例子。

在做项目的过程中,需要写Junit单元测试,有一个方法如下:

@Test

@SuppressWarnings("unchecked")

public void facilitySoftwareQueryByPageExample() throws Exception {

facilitySoftwareRepository.deleteAll();

FacilitySoftwareConfig facilitySoftware = createFacilitySoftware();

facilitySoftwareRepository.save(facilitySoftware);

String userId = "1";

int pageNumber = 1;

int pageSize = 5;

String facilities = objectMapper.writeValueAsString(facilitySoftware);

LinkedHashMap<String, Object> jsonMap = JSON.parseObject(facilities,LinkedHashMap.class, Feature.OrderedField);

JSONArray jsonArray = new JSONArray();

JSONObject jsonObject = new JSONObject(true);

jsonObject.putAll(jsonMap);

jsonArray.add(jsonObject);

this.mockMvc

.perform(get("/v1/facilitysoftware/userid/" + userId + "/page/" + pageNumber

+ "/pagesize/" + pageSize + ""))

.andExpect(status().isOk()).andExpect(jsonPath("content",is(jsonArray)))

.andExpect(jsonPath("totalPages", is(1)))

.andExpect(jsonPath("totalElements", is(1)))

.andExpect(jsonPath("last", is(true)))

.andExpect(jsonPath("number", is(0)))

.andExpect(jsonPath("size", is(5)))

.andExpect(jsonPath("numberOfElements", is(1)))

.andExpect(jsonPath("first", is(true)))

.andDo(document("facilitySoftware-query-example"));

}

例子就在这里:

.andExpect(status().isOk()).andExpect(jsonPath("content",is(jsonArray)))

大家应该都能读懂,这行代码意思就是你用Api获取到的json字符串和你定义的字符串是否一致,一致则该条件测试通过。

这里的比较不仅仅要求所有的key和value都相同,而且需要保证两个json串的顺序完全相同,才可以完成该条件的测试。

查了资料解决途径过程如下:首先我们使用的是阿里的fastJson,需要引入fastJson的依赖,具体百度maven仓库,注意这里尽量使用稳定版本的较高版本。如 1.2.*

在解决问题过程中,遇到如下解决方案

1、在初始化json对象的时候加上参数true,这里不完全符合我们的需求,加上true之后,是让json串按照key的hashcode排序。

可以自定义升序或者降序,因为解决不了该场景的问题。这里不赘述,自行百度。

JSONObject jsonObject = new JSONObject(true);

2、解决问题,代码如下,第一个参数是需要转换的json字符串。

LinkedHashMap<String, Object> jsonMap = JSON.parseObject(facilities,LinkedHashMap.class, Feature.OrderedField);

JSONArray jsonArray = new JSONArray();

JSONObject jsonObject = new JSONObject(true);

jsonObject.putAll(jsonMap);

jsonArray.add(jsonObject);

补充:JSON 序列化key排序问题和序列化大小写问题

1. JSON 序列化key排序问题(fastjson)

import com.alibaba.fastjson.JSONObject;

import com.alibaba.fastjson.serializer.PropertyFilter;

import com.alibaba.fastjson.serializer.SerializerFeature;

//创建学生对象

Student student = new Student();

student.setName("小明");

student.setSex(1);

student.setAge(18);

//序列化 json key按字典排序

System.out.println(JSONObject.toJSONString(student ,SerializerFeature.MapSortField));

//过滤不要的key age

System.out.println(JSONObject.toJSONString(student , new PropertyFilter() {

public boolean apply(Object source, String name, Object value) {

if ("age".equals(name)) {

return false;

}

return true;

}

}, SerializerFeature.MapSortField));

2. JSON 序列化大小写问题(fastjson)

//学生类

import com.alibaba.fastjson.annotation.JSONField;

public class Student {

private String name;

private Integer sex;

private Integer age;

@JSONField(name = "Name") //用于序列化成json,key Name

public String getName() {

return name;

}

@JSONField(name = "Name") 用于json(Name)反序列化成学生对象

public void setName(String name) {

this.name = name;

}

public Integer getSex() {

return sex;

}

public void setSex(Integer sex) {

this.sex = sex;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

3. jackson 序列化大小写问题

@ResponseBody和@RequestBody中的序列化和反序列化就是用的jackson

//学生类

import com.fasterxml.jackson.annotation.JsonProperty;

public class Student {

@JsonProperty("Name")

private String name;

private Integer sex;

private Integer age;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Integer getSex() {

return sex;

}

public void setSex(Integer sex) {

this.sex = sex;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

//自己测试下

import com.fasterxml.jackson.databind.ObjectMapper;

import org.junit.Test;

@Test

public void test() throws Exception{

Student student = new Student();

student.setName("小明");

ObjectMapper MAPPER = new ObjectMapper();

//jackson序列化

String json = MAPPER.writeValueAsString(student);

System.out.println(json);

//jackson反序列化

Student student2 = MAPPER.readValue(json, Student.class);

System.out.println(student2.getName());

}

4. jackson 序列化null值的问题

fastjson序列化默认会去掉值为null的键值对

//在学生类上加上这个

方式一:(已经过时的方法)

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)

方式二:

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL)

5. jackson 反序列化忽略多余的json字段

import com.fasterxml.jackson.databind.DeserializationFeature;

MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

6. jackson 序列化忽略多余的json字段

方式一:

@JsonIgnoreProperties:该注解将在类曾级别上使用以忽略json属性。在下面的栗子中,我们将从albums的dataset中忽略“tag”属性;

@JsonIgnoreProperties({ "tags" })

方式二:

@JsonIgnore:该注释将在属性级别上使用以忽略特定属性;get方法上

@JsonIgnore

7. jackson 常用注解

@JsonAlias("Name") 反序列化时生效

private String name;

@JsonProperty("Name") 反序列化和序列化都时生效

private String name;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。如有错误或未考虑完全的地方,望不吝赐教。

以上是 解决json字符串序列化后的顺序问题 的全部内容, 来源链接: utcz.com/z/361478.html

回到顶部