jackson 實(shí)現(xiàn)null轉(zhuǎn)0 以及0轉(zhuǎn)null的示例代碼
需求背景
最近遇到一個(gè)需求,有個(gè)數(shù)值類型的字段,非必填,默認(rèn)為空,數(shù)據(jù)庫(kù)表針對(duì)該字段設(shè)計(jì)的是一個(gè)int類型, 由于dba推薦規(guī)范,默認(rèn)該值是not null。這個(gè)時(shí)候,問題就來(lái)了,數(shù)據(jù)庫(kù)默認(rèn)存的是0,前端展示時(shí),又不能顯示這個(gè)0(需要的是null)
解決方案
針對(duì)此類處理,通常的方案有以下2種:
前端做處理,統(tǒng)一對(duì)0和null做處理,0即是null,null即是0
后端做處理,針對(duì)要處理的字段,在序列化之前或者之后做處理,或者采取硬編碼的方式,針對(duì)要處理的字段,寫if else
方案分析
針對(duì)第一種,這里面有個(gè)比較尷尬的地方,前端所接收的字段中,有些0是有意義的,譬如是否有效,0可能代表有效,如果統(tǒng)一做了處理,那這個(gè)改為null了,那就出問題了。假如不統(tǒng)一處理,則需要區(qū)別對(duì)待,由于對(duì)前端不熟,不知道是否有類似注解或者帶標(biāo)志的全局方法來(lái)處理類似問題,聽前端說處理比較麻煩,so,只能后端來(lái)處理了。
針對(duì)第二種,后端處理的方式更靈活一些,想要簡(jiǎn)單可拓展,使用@JasonSerilize和@JsonDeserialize注解,寫自定義序列化和反序列化類。想要快速完成,走硬編碼。起初,因?yàn)閷?duì)jackson的序列化反序列化機(jī)制不太了解,寫的2個(gè)serializer和deserializer發(fā)布后也問題不斷,所以為了保證項(xiàng)目的進(jìn)展,采取了比較惡心的硬編碼的方式,寫了很多if else來(lái)做判斷
測(cè)試序列化
maven依賴:jackson版本2.9.7
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency>
序列化類:
@JacksonStdImpl public class ZeroToNullSerializer extends JsonSerializer implements ContextualSerializer { private Class<?> type; public ZeroToNullSerializer() { } public ZeroToNullSerializer(final JavaType type) { this.type = type == null ? Object.class : type.getRawClass(); } @Override public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if (o instanceof Short) { if (((Short) o).compareTo((short)0) == 0) { jsonGenerator.writeNull(); } else { jsonGenerator.writeNumber(((Short) o).shortValue()); } } if (o instanceof Integer) { if (((Integer) o).intValue() == 0) { jsonGenerator.writeNull(); } else { jsonGenerator.writeNumber(((Integer) o).intValue()); } } if (o instanceof Float) { if (((Float) o).compareTo(0f) == 0) { jsonGenerator.writeNull(); } else { jsonGenerator.writeNumber(((Float) o).floatValue()); } } if (o instanceof Double) { if (((Double) o).compareTo(0D) == 0) { jsonGenerator.writeNull(); } else { jsonGenerator.writeNumber(((Double) o).doubleValue()); } } if (o instanceof Long) { if (((Long) o).compareTo(0L) == 0) { jsonGenerator.writeNull(); } else { jsonGenerator.writeNumber(((Long) o).longValue()); } } if (o instanceof BigDecimal) { if (((BigDecimal) o).compareTo(BigDecimal.ZERO) == 0) { jsonGenerator.writeNull(); }else { jsonGenerator.writeNumber((BigDecimal) o); } } } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { return new ZeroToNullSerializer(property.getType()); } }
測(cè)試序列化的bean:
@Data public class TestSerializerBean { @JsonSerialize(using =ZeroToNullSerializer.class) private Integer number; private Integer age; private BigDecimal money; }
序列化Test:
@Test public void testSerializer() throws JsonProcessingException { TestSerializerBean serializerBean = new TestSerializerBean(); serializerBean.setNumber(0); serializerBean.setAge(0); serializerBean.setMoney(new BigDecimal(20)); String string = mapper.writeValueAsString(serializerBean); System.out.println(string); }
測(cè)試結(jié)果:
1、待測(cè)字段帶0:
2、待測(cè)字段不帶0
@Test public void testSerializer() throws JsonProcessingException { TestSerializerBean serializerBean = new TestSerializerBean(); serializerBean.setNumber(10); serializerBean.setAge(0); serializerBean.setMoney(new BigDecimal(20)); String string = mapper.writeValueAsString(serializerBean); System.out.println(string); }
測(cè)試反序列化
反序列化類(僅貼出核心代碼, 完整代碼我會(huì)上傳至github, 地址見后文鏈接):
@Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { if (this.type == Integer.class) { return handleInteger(p, ctxt); } if (this.type == Long.class) { return handleLong(p, ctxt); } if (this.type == BigDecimal.class) { return handleBigDecimal(p, ctxt); } if (this.type == Double.class) { return handleDouble(p, ctxt); } if (this.type == Float.class) { return handleFloat(p, ctxt); } if (this.type == Short.class) { return handleShort(p, ctxt); } throw new RuntimeException("反序列化錯(cuò)誤,類型" + type.toString() + "+不支持?jǐn)?shù)值類型的反序列化"); } private Object handleBigDecimal(JsonParser p, DeserializationContext ctxt) throws IOException { switch (p.getCurrentTokenId()) { case JsonTokenId.ID_NUMBER_INT: case JsonTokenId.ID_NUMBER_FLOAT: return p.getDecimalValue(); case JsonTokenId.ID_STRING: String text = p.getText().trim(); // note: no need to call `coerce` as this is never primitive if (text == null || text.length() == 0) { return getNullValue(ctxt); } try { return new BigDecimal(text); } catch (IllegalArgumentException iae) { } return (BigDecimal) ctxt.handleWeirdStringValue(type, text, "not a valid representation"); case JsonTokenId.ID_START_ARRAY: throw new RuntimeException("NullToZeroDeserializer handleBigDecimal error, encounter token " + JsonTokenId.ID_START_ARRAY); } // Otherwise, no can do: return (BigDecimal) ctxt.handleUnexpectedToken(type, p); } @Override public Object getNullValue(DeserializationContext ctxt) throws JsonMappingException { if (this.type == Integer.class) { return 0; } if (this.type == BigDecimal.class) { return BigDecimal.ZERO; } return 0; }
待反序列化的bean:
@Data public class TestDeSerializerBean{ private Integer number; @JsonDeserialize(using = NullToZeroDeserializer.class) private BigDecimal money; private BigDecimal balance; }
反序列化Test:
@Test public void testDeSerializer() throws IOException { TestDeSerializerBean serializerBean = new TestDeSerializerBean(); serializerBean.setNumber(5); serializerBean.setMoney(new BigDecimal(20)); String string = mapper.writeValueAsString(serializerBean); String testStr = "{\n" + " \"number\": 5,\n" + " \"money\": \"20.0\"\n" + "}"; TestDeSerializerBean deSerializerBean = mapper.readValue(testStr, TestDeSerializerBean.class); System.out.println(deSerializerBean); }
測(cè)試結(jié)果:
null類型:
@Test public void testDeSerializer() throws IOException { TestDeSerializerBean serializerBean = new TestDeSerializerBean(); serializerBean.setNumber(5); serializerBean.setMoney(new BigDecimal(20)); String string = mapper.writeValueAsString(serializerBean); String testStr = "{\n" + " \"number\": 5,\n" + " \"money\": \"\"\n" + "}"; TestDeSerializerBean deSerializerBean = mapper.readValue(testStr, TestDeSerializerBean.class); System.out.println(deSerializerBean); }
2. 非null類型
反序列化的類序列化null值時(shí),注意要重寫 getNullValue方法
總結(jié)
以上只是針對(duì)null轉(zhuǎn)0 以及0轉(zhuǎn)null寫的代碼,當(dāng)需要自定義的序列化時(shí),往往可以參考已有的serializer 和deserializer類,譬如DateDeserializer和DateSerializer,BigDecimalDeserializer和BigDecimalSerializer。參考這些以后的序列化與反序列化類,我們可以寫出任意想要的自定義的序列化和反序列化的效果
以上這篇jackson 實(shí)現(xiàn)null轉(zhuǎn)0 以及0轉(zhuǎn)null的示例代碼就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決springboot responseentity<string>亂碼問題
這篇文章主要介紹了解決springboot responseentity<string>亂碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07Java?Request獲取請(qǐng)求頭數(shù)據(jù)實(shí)例詳解
在開發(fā)中我們經(jīng)常需要獲取用戶IP地址,通過地址來(lái)實(shí)現(xiàn)一些功能,下面這篇文章主要給大家介紹了關(guān)于Java中Request獲取請(qǐng)求頭數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2024-01-01Java結(jié)構(gòu)型設(shè)計(jì)模式之橋接模式詳細(xì)講解
橋接,顧名思義,就是用來(lái)連接兩個(gè)部分,使得兩個(gè)部分可以互相通訊。橋接模式將系統(tǒng)的抽象部分與實(shí)現(xiàn)部分分離解耦,使他們可以獨(dú)立的變化。本文通過示例詳細(xì)介紹了橋接模式的原理與使用,需要的可以參考一下2022-09-09java利用CountDownLatch實(shí)現(xiàn)并行計(jì)算
這篇文章主要介紹了java利用CountDownLatch實(shí)現(xiàn)并行計(jì)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10使用Maven將springboot工程打包成docker鏡像
這篇文章主要介紹了使用Maven將springboot工程打包成docker鏡像,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12RabbitMQ實(shí)現(xiàn)消費(fèi)端限流的步驟
消費(fèi)者端限流的主要目的是控制消費(fèi)者每次從 RabbitMQ 中獲取的消息數(shù)量,從而實(shí)現(xiàn)消息處理的流量控制,這篇文章主要介紹了RabbitMQ如何實(shí)現(xiàn)消費(fèi)端限流,需要的朋友可以參考下2024-03-03Java實(shí)現(xiàn)發(fā)送郵件功能時(shí)碰到的坑
之前用163郵箱發(fā)郵件時(shí)明明是成功的,但是使用中國(guó)移動(dòng)自己的郵箱時(shí),無(wú)論如何在linux服務(wù)器中都發(fā)送不成功。下面小編給大家說下我是怎么解決的,一起看下吧2016-06-06