jackson 实现null转0 以及0转null的示例代码

网友投稿 460 2022-11-19


jackson 实现null转0 以及0转null的示例代码

需求背景

最近遇到一个需求,有个数值类型的字段,非必填,默认为空,数据库表针对该字段设计的是一个int类型, 由于dba推荐规范,默认该值是not null。这个时候,问题就来了,数据库默认存的是0,前端展示时,又不能显示这个0(需要的是null)

解决方案

针对此类处理,通常的方案有以下2种:

前端做处理,统一对0和null做处理,0即是null,null即是0

后端做处理,针对要处理的字段,在序列化之前或者之后做处理,或者采取硬编码的方式,针对要处理的字段,写if else

方案分析

针对第一种,这里面有个比较尴尬的地方,前端所接收的字段中,有些0是http://有意义的,譬如是否有效,0可能代表有效,如果统一做了处理,那这个改为null了,那就出问题了。假如不统一处理,则需要区别对待,由于对前端不熟,不知道是否有类似注解或者带标志的全局方法来处理类似问题,听前端说处理比较麻烦,so,只能后端来处理了。

针对第二种,后端处理的方式更灵活一些,想要简单可拓展,使用@JasonSerilize和@jsonDeserialize注解,写自定义序列化和反序列化类。想要快速完成,走硬编码。起初,因为对jackson的序列化反序列化机制不太了解,写的2个serializer和deserializer发布后也问题不断,所以为了保证项目的进展,采取了比较恶心的硬编码的方式,写了很多if else来做判断

测试序列化

maven依赖:jackson版本2.9.7

com.fasterxml.jackson.core

jackson-databind

${jackson.version}

com.fasterxml.jackson.core

jackson-core

${jackson.version}

com.fasterxml.jackson.core

jackson-annotations

${jackson.version}

序列化类:

@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());

}

}

测试序列化的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.seIjHJKlotNumber(0);

serializerBean.setAge(0);

serializerBean.setMoney(new BigDecimal(20));

String string = mapper.writeValueAsString(serializerBean);

System.out.println(string);

}

测试结果:

1、待测字段带0:

2、待测字段不带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);

}

测试反序列化

反序列化类(仅贴出核心代码, 完整代码我会上传至github, 地址见后文链接):

@Override

public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {

if (this.type == Integer.class) {

return handleInteger(pIjHJKlo, 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("反序列化错误,类型" + type.toString() + "+不支持数值类型的反序列化");

}

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 priIjHJKlomitive

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);

}

测试结果:

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值时,注意要重写 getNullValue方法

总结

以上只是针对null转0 以及0转null写的代码,当需要自定义的序列化时,往往可以参考已有的serializer 和deserializer类,譬如DateDeserializer和DateSerializer,BigDecimalDeserializer和BigDecimalSerializer。参考这些以后的序列化与反序列化类,我们可以写出任意想要的自定义的序列化和反序列化的效果

代码地址


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:解决Jackson反序列化map,set等复杂类型问题
下一篇:Spring Security 中如何让上级拥有下级的所有权限(案例分析)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~