[FEATURE] 当对象中含有BigInteger类型的字段时,没有办法在全局设置中强制转换String
@Data
public static class test {
int a = 1;
Integer b = 2;
long c = 1;
Long d = 1123123213213123213L;
//@JSONField(serializeUsing = BigIntegerToStringSerializer.class)
BigInteger e = new BigInteger("123");
}
public static void main(String[] args) {
FastJsonConfig jsonConfig = new FastJsonConfig();
jsonConfig.setWriterFeatures();
ObjectWriterProvider objectWriterProvider=new ObjectWriterProvider();
objectWriterProvider.register(Long.class, ObjectWriters.ofToString(Object::toString));
JSONWriter.Context context= JSONFactory.createWriteContext(objectWriterProvider);
JSON.config(JSONWriter.Feature.WriteLongAsString);
//JSON.config(JSONWriter.Feature.WriteNonStringValueAsString);
//JSON.config(JSONWriter.Feature.BrowserCompatible);
JSON.register(Long.class, ObjectWriters.ofToString(Object::toString));
JSON.register(Long.TYPE, ObjectWriters.ofToString(Object::toString));
JSON.register(BigInteger.class, ObjectWriters.ofToString(Object::toString));
String json1 = JSONObject.toJSONString(new test());
log.info(json1);
}
输出结果{"a":1,"b":2,"c":"1","d":"1123123213213123213","e":123}
JSONWriter.Feature.WriteNonStringValueAsString和JSONWriter.Feature.BrowserCompatible虽然能部分实现,但是会引入更多的问题,一个会强制把所有的对象都转为字符串,另一个则是为了适配浏览器兼容只会把超过9007199254740991和小于-9007199254740991的转为string,而且空值还会按 JSON 标准输出 null/undefined
看了下源码,序列化时最终会进入JSONWriterUTF16.writeBigInt方法,其中有个isWriteAsString来判断是否转为String
protected static boolean isWriteAsString(BigDecimal value, long features) { return (features & MASK_WRITE_NON_STRING_VALUE_AS_STRING) != 0 || ((features & MASK_BROWSER_COMPATIBLE) != 0 && !isJavaScriptSupport(value)); }
只有JSONWriter.Feature.WriteNonStringValueAsString或者JSONWriter.Feature.BrowserCompatible并且超出了9007199254740991范围才会转String
希望能增加一个JSONWriter.Feature.WriteBigIntegerAsString的枚举和判断条件,或者有其他的方法请告知一下,不胜感激
我查了下源码,全局注册字段级别序列化器,对于Java内置类型,仅支持下面几种(不清楚是否为 bug):
protected ObjectWriter getInitWriter(ObjectWriterProvider provider, Class fieldClass) {
if (fieldClass == Date.class) {
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DATE_MASK) != 0) {
ObjectWriter objectWriter = provider.cache.get(fieldClass);
if (objectWriter != ObjectWriterImplDate.INSTANCE) {
return objectWriter;
}
}
} else if (fieldClass == int.class || fieldClass == Integer.class) {
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT32_MASK) != 0) {
ObjectWriter objectWriter = provider.cache.get(Integer.class);
if (objectWriter != ObjectWriterImplInt32.INSTANCE) {
return objectWriter;
}
}
} else if (fieldClass == long.class || fieldClass == Long.class) {
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_INT64_MASK) != 0) {
ObjectWriter objectWriter = provider.cache.get(Long.class);
if (objectWriter != ObjectWriterImplInt64.INSTANCE) {
return objectWriter;
}
}
} else if (fieldClass == BigDecimal.class) {
if ((provider.userDefineMask & ObjectWriterProvider.TYPE_DECIMAL_MASK) != 0) {
ObjectWriter objectWriter = provider.cache.get(fieldClass);
if (objectWriter != ObjectWriterImplBigDecimal.INSTANCE) {
return objectWriter;
}
}
} else if (Enum.class.isAssignableFrom(fieldClass)) {
ObjectWriter objectWriter = provider.cache.get(fieldClass);
if (!(objectWriter instanceof ObjectWriterImplEnum)) {
return objectWriter;
}
}
return null;
}
是的,fastjson是可以的,这次搞升级太难了,目前看实现两个地方最好都能加一下
增加biginteger的支持或者有别的方法麻烦提醒我一下,这个情况目前是完全没法绕过了,感谢
感谢
请问这个功能大概什么时候能发到下个版本呢
另外能否增加一个JSONWriter.Feature.WriteBigIntegerAsString,来实现局部的序列化设置
您可以暂时用这种方式替代吗?(为每个 JavaBean 的 BigInteger 属性手动指定序列化器)
public class TestData {
@JSONField(serializeUsing = XxxWriter.class)
BigInteger b = new BigInteger("123");
}
可以的,希望后续版本可以加上,这个场景目前不多
同样需要增加一个:JSONWriter.Feature.WriteBigDecimalAsString
另外能不能引入一个像是fastjson中的SerializeConfig,这样自由度更高吧,可以在局部序列化中自由配置,为什么把这个给去掉了呢。。。
另外能不能引入一个像是fastjson中的SerializeConfig,这样自由度更高吧,可以在局部序列化中自由配置,为什么把这个给去掉了呢。。。
需要配置什么呢?2.x中的替代方案应该是 ObjectWriterProvider:
在消息转换器中,FastJsonHttpMessageConverter怎么使用ObjectWriterProvider呢
在消息转换器中,FastJsonHttpMessageConverter怎么使用ObjectWriterProvider呢
可以通过JSONWriter.Context对象传入配置吧:
JSONWriter.Context context = JSONFactory.createWriteContext();
context.config(xxx);
context.config只能使用固定的那些Feature,没法自定义,目前主要就是消息转换器这里的问题,1里面是可以在SerializeConfig里面配置Serializer的
直接全局注册 JSONFactory.register(class, serializer) 可以吗
另外我刚才这样试过了也是不行的 FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setWriterFeatures(
JSONWriter.Feature.PrettyFormat,
JSONWriter.Feature.WriteMapNullValue
);
ObjectWriterProvider provider = fastJsonConfig.writerContext().getProvider();
provider.register(BigInteger.class, ObjectWriters.ofToString(Object::toString));
provider.register(Long.TYPE, ObjectWriters.ofToString(Object::toString));
provider.register(Long.class, ObjectWriters.ofToString(Object::toString));
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
System.out.println(JSON.toJSONString(new test(), fastJsonConfig.writerContext()));
JSONFactory.getDefaultObjectWriterProvider().register(BigInteger.class, ObjectWriters.ofToString(Object::toString));也不行 JSONFactory.register(class, serializer)没这个方法啊
JSON.register(class, serializer)(抱歉,我上面打错成 JSONFactory 了)
JSON.register(BigInteger.class, ObjectWriters.ofToString(Object::toString)); 这个试过,2.0.60还不行,应该要等你的提交发到下个版本才行
对了,看下这个是不是也是和上面一个问题,BigInteger没有按配置序列化
@Data
public static class test1 {
int a = 1;
Integer b = 2;
long c = 1;
Long d = 1123123213213123213L;
//@JSONField(serializeUsing = BigIntegerToStringSerializer.class)
BigInteger e = new BigInteger("123");
}
JSONWriter.Context context = new JSONWriter.Context();
ObjectWriterProvider provider = context.getProvider();
provider.register(BigInteger.class, ObjectWriters.ofToString(Object::toString));
provider.register(Long.TYPE, ObjectWriters.ofToString(Object::toString));
provider.register(Long.class, ObjectWriters.ofToString(Object::toString));
System.out.println(JSON.toJSONString(new test1(), context));
返回{"a":1,"b":2,"c":"1","d":"1123123213213123213","e":123}
问题是没有内置的能力可以支持BigInteger转String啊。。。有的话我也不会这么写。。。
我去想一下应该怎么实现,争取周三前给您答复
非常感谢,另外上面说的有点多,其实就两个需求,一个是希望能增加JSONWriter.Feature.WriteBigIntegerAsString,或者JSONWriter.Feature.WriteLongAsString同样能支持BigInteger,这个是局部的配置,另一个是provider.register(BigInteger.class, ObjectWriters.ofToString(Object::toString))不生效,我看你的提交已经实现了
我倾向于WriteNonStringValueAsString能够在BigInteger和BigDecimal这两个类型起作用,而不是引入这么大的改动
我倾向于WriteNonStringValueAsString能够在BigInteger和BigDecimal这两个类型起作用,而不是引入这么大的改动
WriteNonStringValueAsString 这个名词是否范围有点大了。
最小化改动,是否应该是:参照 WriteLongAsString 新增 WriteBigIntegerAsString 和 WriteBigDecimalAsString 。
那就把 WriteBigIntegerAsString 、 WriteBigDecimalAsString 、WriteNonStringValueAsString都加上,叫开发者自选,另外就是我看这个fix被关掉了,https://github.com/alibaba/fastjson2/pull/3876 ObjectWriterProvider provider = context.getProvider(); provider.register(BigInteger.class, ObjectWriters.ofToString(Object::toString));这个是不是还是不行呢
BigInteger value = BigInteger.valueOf(123456789);
JSON.config(JSONWriter.Feature.WriteNonStringValueAsString);
String str = JSON.toJSONString(value);
System.out.println(str);
BigInteger value = BigInteger.valueOf(123456789);
JSON.register(BigInteger.class, new ObjectWriter<BigInteger>() {
@Override
public void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {
jsonWriter.writeBigInt((BigInteger) object, JSONWriter.Feature.WriteNonStringValueAsString.mask);
}
});
String str = JSON.toJSONString(value);
System.out.println(str);
上面这两种使用方式能够满足你的需求么?
第一种不行,因为我是序列化整个对象,而不是只序列化BigInteger,这样会把所有的属性都转为String,我需要的是一个只转换BigInteger,所以我需要的是有一个WriteBigIntegerAsString 这样的Feature,在当我转向使用第二种方式的时候发现是不生效的,这个fix修复的就是这个问题,但是我看到它已经被关掉了,希望能合并到下个版本 https://github.com/alibaba/fastjson2/pull/3876,您可以看一下我最初提的问题,里面展示了最终的输出结果