有没有办法根据JSON响应设置Moshi adapter
自动创建单个Object
或List<Object>
?目前,我可以明确地这样做。例如,我可以收到以下回复:
{
"userId": "1",
"id": "2",
"body": "body...",
"title": "title..."
}
或者
[
{
"userId": "1",
"id": "2",
"body": "body...",
"title": "title..."
}
]
我想创建Object
或List<Object>
,而无需明确指定使用哪一个。
答案 0 :(得分:2)
您可以使用JsonQualifier来概括它。 从您的示例中,您可以像
一样使用它final class Foo {
@SingleToArray final List<User> users;
}
这里的代码带有测试,以便更加充分地展示。
@Retention(RUNTIME)
@JsonQualifier public @interface SingleToArray {
final class Adapter extends JsonAdapter<List<Object>> {
final JsonAdapter<List<Object>> delegateAdapter;
final JsonAdapter<Object> elementAdapter;
public static final Factory FACTORY = new Factory() {
@Nullable @Override
public JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations,
Moshi moshi) {
Set<? extends Annotation> delegateAnnotations =
Types.nextAnnotations(annotations, SingleToArray.class);
if (delegateAnnotations == null) {
return null;
}
if (Types.getRawType(type) != List.class) {
throw new IllegalArgumentException(
"Only lists may be annotated with @SingleToArray. Found: " + type);
}
Type elementType = Types.collectionElementType(type, List.class);
JsonAdapter<List<Object>> delegateAdapter = moshi.adapter(type, delegateAnnotations);
JsonAdapter<Object> elementAdapter = moshi.adapter(elementType);
return new Adapter(delegateAdapter, elementAdapter);
}
};
Adapter(JsonAdapter<List<Object>> delegateAdapter, JsonAdapter<Object> elementAdapter) {
this.delegateAdapter = delegateAdapter;
this.elementAdapter = elementAdapter;
}
@Nullable @Override public List<Object> fromJson(JsonReader reader) throws IOException {
if (reader.peek() != JsonReader.Token.BEGIN_ARRAY) {
return Collections.singletonList(elementAdapter.fromJson(reader));
}
return delegateAdapter.fromJson(reader);
}
@Override public void toJson(JsonWriter writer, @Nullable List<Object> value)
throws IOException {
if (value.size() == 1) {
elementAdapter.toJson(writer, value.get(0));
} else {
delegateAdapter.toJson(writer, value);
}
}
}
}
@Test public void singleToArray() throws Exception {
Moshi moshi = new Moshi.Builder().add(SingleToArray.Adapter.FACTORY).build();
JsonAdapter<List<String>> adapter =
moshi.adapter(Types.newParameterizedType(List.class, String.class), SingleToArray.class);
assertThat(adapter.fromJson("[\"Tom\",\"Huck\"]")).isEqualTo(Arrays.asList("Tom", "Huck"));
assertThat(adapter.toJson(Arrays.asList("Tom", "Huck"))).isEqualTo("[\"Tom\",\"Huck\"]");
assertThat(adapter.fromJson("\"Jim\"")).isEqualTo(Collections.singletonList("Jim"));
assertThat(adapter.toJson(Collections.singletonList("Jim"))).isEqualTo("\"Jim\"");
assertThat(adapter.fromJson("[]")).isEqualTo(Collections.emptyList());
assertThat(adapter.toJson(Collections.<String>emptyList())).isEqualTo("[]");
}
答案 1 :(得分:0)
使用@ Eric的评论,我想出了以下正确的代码:
public static <T> List<T> loadFakeData(String url, Class<T> cls){
List<T> list = new ArrayList<>();
Moshi moshi = new Moshi.Builder().build();
try {
JsonReader reader = JsonReader.of(runHttpClient(url));
JsonReader.Token token = reader.peek();
if (token.equals(JsonReader.Token.BEGIN_ARRAY)) {
Type type = Types.newParameterizedType(List.class, cls);
JsonAdapter<List<T>> adapter = moshi.adapter(type);
list = adapter.fromJson(reader);
} else if (token.equals(JsonReader.Token.BEGIN_OBJECT)){
JsonAdapter<T> adapter = moshi.adapter(cls);
T t = adapter.fromJson(reader);
list.add(t);
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}