1. 程式人生 > 其它 >gson fastjson jackson_用好Jackson,操作Json節省一半時間

gson fastjson jackson_用好Jackson,操作Json節省一半時間

技術標籤:gson fastjson jackson

前言

目前解析Json的工具包有,Gson,FastJson,Jackson,Json-lib。綜合來看,Jackson的效能較優,穩定性也比較高,而且spring-boot-starter-web預設會引入Jackson包。因此介紹一下Jackson的使用。

Jackson目前有2個版本
1.x版本包名為org.codehaus.jackson
2.x版本包名為com.fasterxml.jackson

使用

在pom中加入如下依賴即可。

<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.9.2version>
dependency>

<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.2version>
dependency>

<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-annotationsartifactId>
<version>2.9.2version>
dependency>

前文說過,當使用spring-boot-starter-web模組時,會預設引入Jackson包,不必在pom中再次引入上面依賴

<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>

序列化

將java物件序列化成json,@Data註解是用lombok外掛來自動生成get和set方法

@Data
publicclassStudent{

/**名字*/
privateStringname;
/**年齡*/
privateIntegerage;
/**頭像*/
privateStringprofileImageUrl;
}

將常用的方法封裝成一個常用的工具類,如下所示,有2個好處

  1. ObjectMapper 類只會生成一個,節省空間

  2. 可以定義統一的配置(後面細說)

@Slf4j
publicclassJsonUtil{

privatestaticObjectMapperobjectMapper=newObjectMapper();

/**將物件轉為string*/
publicstaticStringobj2String(Tobj){if(obj==null){returnnull;
}try{returnobjinstanceofString?(String)obj:objectMapper.writeValueAsString(obj);
}catch(Exceptione){
log.warn("ParseObjecttoStringerror",e);returnnull;
}
}
}

先簡單介紹一下封裝的工具類

1. 將物件轉為json

publicstaticStringobj2String(Tobj){if(obj==null){returnnull;
}try{returnobjinstanceofString?(String)obj:objectMapper.writeValueAsString(obj);
}catch(Exceptione){
log.warn("ParseObjecttoStringerror",e);returnnull;
}
}

各種型別均可

@Test
publicvoidobj2String()throwsException{

Studentstudent=newStudent();
student.setAge(10);
student.setName("name");
student.setProfileImageUrl("link");
Stringresult=JsonUtil.obj2String(student);
//{"name":"name","age":10,"profileImageUrl":"link"}
System.out.println(result);

Map>map=newHashMap<>();
map.put("a",Arrays.asList(1,2,3));
map.put("b",Arrays.asList(1,2,3));
Stringresult1=JsonUtil.obj2String(map);//{"a":[1,2,3],"b":[1,2,3]}
System.out.println(result1);
}

2. 將物件轉為json,並格式化的輸出

publicstaticStringobj2StringPretty(Tobj){if(obj==null){returnnull;
}try{returnobjinstanceofString?(String)obj:objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
}catch(Exceptione){
log.warn("ParseObjecttoStringerror",e);returnnull;
}
}

@Test
publicvoidobj2StringPretty()throwsException{
Studentstudent=newStudent();
student.setAge(10);
student.setName("name");
student.setProfileImageUrl("link");
Stringresult=JsonUtil.obj2StringPretty(student);

/*
{
"name":"name",
"age":10,
"profileImageUrl":"link"
}
*/
System.out.println(result);

Map>map=newHashMap<>();
map.put("a",Arrays.asList(1,2,3));
map.put("b",Arrays.asList(1,2,3));
Stringresult1=JsonUtil.obj2StringPretty(map);/*
{
"a":[1,2,3],
"b":[1,2,3]
}
*/
System.out.println(result1);
}

反序列化

將json轉為java物件

方式1

publicstaticTstring2Obj(Stringstr,Classclazz){if(StringUtils.isEmpty(str)||clazz==null){returnnull;
}try{returnclazz.equals(String.class)?(T)str:objectMapper.readValue(str,clazz);
}catch(Exceptione){
log.warn("ParseStringtoObjecterror",e);returnnull;
}
}

基本型別的轉換

@Test
publicvoidstring2Obj()throwsException{
Stringstr="{\"name\":\"name\",\"age\":10,\"profileImageUrl\":\"link\"}";
Studentstudent=JsonUtil.string2Obj(str,Student.class);
//Student(name=name,age=10,profileImageUrl=link)
System.out.println(student);
}

各種複雜型別的轉換,示例1

