14

I am facing a problem , sometimes Json response returns an array of objects , sometimes object itself , how we can handle dynamically in the response class. In the current eg :results sometimes gets an array of objects

 "\"results\": " +
            "[{" +

and sometimes object itself

 "\"results\": " +
            "{" +

Eg:

How we can handle this ?

Gson gson = new Gson();
    SearchResponse response=new SearchResponse();
    response= gson.fromJson("{" +
            "\"completed_in\": 0.047," +
            "\"max_id\": 291771567376039936," +
            "\"max_id_str\": \"291771567376039936\"," +
            "\"next_page\": \"?page=2&max_id=291771567376039936&q=javacodegeeks\"," +
            "\"page\": 1," +
            "\"query\": \"javacodegeeks\"," +
            "\"refresh_url\": \"?since_id=291771567376039936&q=javacodegeeks\"," +
            "\"results\": " +
            "{" +
            "\"created_at\": \"Thu, 17 Jan 2013 04:58:57 +0000\"," +
            "\"from_user\": \"hkokko\"," +
            "\"from_user_id\": 24726686," +
            "\"from_user_id_str\": \"24726686\"," +
            " \"from_user_name\": \"Hannu Kokko\"," +
            " \"geo\": null," +
            "\"id\": 291771567376039936," +
            "\"id_str\": \"291771567376039936\"," +
            "\"iso_language_code\": \"en\"," +
            " \"metadata\": {" +
            "\"result_type\": \"recent\"}," +
            "\"profile_image_url\": \"hjh\"," +
            "\"profile_image_url_https\": \"kkj\"," +
            "\"source\": \"<a href="hj;\"," +
            "\"text\": \"Continuous Deployment: Are You Afraid It Might Work? jh\"," +
            "\"to_user\": null," +
            "\"to_user_id\": 0," +
            "\"to_user_id_str\": \"0\"," +
            "\"to_user_name\": null" +
            " }," +
            "\"results_per_page\": 15," +
            "\"since_id\": 0," +
            "\"since_id_str\": \"0\"" +
            "}", SearchResponse.class);
    System.out.println(response.toString());

Kindly assist...

Can anyone give any suggestions by using different jars to achieve this?

Rockin
  • 723
  • 4
  • 25
  • 51
  • Such server realisation is real NOT good one. It's yours back-end? – Evos Jan 17 '13 at 06:49
  • its client, i receive this response from server.. – Rockin Jan 17 '13 at 06:57
  • If the server returns an array of object does it always contain a single object or can contain multiple ones ? If it's an array do you proccess every element of it? – dstronczak Jan 17 '13 at 12:22
  • Have a look at this question http://stackoverflow.com/questions/16654042/gson-expected-begin-array-but-was-begin-object/25336864#25336864 – Abhishek V Aug 16 '14 at 04:13

2 Answers2

18

i found a solution for this ,i felt to share this..The code will automatically convert ..if excepted response is arraylist in response class....then if object is coming in response then add to arraylist else if arraylist it will take the same list. we need hook change the response bfore it calls fromJson.

public class ArrayAdapter<T> extends TypeAdapter<List<T>> {
    private Class<T> adapterclass;

    public ArrayAdapter(Class<T> adapterclass) {

        this.adapterclass = adapterclass;
    }

    public List<T> read(JsonReader reader) throws IOException {


        List<T> list = new ArrayList<T>();

        Gson gson = new Gson();

        if (reader.peek() == JsonToken.BEGIN_OBJECT) {

            T inning = (T) gson.fromJson(reader, adapterclass);
            list.add(inning);

        } else if (reader.peek() == JsonToken.BEGIN_ARRAY) {

            reader.beginArray();
            while (reader.hasNext()) {
                T inning = (T) gson.fromJson(reader, adapterclass);
                list.add(inning);
            }
            reader.endArray();

        } else {
            reader.skipValue();
        }

        return list;
    }

    public void write(JsonWriter writer, List<T> value) throws IOException {

    }

}

public class ArrayAdapterFactory implements TypeAdapterFactory {

  @SuppressWarnings({ "unchecked" })
  @Override
  public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {

      ArrayAdapter typeAdapter = null;
      try {
          if (type.getRawType() == List.class)
          {

              typeAdapter = new ArrayAdapter(
                      (Class) ((ParameterizedType) type.getType())
                              .getActualTypeArguments()[0]);
          }
      } catch (Exception e) {
          e.printStackTrace();
      }

      return typeAdapter;
}

then just call

 Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ArrayAdapterFactory()).create();
 SearchResponse response;
 esponse= gson.fromJson("your json string", SearchResponse.class)
mixel
  • 25,177
  • 13
  • 126
  • 165
Rockin
  • 723
  • 4
  • 25
  • 51
  • it gives error at TypeAdapter typeAdapter = null; for .. You can resolve this issue by modifying the class signature like public class ArrayAdapterFactory implements TypeAdapterFactory { – Yasir Ali Jul 08 '13 at 12:58
  • com.google.gson.internal.$Gson$Types$ParameterizedTypeImpl cannot be cast to java.lang.Class at am getting error while mapping using the above example – Syed Rafi Aug 24 '16 at 14:27
4

You would need to write a custom deserializer that checks the type of results in the JSON then acts accordingly.

Your POJO will contain an array for results and if your incoming JSON only has a single object you'll need to fix that. One way is to modify the JSON then deserialize it:

class SearchResponseDeserializer implements JsonDeserializer<SearchResponse> {
  public SearchResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {

    if (json.getAsJsonObject().get("results").isJsonObject()) {
      //modify JSON: change results to be an array
      // ...
    }

    return new Gson().fromJson(json, SearchResults.class);

  }
}

Or, fix the server, of course. It should always be returning an array to avoid this issue.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161