Gson Parsing with data being string sometimes and object sometimes

I have to parse a json that looks sometimes as

school_name:"Martin High School", leader: { first_name: "Austin", last_name: "Marriot", }

y a veces como

school_name:"Martin High School", leader: "/leader/3434".

I have tried to see if there is an example deserializer that can handle the "leader" sometiems to be a string and sometimes to be an object. But couldn't find any.

Is this possible with gson?

preguntado el 31 de julio de 12 a las 15:07

1 Respuestas

You only need to implement a TypeAdapter para su Leader. En read(JsonReader in) utilizan el JsonReader.peek() to find out what is coming and either read it and convert it to Leader. It should be rather trivial.

I did it as an exercise....

public class GsonStringOrObjectDemo {
    @EqualsAndHashCode
    private static class Leader {
        String firstName;
        String lastName;
    }
    private static class LeaderAdapter extends TypeAdapter<Leader> {
        @Override
        public void write(JsonWriter out, Leader value) throws IOException {
            if (useString) {
                out.value(value.firstName + ":" + value.lastName);
            } else {
                out.beginObject();
                out.name("firstName");
                out.value(value.firstName);
                out.name("lastName");
                out.value(value.lastName);
                out.endObject();
            }
            useString = !useString;
        }

        @Override
        public Leader read(JsonReader in) throws IOException {
            final Leader result = new Leader();
            final JsonToken type = in.peek();
            switch (type) {
            case BEGIN_OBJECT:
                in.beginObject();
                while (true) {
                    final String key = in.nextName();
                    final String value = in.nextString();
                    if (key.equals("firstName")) result.firstName = value;
                    else if (key.equals("lastName")) result.lastName = value;
                    else throw new JsonParseException("Unexpected key in Leader: " + key);
                    if (in.peek() == JsonToken.END_OBJECT) break;
                }
                in.endObject();
                return result;
            case STRING:
                final String string = in.nextString();
                final int pos = string.indexOf(':');
                result.firstName = string.substring(0, pos);
                result.lastName = string.substring(pos+1);
                return result;
            default:
                throw new JsonParseException("Expected string or object for Leader, got: " + type);
            }
        }

        private boolean useString;
    }

    public static void main(String[] args) throws Exception {
        final Gson gson = new GsonBuilder().registerTypeAdapter(Leader.class, new LeaderAdapter()).setPrettyPrinting().create();
        final Leader[] leaders = new Leader[10];
        for (int i=0; i<leaders.length; ++i) {
            leaders[i] = new Leader();
            leaders[i].firstName = "First" + i;
            leaders[i].lastName = "Last" + i;
        }
        final String json = gson.toJson(leaders);
        final Leader[] leaders2 = gson.fromJson(json, Leader[].class);
        Assert.assertTrue(Arrays.equals(leaders, leaders2));
    }
}

Respondido 31 Jul 12, 22:07

Wrote a separate class and added it in my builder.. builder.registerTypeAdapter(Leader.class, new LeaderAdapter()); but the adapter's read or write is never getting called.. Any thoughts? - Srini Raja

So it is getting called with Leader is an object, but never gets called when it is a String - Srini Raja

That's strange.. look at my updated answer, it works. In Java you must use always an object, but I hope you do. - maaartinus

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.