@Test
publicvoidstring2Obj1()throwsException{

Studentstudent1=newStudent();
student1.setAge(10);
student1.setName("name1");
student1.setProfileImageUrl("link1");

Studentstudent2=newStudent();
student2.setAge(20);
student2.setName("name2");
student2.setProfileImageUrl("link2");

ListstudentList=newArrayList<>();
studentList.add(student1);
studentList.add(student2);
Stringresult=JsonUtil.obj2String(studentList);//[{"name":"name1","age":10,"profileImageUrl":"link1"},{"name":"name2","age":20,"profileImageUrl":"link2"}]
System.out.println(result);
ListfinalList=JsonUtil.string2Obj(result,List.class);//[{name=name1,age=10,profileImageUrl=link1},{name=name2,age=20,profileImageUrl=link2}]
System.out.println(finalList);
}

複雜型別的轉換,示例2

@Test
publicvoidstring2Obj2()throwsException{

Map>testMap=newHashMap<>();
testMap.put("1",Arrays.asList(1,2,3));
testMap.put("2",Arrays.asList(2,3,4));
Stringresult=JsonUtil.obj2String(testMap);//{"1":[1,2,3],"2":[2,3,4]}
System.out.println(result);
Map>finalMap=JsonUtil.string2Obj(result,Map.class);//{1=[1,2,3],2=[2,3,4]}
System.out.println(finalMap);
}

到現在為止,你可以用這3個函式進行序列化和反序列化操作

/**將物件轉為json*/
publicstaticStringobj2String(Tobj)/**將物件轉為json,並格式化顯示*/publicstaticStringobj2StringPretty(Tobj)/**將json轉為物件*/publicstaticTstring2Obj(Stringstr,Classclazz)

可能你還看過其他型別的解析方式,如下所示,但是沒有必要,上面3個函式完全能滿足你的需求,我這裡演示一下

方式2

publicstaticTstring2Obj(Stringstr,TypeReferencetypeReference){if(StringUtils.isEmpty(str)||typeReference==null){returnnull;
}try{return(T)(typeReference.getType().equals(String.class)?str:objectMapper.readValue(str,typeReference));
}catch(Exceptione){
log.warn("ParseStringtoObjecterror",e);returnnull;
}
}

@Test
publicvoidstring2Obj3()throwsException{

Studentstudent1=newStudent();
student1.setAge(10);
student1.setName("name1");
student1.setProfileImageUrl("link1");

Studentstudent2=newStudent();
student2.setAge(20);
student2.setName("name2");
student2.setProfileImageUrl("link2");

ListstudentList=newArrayList<>();
studentList.add(student1);
studentList.add(student2);
Stringresult=JsonUtil.obj2String(studentList);//[{"name":"name1","age":10,"profileImageUrl":"link1"},{"name":"name2","age":20,"profileImageUrl":"link2"}]
System.out.println(result);
ListfinalList=JsonUtil.string2Obj(result,newTypeReference>(){});//[{name=name1,age=10,profileImageUrl=link1},{name=name2,age=20,profileImageUrl=link2}]
System.out.println(finalList);
}

方式3

publicstaticTstring2Obj(Stringstr,Class>collectionClass,Class>...elementClasses){
JavaTypejavaType=objectMapper.getTypeFactory().constructParametricType(collectionClass,elementClasses);try{returnobjectMapper.readValue(str,javaType);
}catch(Exceptione){
log.warn("ParseStringtoObjecterror",e);returnnull;
}
}

@Test
publicvoidstring2Obj4()throwsException{

Studentstudent1=newStudent();
student1.setAge(10);
student1.setName("name1");
student1.setProfileImageUrl("link1");

Studentstudent2=newStudent();
student2.setAge(20);
student2.setName("name2");
student2.setProfileImageUrl("link2");

ListstudentList=newArrayList<>();
studentList.add(student1);
studentList.add(student2);
Stringresult=JsonUtil.obj2String(studentList);//[{"name":"name1","age":10,"profileImageUrl":"link1"},{"name":"name2","age":20,"profileImageUrl":"link2"}]
System.out.println(result);
ListfinalList=JsonUtil.string2Obj(result,List.class,Student.class);//[{name=name1,age=10,profileImageUrl=link1},{name=name2,age=20,profileImageUrl=link2}]
System.out.println(finalList);
}

常用註解及配置

@JsonIgnore忽略屬性

@Data
publicclassStudent{

/**名字*/
privateStringname;
/**年齡*/
privateIntegerage;
/**頭像*/
@JsonIgnore
privateStringprofileImageUrl;
}

