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"}]}"
Kenenisa Bekele
  • 835
  • 13
  • 34
  • I don't understand. A Java `String` will be serialized as a JSON string. Can you clarify with an example? – Sotirios Delimanolis Jun 29 '17 at 17:13
  • 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. – Kenenisa Bekele Jun 29 '17 at 17:18
  • 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. – Sotirios Delimanolis Jun 29 '17 at 17:24
  • 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 field – Kenenisa Bekele Jun 29 '17 at 17:52

4 Answers4

18

The only way I found this to work was using

public JsonElement perro;
Kenenisa Bekele
  • 835
  • 13
  • 34
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
tmm1
  • 2,025
  • 1
  • 20
  • 35
  • There is an updated version in https://github.com/google/gson/issues/1368#issuecomment-417821473 – tmm1 May 20 '21 at 20:28
  • For the equivalent in moshi, see https://github.com/square/moshi/issues/675#issuecomment-842732058 – tmm1 May 21 '21 at 01:20
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
Yossi Segev
  • 607
  • 5
  • 12
0

You should be able to use public JsonObject perro;

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

John O'Reilly
  • 10,000
  • 4
  • 41
  • 63
  • I tried using @SerializedName("perro") public JsonObject perro but does not work – Kenenisa Bekele Jun 29 '17 at 17:47
  • @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. – John O'Reilly Jun 29 '17 at 18:05
  • There's no reason to involve a `Gson` instance again. Just use `perro.toString()` to get the `String` representation. – Sotirios Delimanolis Jun 29 '17 at 18:06
  • @KenenisaBekele Why this answer is downvoted. This is a good solution without a custom type adapter. – Krish Jun 29 '17 at 20:36
  • does not work Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive – Kenenisa Bekele Aug 04 '17 at 02:13