【问题标题】:switch off scientific notation in Gson double serialization在 Gson 双序列化中关闭科学记数法
【发布时间】:2012-06-20 12:01:22
【问题描述】:

当我使用 Gson 序列化一个包含接近零的双精度值的对象时,它使用的是科学 E 符号:

{"doublevaule":5.6E-4}

如何告诉 Gson 生成

{"doublevaule":0.00056}

相反?我可以实现一个自定义的 JsonSerializer,但它返回一个 JsonElement。我将不得不返回一个 JsonPrimitive,其中包含一个无法控制其序列化方式的 double。

谢谢!

【问题讨论】:

  • 为什么会有问题?科学记数法在 JSON 中有效,任何处理 JSON 的东西都应该能够正确解析(与未使用科学记数法完全相同的值)。
  • 我不反对,你是对的 Joachim。我仍然希望我的 JSON 不包含科学记数法。这对 GSon 可行吗?
  • 我有完全相同的问题,仅仅是因为我有一个无法处理指数的损坏的 JSON 消费者。我意识到真正的解决方法是对消费者进行排序,但有时这超出了我们的控制范围。因此,我认为这是一个合理(如果不寻常)的要求

标签: java json format double gson


【解决方案1】:

为什么不为Double 提供新的序列化程序? (您可能必须重写您的对象以使用Double 而不是double)。

然后在序列化器中,您可以转换为BigDecimal,并使用比例等。

例如

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {
        @Override
        public JsonElement serialize(final Double src, final Type typeOfSrc, final JsonSerializationContext context) {
            BigDecimal value = BigDecimal.valueOf(src);

            return new JsonPrimitive(value);
        }
    });

    gson = gsonBuilder.create();

上面将呈现(比如)9.166666E-60.000009166666

【讨论】:

【解决方案2】:

Brian Agnew's answer 的小改动:

public class DoubleJsonSerializer implements JsonSerializer<Double> {
    @Override
    public JsonElement serialize(final Double src, final Type typeOfSrc, final JsonSerializationContext context) {
        BigDecimal value = BigDecimal.valueOf(src);
        try {
            value = new BigDecimal(value.toBigIntegerExact());
        } catch (ArithmeticException e) {
            // ignore
        }

        return new JsonPrimitive(value);
    }
}

【讨论】:

    【解决方案3】:

    您可以尝试扩展 JsonWriter 并覆盖 the method value(double)

    它似乎不是为了像这样修改而构建的(您几乎需要复制现有代码),但应该可以让它工作。

    很遗憾,我认为没有其他原因会影响输出格式。

    【讨论】:

    • 这是正确的方法,但它可能需要大量重复的代码。 JsonWriter 不是为这种可扩展性而设计的,并且缺少必要的钩子。
    【解决方案4】:

    Double 创建一个自定义序列化程序

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {
        @Override
        public JsonElement serialize(Double originalValue, Type typeOf, JsonSerializationContext context) {
            BigDecimal bigValue = BigDecimal.valueOf(originalValue);
    
            return new JsonPrimitive(bigValue.toPlainString());
        }
    });
    

    之前:{“金额”:1.0E9}

    之后:{“金额”:“1000000000”}

    不完全完美,因为它是 JSON 中的字符串。

    【讨论】:

      【解决方案5】:

      GSON 内部使用 Number#toString,所以我们只需要创建一个 Number 的新实例:

      .registerTypeAdapter(Double.class, new JsonSerializer<Double>() {
          @Override
          public JsonElement serialize(final Double src, final Type typeOfSrc, final JsonSerializationContext context) {
      
              Number n = new Number() {
      
                  @Override
                  public long longValue() {
                      return 0;
                  }
      
                  @Override
                  public int intValue() {
                      return 0;
                  }
      
                  @Override
                  public float floatValue() {
                      return 0;
                  }
      
                  @Override
                  public double doubleValue() {
                      return 0;
                  }
      
                  @Override
                  public String toString() {
                      return new BigDecimal(src).toPlainString();
                  }
      
              };
      
              return new JsonPrimitive(n);
          }
      })
      

      【讨论】:

        【解决方案6】:

        使用 Kotlin:

            val gsonBuilder = GsonBuilder()
            gsonBuilder.registerTypeAdapter(object: TypeToken<Double>() {}.type, object : JsonSerializer<Double> {
                override fun serialize(src: Double, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
                    val value = BigDecimal.valueOf(src)
                    return JsonPrimitive(value)
                }
            })
        
            val gson = gsonBuilder.create()
        

        【讨论】:

          【解决方案7】:

          由于某种原因,我无法按照许多人的建议使用 BigDecimal 的解决方案。所以我不得不这样写:

          .registerTypeAdapter(object : TypeToken<Double>() {}.type, object : JsonSerializer<Double> {
              override fun serialize(src: Double, typeOfSrc: Type, context: JsonSerializationContext): JsonElement =
                  JsonPrimitive(src.toBigDecimal().toPlainString().toBigDecimal())
          })
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-08-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-01-15
            • 1970-01-01
            • 2020-12-26
            相关资源
            最近更新 更多