抽象類使用Jackson序列化問題
抽象類使用Jackson序列化
當(dāng)java對(duì)象中含List<Object>時(shí),如果Object一個(gè)抽象類或接口,這里就會(huì)出現(xiàn)java多態(tài)的現(xiàn)象,比如List<Animal>, 如果Animal是個(gè)抽象類,并且有多個(gè)子類時(shí),由于List中保存的Animal沒有明確指向具體的子類或?qū)崿F(xiàn)類,json反序列化java對(duì)象時(shí)就會(huì)拋出提示:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException:Can not construct instance of Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
可以使用@JsonTypeInfo與@JsonSubTypes來解決此類問題,通過注解,可以在序列化時(shí),保存具體的類型信息到j(luò)son中,當(dāng)json反序列到j(luò)ava對(duì)象時(shí),就可以根據(jù)具體類型信息創(chuàng)建正確的java對(duì)象。
@JsonTypeInfo– indicates details of what type information to include in serialization 指出序列化包含的類型信息細(xì)節(jié)@JsonSubTypes– indicates sub-types of the annotated type 指出被注解類型的子類@JsonTypeName– defines a logical type name to use for annotated class 定義被注解類使用的邏輯名稱
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public class Animal {
public String name;
public Animal(String name) {
}
}
@JsonTypeName("dog")
// 這里在子類中指定的type name必須和抽象類中注解@JsonSubTypes中name屬性指定的值保持一致
public class Dog extends Animal {
public double barkVolume;
public Dog(String name) {
super(name);
barkVolume = 0.5;
}
}
@JsonTypeName("cat")
public class Cat extends Animal {
boolean likesCream;
public int lives;
public Cat(String name) {
super(name);
likesCream = true;
lives = 10;
}
}
@Test
public void whenSerializingPolymorphic_thenCorrect()
throws JsonProcessingException {
Zoo.Dog dog = new Zoo.Dog("lacy");
Zoo zoo = new Zoo(dog);
String result = new ObjectMapper()
.writeValueAsString(zoo);
assertThat(result, containsString("type"));
assertThat(result, containsString("dog"));
}
序列化zoo對(duì)象,結(jié)果如下:
{
"type":"dog",
"name":"lacy",
"barkVolume":0
}
@Test
public void whenDeserializingPolymorphic_thenCorrect()
throws IOException {
String json = "{\"name\":\"lacy\",\"type\":\"cat\"}";
Animal animal =
new ObjectMapper().readerFor(Animal.class).readValue(json);
assertEquals("lacy", animal.name);
assertEquals(Cat.class, animal.getClass());
}記一次jackson序列化Boolean的坑
@Data
public class CouponTemplateDto {
/**
* 優(yōu)惠券類型id
*/
private Long couponTypeId;
/**
* 優(yōu)惠券模板id
*/
private Long couponTemplateId;
/**
* 用戶id
*/
private Long userId;
/**
* 優(yōu)惠券描述
*/
private String description;
/**
* 面值,滿200減30,則此值為30
*/
private BigDecimal value;
/**
* 從次日起,多少天可用
*/
private Integer delayDays;
/**
* 從當(dāng)日起,多少天可用
*/
private Integer nowDays;
/**
* 滿多少可以減,滿200減30,則此值為200
*/
private BigDecimal fullAmount;
/**
* 券號(hào)
*/
private String couponNo;
/**
* 有效起始日期
*/
private Date startTime;
/**
* 失效日期
*/
private Date endTime;
/**
* 創(chuàng)建時(shí)間
*/
private Date createTime;
/**
* 使用日期
*/
private Date useTime;
/**
* 券使用狀態(tài):0-未使用 1-已使用 2-已過期
*/
private Integer couponUseStatus;
/**
* 過期前多少天提醒,默認(rèn)7天
*/
private Integer overDueRemind;
/**
* 優(yōu)惠券標(biāo)題
*/
private String title;
/**
* 優(yōu)惠券是否能開始使用
*/
// @JsonProperty("isStart")
private Boolean start;
/**
* 優(yōu)惠券是否過期
*/
// @JsonProperty("isEnd")
private Boolean end;
private Boolean getStart() {
return startTime.before(new Date());
}
private Boolean getEnd() {
return endTime.before(new Date());
}
}
我定義了一個(gè)這樣的類,我們項(xiàng)目用的是Spring Boot,默認(rèn)底層采用的是jackson序列化,但是在使用中出了一個(gè)問題private Boolean start跟private Boolean end這兩個(gè)字段一直無法序列化
總結(jié)排查思路如下
1.是boolean還是Boolean,到底是基本數(shù)據(jù)類型還是包裝類,如果是基本數(shù)據(jù)類型的話(包裝類可以使用,但是不推薦),不要使用is開頭。我們可以看看阿里巴巴規(guī)范中的這段話
【強(qiáng)制】POJO類中的任何布爾類型的變量,都不要加 is,否則部分框架解析會(huì)引起序列化錯(cuò)誤。
反例:定義為基本數(shù)據(jù)類型 boolean isSuccess;的屬性,它的方法也是 isSuccess(),RPC框架在反向解析的時(shí)候,“以為”對(duì)應(yīng)的屬性名稱是 success,導(dǎo)致屬性獲取不到,進(jìn)而拋出異常。
2.這個(gè)錯(cuò)誤也是我犯的錯(cuò)誤,我復(fù)寫了get方法,方法的訪問權(quán)限被設(shè)置成了private級(jí)別
解決方案:
- 加注解,@JsonProperty(“isEnd”)
- 將方法級(jí)別更正為public
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解析Spring事件發(fā)布與監(jiān)聽機(jī)制
本篇文章給大家介紹Spring事件發(fā)布與監(jiān)聽機(jī)制,通過 ApplicationEvent 事件類和 ApplicationListener 監(jiān)聽器接口,可以實(shí)現(xiàn) ApplicationContext 事件發(fā)布與處理,需要的朋友參考下吧2021-06-06
SpringCloud+Tornado基于jwt實(shí)現(xiàn)請(qǐng)求安全校驗(yàn)功能
這篇文章主要介紹了SpringCloud+Tornado基于jwt實(shí)現(xiàn)請(qǐng)求安全校驗(yàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
SpringBoot整合SpringSecurity和JWT和Redis實(shí)現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證
Spring Security是一個(gè)可以為Java應(yīng)用程序提供全面安全服務(wù)的框架,同時(shí)它也可以輕松擴(kuò)展以滿足自定義需求,本文主要介紹了SpringBoot整合SpringSecurity和JWT和Redis實(shí)現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證,感興趣的可以了解一下2023-11-11
Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解
這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解,當(dāng)一個(gè)對(duì)象發(fā)生數(shù)據(jù)變化時(shí),通知其他相關(guān)的一系列對(duì)象,接受到通知的對(duì)象根據(jù)該對(duì)象的變化進(jìn)行相應(yīng)處理以響應(yīng)變化的過程,需要的朋友可以參考下2023-12-12
SpringMVC用XML方式實(shí)現(xiàn)AOP的方法示例
這篇文章主要介紹了SpringMVC用XML方式實(shí)現(xiàn)AOP的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
SpringCloud feign微服務(wù)調(diào)用之間的異常處理方式
這篇文章主要介紹了SpringCloud feign微服務(wù)調(diào)用之間的異常處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Spring Boot 自動(dòng)配置的實(shí)現(xiàn)
這篇文章主要介紹了Spring Boot 自動(dòng)配置的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
springmvc+shiro自定義過濾器的實(shí)現(xiàn)代碼
這篇文章主要介紹了springmvc+shiro自定義過濾器的實(shí)現(xiàn)方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-10-10

