1

I use gson both for serializing and deserializing java objects as well as its built-in JsonElement. If I'm serializing a java object then I can register a type adapter and it will get called and allow me to provide a custom serialization.

But when I have a JsonElement, I can't seem to get it to ever recognize the type I want to adapt. Say I have this:

JsonArray arr = new JsonArray();
arr.add(Math.PI);
arr.add(Math.E);
System.out.println(arr.toString());

This will print out:

[3.141592653589793,2.718281828459045]

But how do I limit this to, say, three fractional digits? I was hoping I could add a type adapter, but I can't get anything to ever register, i.e., the adapter's methods are never called. Am I supposed to register a Double, Number, JsonPrimitive, or something else in this case? I've tried them all and nothing works.

And even if it did work, I think the best I could do is some math rounding, because if I tried to 'adapt' the number using, say, String.format() then the result would be a string and not a number, and I want the output json to remain a number.

Or maybe I'm completely missing something? Here's one example of what I've tried:

Gson gson = (new GsonBuilder()).registerTypeAdapter(
    JsonPrimitive.class,
    new TypeAdapter<JsonPrimitive>() {
        @Override
        public JsonPrimitive read(JsonReader reader) throws IOException {
            // never using deserialization, don't expect this to print
            System.out.println("read adapter");
            return null;
        }

        @Override
        public void write(JsonWriter writer, JsonPrimitive primitive) throws IOException {
            // this never gets called; output same as above
            System.out.println("write adapter");
            writer.nullValue();
        }
    }
).create();
System.out.println(gson.toJson(arr));
rjcarr
  • 1,932
  • 2
  • 20
  • 29

1 Answers1

1

We are not able to change internal adapters for Json* classes because Gson uses predefined com.google.gson.internal.bind.TypeAdapters.JSON_ELEMENT. But fortunately we can provide our JsonWriter implementation. Override methods which you need and provide your implementation to serialisation process. To round doubles use, for example, BigDecimal. Example custom implementation:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;

public class GsonApp {

    public static void main(String[] args) {
        Gson gson = new GsonBuilder().create();
        JsonArray array = new JsonArray();
        array.add(Math.PI);
        array.add(Math.E);

        StringWriter stringWriter = new StringWriter();
        JsonWriter jsonWriter = new JsonWriter(stringWriter) {
            @Override
            public JsonWriter value(Number value) throws IOException {
                BigDecimal bigDecimal = BigDecimal.valueOf(value.doubleValue());
                BigDecimal result = bigDecimal.setScale(3, BigDecimal.ROUND_UP);

                return super.value(result.doubleValue());
            }
        };
        jsonWriter.setIndent("  ");

        gson.toJson(array, jsonWriter);
        System.out.println(stringWriter.toString());
    }
}

Above code prints:

[
  3.142,
  2.719
]

See also:

Michał Ziober
  • 31,576
  • 17
  • 81
  • 124
  • Perfect, thanks, this is exactly what I was looking for, and would have never figured it out on my own. Cheers! – rjcarr Mar 04 '19 at 18:19