2017-02-18 8 views
2

JSON配列またはオブジェクトを返すAPIがあります。例えばJSONオブジェクトJava Gsonライブラリを使用して動的JSON応答を変換する方法

{ 
    "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); 

これらの2つの応答を適切なタイプに動的に変換するにはどうすればよいですか?

注:私はサーバーの応答を変更できません。これは公開APIです。

ありがとうございました!

EDIT:

私はこれを自動的に行いメソッドを実装しようとしていますが、私は何かが欠けています。メソッド

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のリストを返します。 Object[]と同じコンテンツを返すようにコードを変更するにはどうすればよいですか?

答えて

1

がどのように私は適切な型に動的にそれらの2つの応答を変換することができますか?

それはあなたがそれを必要とする解析され-から-JSONオブジェクトごとに処理するためにしようとしたら、それは適切な型を取得するためにinstanceofやビジターパターンにつながるので、ここでは「適切なタイプを」解釈する方法に依存します。 APIを変更できない場合は、使用方法をスムーズにすることができます。可能なオプションの1つは、すべてがリストであるかのようにそのような応答を処理することです。 1つのオブジェクトでも、1つの要素だけのリストとして扱うことができます(多くのライブラリは、その事実を持つシーケンス/リストで動作します:JavaのStream API、.NETのLINQ、JavaScriptのjQueryなど)。さんがいつもいるかのように「真」のリストと、単一のオブジェクトを整列するタイプのアダプタを作成してみましょう、

// 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; 
    } 

} 

次へ:

はあなたが必要なAPIから取得した要素を処理するために、次のMyEntityクラスがあるとしリストした:

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が "要素かリスト"のどちらかの変更要求を消費するかどうかはわかりません)。

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; 
    } 

} 

そして、どのようにそれは結局使われています:今ではGsonは、すべての特定のタイプのために右のタイプのアダプタを拾うようにするタイプのアダプタファクトリを作成する必要があります

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); 
} 
関連する問題