2017-02-18 43 views
2

我有一個API可以返回JSON數組或對象。例如JSON對象如何轉換動態JSON響應與Java Gson庫

{ 
    "id": 1, 
    "name": "name" 
} 

JSON數組:

[ 
    { 
     "id": 1, 
     "name": "name" 
    }, 
    { 
     "id": 1, 
     "name": "name" 
    } 
] 

當映射到POJO JSON對象響應我使用:

MyEntity myEntity = new Gson().fromJson(jsonString, MyEntity.class); 

當映射到的POJO陣列的JSON陣列響應我用:

MyEntity[] myEntity = new GSON().fromJson(jsonString, MyEntity[].class); 

我如何動態地將這兩個響應轉換爲適當的類型?

注意:我無法修改服務器響應,這是一個公共API。

謝謝!

編輯:

我想實現自動執行此操作的方法,但我失去了一些東西。方法

public <T> T convertResponseToEntity(Class<T> classOfT) 
{ 
    JsonElement jsonElement = this.gson.fromJson(getResponseAsString(), JsonElement.class); 

    if (jsonElement.isJsonArray()) { 
     Type listType = new TypeToken<T>(){}.getType(); 
     return this.gson.fromJson(getResponseAsString(), listType); 
    } 

    return this.gson.fromJson(getResponseAsString(), (Type) classOfT); 
} 

它返回一個列表LinkedTreeMap s。我如何修改代碼以返回與Object[]相同的內容?

回答

1

我怎麼能動態轉換爲相應類型的2層的反應?

這取決於如何解釋「適當的類型」在這裏,因爲它會導致instanceof或訪客模式,以獲得相應的類型,一旦你嘗試解析 - 從 - JSON對象,你需要它,每次處理。如果您無法更改API,則可以平滑使用它的方式。其中一種可能的選擇是處理這種響應,就好像一切都是列表。即使只有一個對象可以作爲僅包含一個元素的列表進行處理(許多庫僅適用於具有以下事實的序列/列表:Java中的Stream API,.NET中的LINQ,JavaScript中的jQuery等)。

假設你有以下MyEntity類來處理,你需要從API獲得的元素:

// For the testing purposes, package-visible final fields are perfect 
// Gson can deal with final fields too 
final class MyEntity { 

    final int id = Integer.valueOf(0); // not letting javac to inline 0 since it's primitive 
    final String name = null; 

    @Override 
    public String toString() { 
     return id + "=>" + name; 
    } 

} 

接下來,讓我們創建一個類型的適配器,將始終一致「真」列表和單個對象,就好像它是一個列表:

final class AlwaysListTypeAdapter<T> 
     extends TypeAdapter<List<T>> { 

    private final TypeAdapter<T> elementTypeAdapter; 

    private AlwaysListTypeAdapter(final TypeAdapter<T> elementTypeAdapter) { 
     this.elementTypeAdapter = elementTypeAdapter; 
    } 

    static <T> TypeAdapter<List<T>> getAlwaysListTypeAdapter(final TypeAdapter<T> elementTypeAdapter) { 
     return new AlwaysListTypeAdapter<>(elementTypeAdapter); 
    } 

    @Override 
    @SuppressWarnings("resource") 
    public void write(final JsonWriter out, final List<T> list) 
      throws IOException { 
     if (list == null) { 
      out.nullValue(); 
     } else { 
      switch (list.size()) { 
      case 0: 
       out.beginArray(); 
       out.endArray(); 
       break; 
      case 1: 
       elementTypeAdapter.write(out, list.iterator().next()); 
       break; 
      default: 
       out.beginArray(); 
       for (final T element : list) { 
        elementTypeAdapter.write(out, element); 
       } 
       out.endArray(); 
       break; 
      } 
     } 
    } 

    @Override 
    public List<T> read(final JsonReader in) 
      throws IOException { 
     final JsonToken token = in.peek(); 
     switch (token) { 
     case BEGIN_ARRAY: 
      final List<T> list = new ArrayList<>(); 
      in.beginArray(); 
      while (in.peek() != END_ARRAY) { 
       list.add(elementTypeAdapter.read(in)); 
      } 
      in.endArray(); 
      return unmodifiableList(list); 
     case BEGIN_OBJECT: 
      return singletonList(elementTypeAdapter.read(in)); 
     case NULL: 
      return null; 
     case END_ARRAY: 
     case END_OBJECT: 
     case NAME: 
     case STRING: 
     case NUMBER: 
     case BOOLEAN: 
     case END_DOCUMENT: 
      throw new MalformedJsonException("Unexpected token: " + token); 
     default: 
      // A guard case: what if Gson would add another token someday? 
      throw new AssertionError("Must never happen: " + token); 
     } 
    } 

} 

