konstantin
konstantin

Reputation: 725

switch off scientific notation in Gson double serialization

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

Answers (7)

Bogdan Kornev
Bogdan Kornev

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

Elnatan Derech
Elnatan Derech

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

Ron Klein
Ron Klein

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

Denis
Denis

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

swanson
swanson

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

Brian Agnew
Brian Agnew

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

Joachim Sauer
Joachim Sauer

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

Related Questions