Using GSON do not parse a field, only keep it with the json raw string
Asked Answered
S

4

10

Using GSON in Java is there any annotation where I can indicate a field that it should keep it as a raw string even though it is an object. ?

Or What would be the easiest way to achieve this?

//This is the original
    @SerializedName("perro")
    public Perro perro

//This is what I want to achieve 
    @SerializedName("perro")
    public String perro

So the result should be 
perro = "{"Users":[{"Name":"firulais","Raza":"beagle"},{"Name":"Spike","Value":"Terrier"}]}"
Samurai answered 29/6, 2017 at 17:11 Comment(4)
I don't understand. A Java String will be serialized as a JSON string. Can you clarify with an example?Unmoor
So say I have a Java Class call Animal.java that has many fields one of the fields is call Perro which an Object, so If I have a String response that it is actually a JSON , then if I do something like Animal animal = gson.fromJson(response,Animal.class), then I want the Perro field to be kept as the json raw string and not parse it into the Perro object.Samurai
Please edit your question with an example JSON payload. If your field is of type Object and it's actually a JSON string in the JSON, I believe Gson will fail to parse. If it's Object, Gson expects a JSON object.Unmoor
So the field of type Object I want it to be type of String, to not parse that field and just keep the raw Json string specific of that fieldSamurai
S
18

The only way I found this to work was using

public JsonElement perro;
Samurai answered 4/8, 2017 at 2:18 Comment(2)
Thanks, this is exactly what I was looking for!Wendall
Although this works, it uses a ton of memory because JsonElement keeps the entire json structure in memory as a tree.Wendall
W
6

Based on @mrsegev's answer, here's a simpler version (in Kotlin) that works with arbitrary objects:

class RawJsonAdapter: TypeAdapter<String>() {
    override fun write(out: JsonWriter?, value: String?) {
        out?.jsonValue(value)
    }
    override fun read(reader: JsonReader?): String {
        return JsonParser().parse(reader).toString()
    }
}

This takes advantage of JsonWriter#jsonValue() which was added in https://github.com/google/gson/pull/667

Usage:

@JsonAdapter(RawJsonAdapter::class)
val fieldName: String? = null
Wendall answered 25/5, 2018 at 21:24 Comment(2)
There is an updated version in github.com/google/gson/issues/1368#issuecomment-417821473Wendall
For the equivalent in moshi, see github.com/square/moshi/issues/675#issuecomment-842732058Wendall
B
2

Basically speaking, You need to create a custom gson TypeAdapter class and write the conversion login from Object to String yourself.

Then annotate the field indicating what TypeAdapter to use in order to read/write it using gson.

More details in this blog post: Gson TypeAdapter Example

Example: Prasing class object as a raw JSON string

public class StringTypeAdapter extends TypeAdapter<String> {

    @Override
    public void write(JsonWriter out, String value) throws IOException {
        try {
            JSONObject jsonObject = new JSONObject(value);
            out.beginObject();
            Iterator<String> iterator = jsonObject.keys();
            while (iterator.hasNext()) {
                String key = iterator.next();
                String keyValue = jsonObject.getString(key);
                out.name(key).value(keyValue);
            }
            out.endObject();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String read(JsonReader in) throws IOException {
        in.beginObject();
        JSONObject jsonObject = new JSONObject();
        while (in.hasNext()) {
            final String name = in.nextName();
            final String value = in.nextString();
            try {
                jsonObject.put(name, value);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        in.endObject();
        return jsonObject.toString();
    }
}

Using the TypeAdapter:

@JsonAdapter(StringTypeAdapter.class)
private String someClass; // Lazy parsing this json
Benioff answered 29/6, 2017 at 18:13 Comment(4)
I tried using the TypeAdapter but how to convert the JsonReader in, to the original string?Samurai
Updated my answer with an example to parse class object as a raw JSON string.Benioff
This one did not work, while is reading if there is a JSONObject as a string then it gets an exceptionSamurai
FYI, the write() method of the TypeAdapter can use jsonValue() to emit raw json directly. See github.com/google/gson/pull/667Wendall
S
0

You should be able to use public JsonObject perro;

You can then call gson.toJson(perro) to get the String value.

Segregation answered 29/6, 2017 at 17:31 Comment(5)
I tried using @SerializedName("perro") public JsonObject perro but does not workSamurai
@KenenisaBekele can you include full json string you're converting...I'm using the approach I mentioned in my answer in a few places where a field in json payload contains another json string.....but perhaps what you have isn't quite this case.Civics
There's no reason to involve a Gson instance again. Just use perro.toString() to get the String representation.Unmoor
@KenenisaBekele Why this answer is downvoted. This is a good solution without a custom type adapter.Therefore
does not work Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitiveSamurai

© 2022 - 2024 — McMap. All rights reserved.