fastjson @JSONField(serializeUsing = XXX.class)自定义Serializer bug

kqqjbcuj  于 2022-10-27  发布在  其他
关注(0)|答案(7)|浏览(376)

public class Test { private String name; @JSONField(serializeUsing = ToStringSerializer.class) private Integer age; public static void main(String[] args) { Test test = new Test(); test.setName("张三"); test.setAge(null); System.out.println(JSON.toJSONString(test)); } // get set }

上面不会进入ToStringSerializer.writer 方法。

//这里不会执行
if (object == null) { out.writeNull(); }

ttcibm8c

ttcibm8c1#

版本1.2.76也不行

qyzbxkaa

qyzbxkaa2#

请问对于

public class Test {
  private String name;
  @JSONField(serializeUsing = ToStringSerializer.class)
  private Integer age;
  public static void main(String[] args) {
    Test test = new Test();
    test.setName("张三");
    test.setAge(null);
    System.out.println(JSON.toJSONString(test));
  }
// get set
}

你想要的预期效果是这样的吗: {"age":"null","name":"张三"}

syqv5f0l

syqv5f0l3#

@Tloops 我的预期是当age 为null 时,能进入ToStringSerializer里面的write方法。
因为方法里面有一段代码
if (object == null) { out.writeNull(); }
但是现在这种null情况不会进入这个序列化方法,所以,上面这段代码是不会生效的。(ToStringSerializer是fastjson自带的,其他自定义序列化方法也是不会有null情况进入。)所以我觉得这是一个bug

ykejflvf

ykejflvf4#

从源码跟了一下,现在的代码,对于null值处理时,针对Number、String、Boolean、Collection这四种类型是不支持JSONField.serializeUsing的(这里是做特例处理造成的,不知道是否有什么考量)

有两段相关代码
1.JavaBeanSerializer中,对于属性值为null处理时,会特殊处理几个特定类型,对于这里相关的Number.class类型处理时,会优先考虑定义的特性(SerializerFeature),如果null不写则直接跳过处理,所以也就不会再进注解自定义的处理器,相关代码为
JavaBeanSerializer 350行 } else if (Number.class.isAssignableFrom(fieldClass)) { int defaultMask = SerializerFeature.WriteNullNumberAsZero.mask; final int mask = defaultMask | SerializerFeature.WriteMapNullValue.mask; if ((!writeAsArray) && (serialzeFeatures & mask) == 0 && (out.features & mask) == 0) { continue; }

2.如果这里我们开启WriteMapNullValue,执行了FieldSerializer(实现JSONField处理的地方)了,则会因为下述代码直写null而不触发JSONField.serializeUsing 的处理逻辑

//FieldSerializer 233行 if (Number.class.isAssignableFrom(runtimeFieldClass)) { out.writeNull(features, SerializerFeature.WriteNullNumberAsZero.mask); return; } else if (String.class == runtimeFieldClass) { out.writeNull(features, SerializerFeature.WriteNullStringAsEmpty.mask); return; } else if (Boolean.class == runtimeFieldClass) { out.writeNull(features, SerializerFeature.WriteNullBooleanAsFalse.mask); return; } else if (Collection.class.isAssignableFrom(runtimeFieldClass) || runtimeFieldClass.isArray()) { out.writeNull(features, SerializerFeature.WriteNullListAsEmpty.mask); return; }

mrzz3bfm

mrzz3bfm5#

从源码跟了一下,现在的代码,对于null值处理时,针对Number、String、Boolean、Collection这四种类型是不支持JSONField.serializeUsing 的(这里是做特例处理造成的,不知道是否有什么考量)

有两段相关代码
1.JavaBeanSerializer中,对于属性值为null处理时,会特殊处理几个特定类型,对于这里相关的Number.class类型处理时,会优先考虑定义的特性(SerializerFeature),如果null不写则直接跳过处理,所以也就不会再进注解自定义的处理器,相关代码为
JavaBeanSerializer 350行 } else if (Number.class.isAssignableFrom(fieldClass)) { int defaultMask = SerializerFeature.WriteNullNumberAsZero.mask; final int mask = defaultMask | SerializerFeature.WriteMapNullValue.mask; if ((!writeAsArray) && (serialzeFeatures & mask) == 0 && (out.features & mask) == 0) { continue; }

2.如果这里我们开启WriteMapNullValue,执行了FieldSerializer(实现JSONField处理的地方)了,则会因为下述代码直写null而不触发JSONField.serializeUsing 的处理逻辑

//FieldSerializer 233行 if (Number.class.isAssignableFrom(runtimeFieldClass)) { out.writeNull(features, SerializerFeature.WriteNullNumberAsZero.mask); return; } else if (String.class == runtimeFieldClass) { out.writeNull(features, SerializerFeature.WriteNullStringAsEmpty.mask); return; } else if (Boolean.class == runtimeFieldClass) { out.writeNull(features, SerializerFeature.WriteNullBooleanAsFalse.mask); return; } else if (Collection.class.isAssignableFrom(runtimeFieldClass) || runtimeFieldClass.isArray()) { out.writeNull(features, SerializerFeature.WriteNullListAsEmpty.mask); return; }

看源码下来有一个体验就是... 现在的实现里特例处理的情景太多了,而且没有注解说明,不知道因为什么考量引入的特例处理... ... 这就导致了能看清楚引发问题的逻辑是什么... ... 但是不敢改..

izj3ouym

izj3ouym6#

回归到这个问题的解决办法,个人觉得有一个方案是
1.业务上设定 0、null、空值同一个业务含义
2.然后就是转不转出来都没关系了.... 需要转出来null的话,用
JSON.toJSONString(test, SerializerFeature.WriteMapNullValue)
这种写法即可

jqjz2hbq

jqjz2hbq7#

@RLin2015New 仔细看了你的解析,非常感谢你的回答。我原先的需求是。对于Number类型的字段。在serializeUsing时,可以生成一个新的字段(比如BigDecimal amount 生成String amountStr = "5")。用于前端展示,解决浮点数精度丢失问题。后面发现这个null时不进入,也就不能适配null的情况。所以也就用其他方法代替。

相关问题