Выключить научную нотацию в двойной сериализации Gson

Когда я использую Gson для сериализации объекта, который содержит двойное значение, близкое к нулю, он использует научное E-нотацию:

{"doublevaule":5.6E-4}

Как сообщить Gson генерировать

{"doublevaule":0.00056}

вместо этого? Я могу реализовать пользовательский JsonSerializer, но он возвращает JsonElement. Я должен был бы вернуть JsonPrimitive, содержащий double, не имеющий контроля над тем, как это сериализуется.

Спасибо!

Ответ 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

Ответ 2

Небольшое изменение на Брайан Агнью ответ:

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 и переопределить метод value(double)

Кажется, он не создан так, чтобы его можно было модифицировать (вам в значительной степени нужно будет дублировать существующий код), но должно быть возможно заставить его работать.

К сожалению, я не вижу другой причины влиять на выходной формат.

Ответ 4

Внутренне 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);
    }
})

Ответ 5

Создайте собственный сериализатор для 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.

Ответ 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()