2017-02-18 47 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); 
}