Reputation: 725
When I use Gson to serialize an Object that contains a double value close to zero it is using the scientific E-notation:
{"doublevaule":5.6E-4}
How do I tell Gson to generate
{"doublevaule":0.00056}
instead? I can implement a custom JsonSerializer, but it returns a JsonElement. I would have to return a JsonPrimitive containing a double having no control about how that is serialized.
Thanks!
Upvotes: 23
Views: 17269
Reputation: 111
For some reason I can't get the solution with BigDecimal to work as suggested here by many people. So I had to write it like that:
.registerTypeAdapter(object : TypeToken<Double>() {}.type, object : JsonSerializer<Double> {
override fun serialize(src: Double, typeOfSrc: Type, context: JsonSerializationContext): JsonElement =
JsonPrimitive(src.toBigDecimal().toPlainString().toBigDecimal())
})
Upvotes: 0
Reputation: 1037
With 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()
Upvotes: 2
Reputation: 9460
A minor change on 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);
}
}
Upvotes: 5
Reputation: 613
Internally GSON uses Number#toString so we just need to create a new instance of a 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);
}
})
Upvotes: 3
Reputation: 7472
Create a custom serializer for 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());
}
});
Before: {"Amount": 1.0E9}
After: {"Amount": "1000000000"}
Not exactly perfect since it's a String in the JSON.
Upvotes: 3
Reputation: 272337
Why not provide a new serialiser for Double
? (You will likely have to rewrite your object to use Double
instead of double
).
Then in the serialiser you can convert to a BigDecimal
, and play with the scale etc.
e.g.
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();
The above will render (say) 9.166666E-6
as 0.000009166666
Upvotes: 15
Reputation: 308131
You could try extending JsonWriter
and overriding the method value(double)
It doesn't seem to be built to be modified like this (you'll pretty much need to duplicate the existing code), but it should be possible to get it working.
Unfortunately I see no other reason to influence the output format.
Upvotes: 2