在 Gson 双序列化中关闭科学记数法
Posted
技术标签:
【中文标题】在 Gson 双序列化中关闭科学记数法【英文标题】:switch off scientific notation in Gson double serialization 【发布时间】: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 消费者。我意识到真正的解决方法是对消费者进行排序,但有时这超出了我们的控制范围。因此,我认为这是一个合理(如果不寻常)的要求 【参考方案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-6
为0.000009166666
【讨论】:
使用 Kotlin - 查看我的回答 ***.com/a/57254418/2826184【参考方案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())
)
【讨论】:
以上是关于在 Gson 双序列化中关闭科学记数法的主要内容,如果未能解决你的问题,请参考以下文章
解决GSON转Long型变为科学计数法或整形变double的问题(自动转换成Double类型