简体   繁体   中英

Deserializing JSON object to string field with GSON

I have a POJO with a String field that is already serialized JSON. Performance is key here, so I want to avoid parsing it and then re-serializing it.

public class SomeObject {
    String someString = "";
    String jsonString = "{\"one\":4, \"two\":\"hello\"}";
    long someLong = 4;
}

Currently GSON serialises it like so:

{ "someString":"", "jsonString":"{\\"one\\":4, \\"two\\":\\"hello\\"}", "someLong":4 }

I wrote a JsonSerializer/Deserializer in hopes of using the @JsonAdapter annotation, but it only supports TypeAdapter or TypeAdapterFactory.

public class JsonStringTypeAdapter implements JsonSerializer<String>, JsonDeserializer<String> {

    @Override
    public JsonElement serialize(String t, Type type, JsonSerializationContext jsc) {
        return new JsonParser().parse(t).getAsJsonObject();
    }

    @Override
    public String deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException {
        return je.getAsString();
    }

    @Override
    public void write(JsonWriter writer, String t) throws IOException {
        writer.jsonValue(t);
    }

}

So I wrote the following simple TypeAdapter that works perfectly for serialisation, but I can't work out how to deserialise a Json object to String in a TypeAdapter.

public class JsonStringTypeAdapter extends TypeAdapter<String> {

    @Override
    public void write(JsonWriter writer, String t) throws IOException {
        writer.jsonValue(t);
    }

    @Override
    public String read(JsonReader reader) throws IOException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}

I know Jackson has an annotation for this. Any ideas for doing it with GSON?

Solved it using TypeAdapterFactory.

public class JsonStringTypeAdapterFactory implements TypeAdapterFactory {

   @Override
   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> tokenType) {
       if (!JsonString.class.isAssignableFrom(tokenType.getRawType())) return null;

       return (TypeAdapter<T>) new JsonStringTypeAdapter(gson);
   }

}

And completing the read method

/* The JsonStringTypeAdapter writes the raw string value directly to the JSON output
 *  this offers great performance by avoiding parsing then reserialising
 * Note: Care must be taken to ensure the input JsonString is well formed JSON.
 *       Otherwise, when it is deserialised, errors will occur.
 *
 * @author adamjohnson
 */
public class JsonStringTypeAdapter extends TypeAdapter<JsonString> {

    private final Gson gson;
    public JsonStringTypeAdapter(Gson gson) {
        this.gson = gson;
    }

    @Override
    public void write(JsonWriter writer, JsonString t) throws IOException {
        /* check for invalid json string, if so create empty object. */
        if (t.value().equals("")) {
            writer.jsonValue("{}");
        } else /* write raw string directly to json output */ {
            writer.jsonValue(t.value());
        }
    }

    @Override
    public JsonString read(JsonReader reader) throws IOException {
        return new JsonString(gson.getAdapter(JsonElement.class).read(reader).getAsString());
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM