gson fastjson jackson_用好Jackson,操作Json節省一半時間
前言
目前解析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個好處
ObjectMapper 類只會生成一個,節省空間
可以定義統一的配置(後面細說)
@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識堂
一個有乾貨的公眾號