fastjson2 icon indicating copy to clipboard operation
fastjson2 copied to clipboard

[BUG]JSONWriter.Feature.BrowserCompatible和Feature.WriteBigDecimalAsPlain是否有冲突,针对BigDecimal和BigInteger类型与预期不符

Open 805728578 opened this issue 1 year ago • 9 comments

问题描述

简要描述您碰到的问题。 问题1:设置JSONWriter.Feature.BrowserCompatible,接口返回BigDecimal和BigInteger类型均为字符串 问题2:不设置JSONWriter.Feature.BrowserCompatible,接口返回BigDecimal和BigInteger类型均为数字类型 问题3:不设置JSONWriter.Feature.BrowserCompatible且设置Feature.WriteBigDecimalAsPlain,接口返回BigDecimal和BigInteger类型均为数字类型,感觉Feature.WriteBigDecimalAsPlain不生效 问题4:设置JSONWriter.Feature.BrowserCompatible且设置Feature.WriteBigDecimalAsPlain,接口返回BigDecimal和BigInteger类型均为字符串

问题总结:有JSONWriter.Feature.BrowserCompatible特性,BigDecimal和BigInteger类型数据均反序列化为字符串;设置Feature.WriteBigDecimalAsPlain不生效,无法序列化BigDecimal和BigInteger类型数据为字符串

环境信息

请填写以下信息:

  • OS信息: [e.g.:CentOS 8.4.2105 4Core 3.10GHz 16 GB]
  • JDK信息: [e.g.:Openjdk 1.8.0_312]
  • 版本信息:[e.g.:Fastjson2 2.0.52]

重现步骤

如何操作可以重现该问题:

  1. 使用 xxx.xxx 方法
  2. 输入 ... 数据
  3. 出现 ... 错误

Controller类示例

	@GetMapping(value = "/mockData")
	public AjaxResult.Result<Object> mockData(@RequestParam("mock") Object mock){
		JSONObject result = new JSONObject();
		result.put("boolean", Boolean.TRUE);
		result.put("byte", Byte.MAX_VALUE);
		result.put("char", Character.MAX_VALUE);
		result.put("int", Integer.MAX_VALUE);
		result.put("long", Long.MAX_VALUE);
		result.put("float", Float.MAX_VALUE);
		result.put("double", Double.MAX_VALUE);
		result.put("datetime", LocalDateTime.now());
		result.put("date", LocalDate.now());
		result.put("time", LocalTime.now());
		result.put("timestamp", System.currentTimeMillis());
		result.put("nanotime", System.nanoTime());
		result.put("BigDecimal", new BigDecimal("12345678901234567890"));
//		result.put("BigReal", new BigReal("999999999"));
		result.put("BigInteger", BigInteger.valueOf(Long.MIN_VALUE));
		result.put("string", "为了适应行业用户数字化升级的新需求和保持产品技术的竞争力");
		result.put("round", new Random().nextLong());
		result.put("mock", mock);
		return success(ReturnInfo.OPERATION_SUCCESS_MSG, result);
	}

MVC配置示例

@Configuration
public class FastjsonGlobalConfigurer implements WebMvcConfigurer {
/**
	 * Fastjson默认写特性
	 */
	public static final JSONWriter.Feature[] FASTJSON_DEFAULT_WRITER_FEATURES = {JSONWriter.Feature.BrowserCompatible, JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteNullListAsEmpty, JSONWriter.Feature.WriteNullBooleanAsFalse, JSONWriter.Feature.WriteNulls,JSONWriter.Feature.WriteEnumsUsingName,JSONWriter.Feature.WritePairAsJavaBean,JSONWriter.Feature.IgnoreErrorGetter,JSONWriter.Feature.LargeObject};
	/**
	 * Fastjson默认读特性
	 */
	public static final JSONReader.Feature[] FASTJSON_DEFAULT_READER_FEATURES = {JSONReader.Feature.SupportSmartMatch, JSONReader.Feature.SupportArrayToBean, JSONReader.Feature.UseNativeObject, JSONReader.Feature.SupportClassForName,JSONReader.Feature.IgnoreSetNullValue,JSONReader.Feature.AllowUnQuotedFieldNames,JSONReader.Feature.IgnoreCheckClose,JSONReader.Feature.IgnoreAutoTypeNotMatch /* ,JSONReader.Feature.NonErrorOnNumberOverflow */ };
private FastJsonConfig defaultFastJsonConfig() {
		Charset charset = StandardCharsets.UTF_8;
		JSONWriter.Feature[] writerFeatures = FASTJSON_DEFAULT_WRITER_FEATURES;
		JSONReader.Feature[] readerFeatures = FASTJSON_DEFAULT_READER_FEATURES;
		// 创建配置类
		FastJsonConfig config = new FastJsonConfig();
		config.setWriterFeatures(writerFeatures);
		config.setReaderFeatures(readerFeatures);
		config.setCharset(charset);
		config.setDateFormat(DateUtils.DEFAULT_FORMAT_DATE_TIME);
		return config;
	}
	@Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        FastJsonJsonView view = new FastJsonJsonView();
        view.setFastJsonConfig(defaultFastJsonConfig());
        registry.enableContentNegotiation(view);
    }
	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
		Charset charset = StandardCharsets.UTF_8;
		FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
		converter.setFastJsonConfig(defaultFastJsonConfig());
		converter.setDefaultCharset(charset);
		List<MediaType> supportedMediaTypes = Lists.newArrayList();
		supportedMediaTypes.add(MediaType.ALL);
		converter.setSupportedMediaTypes(supportedMediaTypes);
		converters.add(1, converter);
		oconverter.setSupportedMediaTypes(supportedMediaTypes);
		oconverter.setDefaultCharset(charset);
	}
}