@Test
publicvoidjsonIgnore()throwsException{
Studentstudent=newStudent();
student.setAge(10);
student.setName("name");
student.setProfileImageUrl("link");
Stringresult=JsonUtil.obj2String(student);
//{"name":"name","age":10}
System.out.println(result);

Stringstr="{\"name\":\"name\",\"age\":10,\"profileImageUrl\":\"link\"}";
Studentstudent1=JsonUtil.string2Obj(str,Student.class);
//Student(name=name,age=10,profileImageUrl=null)
System.out.println(student1);
}

@JsonProperty

當Json的屬性值和Java的屬性值不一樣時,會對映失敗,用這個註解指定對映關係,在屬性上用這個註解,則序列化和反序列化都會用這個值。如果序列化和反序列化的屬性不一致,可以在get方法或者set方法上用這個註解,set方法影響反序列化,get方法影響序列化。

去掉@Data註解

publicclassStudent{

/**名字*/
privateStringname;
/**年齡*/
privateIntegerage;
/**頭像*/
privateStringprofileImageUrl;

@JsonProperty("getImage")
publicStringgetProfileImageUrl(){
returnprofileImageUrl;
}

@JsonProperty("setImage")
publicvoidsetProfileImageUrl(StringprofileImageUrl){
this.profileImageUrl=profileImageUrl;
}

}

@Test
publicvoidjsonProperty()throwsException{

Stringstr="{\"name\":\"name\",\"age\":10,\"setImage\":\"link\"}";
Studentstudent1=JsonUtil.string2Obj(str,Student.class);
//name
System.out.println(student1.getName());
//10
System.out.println(student1.getAge());
//link
System.out.println(student1.getProfileImageUrl());
//{"name":"name","age":10,"getImage":"link"}
System.out.println(JsonUtil.obj2String(student1));
}

@JsonFormat

日期格式化註解,不再演示

@JsonIgnoreProperties(ignoreUnknown = true)

如果json字串中的屬性個數小於java物件中的屬性個數,可以順利轉換,java中多的那個屬性為null

如果json字串中出現java物件中沒有的屬性,則在將json轉換為java物件時會報錯:Unrecognized field, not marked as ignorable

解決方法1:
在目標物件的類級別上添加註解:@JsonIgnoreProperties(ignoreUnknown = true)

解決方法2:

@Slf4j
publicclassJsonUtil{

privatestaticObjectMapperobjectMapper=newObjectMapper();

static{
//忽略 在json字串中存在,但是在java物件中不存在對應屬性的情況。防止錯誤
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
}

}

這樣就不用在目標類上加@JsonIgnoreProperties屬性了,體現了全域性配置的優勢,配置項很多,包括格式化顯示日期等,不再詳細介紹,百度配置即可

用Tree Mode方式解析JSON

除了將json轉為物件外,還可以用Tree Mode方式解析JSON,全程無腦操作,除了一些特別複雜的JSON,或者只取JSON中的一部分,千萬不要用這種二B方式解析JSON。正確的方式是將JSON直接轉為物件。我這裡演示一下解析的方式

{
"name":"zhansan",
"age":100,
"schools":[
{
"name":"tsinghua",
"location":"beijing"
},
{
"name":"pku",
"location":"beijing"
}
]
}

@Test
publicvoidparseJson()throwsException{
StringjsonStr="{\"name\":\"zhansan\",\"age\":100,\"schools\":[{\"name\":\"tsinghua\",\"location\":\"beijing\"},{\"name\":\"pku\",\"location\":\"beijing\"}]}";

ObjectMapperobjectMapper=newObjectMapper();
JsonNodejsonNode=objectMapper.readTree(jsonStr);

Stringname=jsonNode.get("name").asText();
intage=jsonNode.get("age").asInt();
//nameiszhansanageis100
System.out.println("nameis"+name+"ageis"+age);

JsonNodeschoolsNode=jsonNode.get("schools");
for(inti=0;iStringschooleName=schoolsNode.get(i).get("name").asText();
StringschooleLocation=schoolsNode.get(i).get("location").asText();
//schooleNameistsinghuaschooleLocationisbeijing
//schooleNameispkuschooleLocationisbeijing
System.out.println("schooleNameis"+schooleName+"schooleLocationis"+schooleLocation);
}
}

推薦閱讀:

【漫畫】TCP連線為什麼是三次握手,而不是兩次握手,也不是四次握手?

裝飾者模式在JDK和Mybatis中是怎麼應用的?

MySQL索引優化實戰

Java識堂

一個有乾貨的公眾號


98ee8c41227a6969fb232634b9bc4be5.png