GSON TypeAdapter設計以流方式工作因此它們從效率的角度便宜,但實施並不容易。上面的write()方法僅僅是爲了不把throw new UnsupportedOperationException();放在那裏(我假設你只是閱讀那個API,但不知道這個API是否可能使用「元素或列表」修改請求)。現在有必要建立一個類型的適配器工廠讓GSON拿起每一個特定類型的正確類型的適配器:

final class AlwaysListTypeAdapterFactory 
     implements TypeAdapterFactory { 

    private static final TypeAdapterFactory alwaysListTypeAdapterFactory = new AlwaysListTypeAdapterFactory(); 

    private AlwaysListTypeAdapterFactory() { 
    } 

    static TypeAdapterFactory getAlwaysListTypeAdapterFactory() { 
     return alwaysListTypeAdapterFactory; 
    } 

    @Override 
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) 
      throws IllegalArgumentException { 
     if (List.class.isAssignableFrom(typeToken.getRawType())) { 
      final Type elementType = getElementType(typeToken); 
      // Class<T> instances can be compared with == 
      final TypeAdapter<?> elementTypeAdapter = elementType == MyEntity.class ? gson.getAdapter(MyEntity.class) : null; 
      // Found supported element type adapter? 
      if (elementTypeAdapter != null) { 
       @SuppressWarnings("unchecked") 
       final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) getAlwaysListTypeAdapter(elementTypeAdapter); 
       return castTypeAdapter; 
      } 
     } 
     // Not a type that can be handled? Let Gson pick a more appropriate one itself 
     return null; 
    } 

    // Attempt to detect the list element type 
    private static Type getElementType(final TypeToken<?> typeToken) { 
     final Type listType = typeToken.getType(); 
     return listType instanceof ParameterizedType 
       ? ((ParameterizedType) listType).getActualTypeArguments()[0] 
       : Object.class; 
    } 

} 

而且它是如何使用的畢竟:

private static final Type responseItemListType = new TypeToken<List<MyEntity>>() { 
}.getType(); 

private static final Gson gson = new GsonBuilder() 
     .registerTypeAdapterFactory(getAlwaysListTypeAdapterFactory()) 
     .create(); 

public static void main(final String... args) { 
    test(""); 
    test("{\"id\":1,\"name\":\"name\"}"); 
    test("[{\"id\":1,\"name\":\"name\"},{\"id\":1,\"name\":\"name\"}]"); 
    test("[]"); 
} 

private static void test(final String incomingJson) { 
    final List<MyEntity> list = gson.fromJson(incomingJson, responseItemListType); 
    System.out.print("LIST="); 
    System.out.println(list); 
    System.out.print("JSON="); 
    gson.toJson(list, responseItemListType, System.out); // no need to create an intermediate string, let it just stream 
    System.out.println(); 
    System.out.println("-----------------------------------"); 
} 

輸出:

LIST=null 
JSON=null 
----------------------------------- 
LIST=[1=>name] 
JSON={"id":1,"name":"name"} 
----------------------------------- 
LIST=[1=>name, 1=>name] 
JSON=[{"id":1,"name":"name"},{"id":1,"name":"name"}] 
----------------------------------- 
LIST=[] 
JSON=[] 
----------------------------------- 
1

只是解析成JsonElement,檢查實際的元素類型:

Gson g = new Gson(); 
JsonParser parser = new JsonParser(); 
JsonElement e = parser.parse(new StringReader(jsonString)); 
if(e instanceof JsonObject) { 
    MyEntity myEntity = g.fromJson(e, MyEntity.class); 
} else { 
    MyEntity[] myEntity = g.fromJson(e, MyEntity[].class); 
}