期待的正确结果

对您期望发生的结果进行清晰简洁的描述。

相关日志输出

请复制并粘贴任何相关的日志输出。

附加信息

如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。

805728578 avatar Aug 06 '24 02:08 805728578

@wenshao v2.0.53版本什么时候发布

805728578 avatar Aug 09 '24 01:08 805728578

这个周末

wenshao avatar Aug 09 '24 01:08 wenshao

@Test
    public void test() {
        BigDecimal decimal = new BigDecimal("12345678901234567890");
        String expected = "\"12345678901234567890\"";
        assertEquals(expected, JSON.toJSONString(decimal, WriteBigDecimalAsPlain, BrowserCompatible));

        assertEquals(expected,
                new String(JSON.toJSONBytes(decimal, WriteBigDecimalAsPlain, BrowserCompatible)));

        Bean bean = new Bean();
        bean.decimal = decimal;

        assertEquals("{\"decimal\":\"12345678901234567890\"}",
                JSON.toJSONString(bean, WriteBigDecimalAsPlain, BrowserCompatible));

        assertEquals("{\"decimal\":\"12345678901234567890\"}",
                new String(JSON.toJSONBytes(bean, WriteBigDecimalAsPlain, BrowserCompatible)));
    }

    public static class Bean {
        public BigDecimal decimal;
    }

我测试是好的,WriteBigDecimalAsPlain, BrowserCompatible没有冲突啊

wenshao avatar Aug 09 '24 17:08 wenshao

image

805728578 avatar Aug 13 '24 03:08 805728578

@wenshao 上述就是我写的测试用例,其结果BigDecimal和BigInteger为字符串,如果没有BrowserCompatible其接口返回BigDecimal和BigInteger为数字,其中WriteBigDecimalAsPlain设置不生效,那是和SpringBoot冲突了吗?

805728578 avatar Aug 19 '24 00:08 805728578

public class FastJSONTest {
	@Test
    public void test() {
        BigDecimal decimal = new BigDecimal("12345678901234567890");
        String expected = "\"12345678901234567890\"";
        assertEquals(expected, JSON.toJSONString(decimal, WriteBigDecimalAsPlain));
    }
    public static class Bean {
        public BigDecimal decimal;
    }
    public static void main(String[] args) {
    	BigDecimal decimal = new BigDecimal("12345678901234567890");
    	String expected = "\"12345678901234567890\"";
    	String expectNum = JSON.toJSONString(decimal, BrowserCompatible);
    	String expectStr = JSON.toJSONString(decimal, WriteBigDecimalAsPlain);
    	System.out.println("期望输出数字类型:"+expectNum);
    	System.out.println("期望输出字符串:"+expectStr);
    	System.out.println(expected.equals(expectStr));
	}
}

其测试结果如下:

image

805728578 avatar Aug 19 '24 01:08 805728578

@wenshao 上述测试用例期望结果未达到预期,我理解的预期的和你设计特性是否一致?如果一致这就是Bug,如果不一致则请给出说明

805728578 avatar Aug 19 '24 01:08 805728578

只要配置了BrowserCompatible,在[-9007199254740991, 9007199254740991]之外的数字都要输出为字符串

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

wenshao avatar Aug 20 '24 23:08 wenshao

@wenshao 上述测试用例只配置WriteBigDecimalAsPlain,但BigDecimal输出仍为数字,这是不是问题

805728578 avatar Aug 21 '24 06:08 805728578

@wenshao 上述测试用例只配置WriteBigDecimalAsPlain,但BigDecimal输出仍为数字,这是不是问题

貌似没什么问题,只是以非科学计数法输出数字,而不是以 string格式输出

rowstop avatar Oct 24 '24 09:10 rowstop