Retrofit和Gson:解析数组/元素多态对象
我按顺序得到回应:
"parameters": { "parameter": { "Data":"value" } }, "parameters":{ "parameter": [ { "Data":"value" }, { "Data":"value" }, ] },
如果我调用List
参数,则会出现错误:
预计BEGIN_OBJECT但获得BEGIN_ARRAY
我需要解析参数来获取值
public class ApiClient { public static final String BASE_URL ="http://........."; private static Retrofit retrofit = null; public static Retrofit getClient() { OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(1, TimeUnit.MINUTES) .writeTimeout(1, TimeUnit.MINUTES) .readTimeout(1, TimeUnit.MINUTES) .addInterceptor(new ServiceGenerator("Content-Type","application/json")).build(); Gson gson = new GsonBuilder() .setLenient() .create(); if (retrofit==null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .client(client) .build(); } return retrofit; }
}
public class ServiceGenerator implements Interceptor{ private String httpUsername; private String httpPassword; public ServiceGenerator(String httpUsername, String httpPassword) { this.httpUsername = httpUsername; this.httpPassword = httpPassword; } @Override public Response intercept(Chain chain) throws IOException { Request newRequest = chain.request().newBuilder() .addHeader("Authorization", getAuthorizationValue()) .build(); return chain.proceed(newRequest); } private String getAuthorizationValue() { final String userAndPassword = httpUsername + ":" + httpPassword; return "Basic " + Base64.encodeToString(userAndPassword.getBytes(), Base64.NO_WRAP); }
}
@POST("OneWay.json") Call sendOneWay(@Body Query data); @SerializedName("FlightDetails") public ApiResponse FlightDetails;
现在我打电话给ApiResponse类但是如何调用公共ApiResponse FlightDetails; &public List FlightDetails;
你可以使用这个网站为你生成java对象http://www.jsonschema2pojo.org/只需放入json响应并选择Json作为Source类型,Gson选择Annotation样式。
并将生成的java类复制到您的应用程序并将其用于改进响应。
你在这里遇到的问题是,对于相同的json字段,你有不同的类型。 因此,第一次获取JSON对象时,第二次使用JSON数组,这显然会在您严格定义为解析为数组(List)时崩溃。
你需要动态地处理这个案例,或者由API人员要求修复坏的数据结构,这似乎是你要回来的(除非它是故意的)。
要更好地理解JSON类型,请阅读http://www.json.org/
这只是一个非常微不足道的问题,通常会出现具有奇怪设计选择的API。 您只需将两种格式“对齐”为统一格式:列表可以涵盖两种情况。 因此,您必须实现的是一个类型适配器,它将检查是否需要这样的对齐,如果值是列表,则使用原始类型适配器,或者将其包装在单个元素列表中。
为简单起见,请考虑以下JSON文档:
single.json
{ "virtual": { "key-1": "value-1" } }
multiple.json
{ "virtual": [ { "key-1": "value-1" }, { "key-2": "value-2" } ] }
现在使用对齐字段定义映射:
final class Response { @JsonAdapter(AlwaysListTypeAdapterFactory.class) final List
注意JsonAnnotaion
注释:这是告诉Gson必须如何读取或写入字段的方法。 AlwaysListTypeAdapterFactory
实现可能如下所示:
final class AlwaysListTypeAdapterFactory implements TypeAdapterFactory { // Always consider making constructors private // + Gson can instantiate this factory itself private AlwaysListTypeAdapterFactory() { } @Override public TypeAdapter create(final Gson gson, final TypeToken typeToken) { // Not a list? if ( !List.class.isAssignableFrom(typeToken.getRawType()) ) { // Not something we can to deal with return null; } // Now just return a special type adapter that could detect how to deal with objects @SuppressWarnings("unchecked") final TypeAdapter castTypeAdapter = (TypeAdapter ) new AlwaysListTypeAdapter<>( (TypeAdapter
考试:
public static void main(final String... args) throws IOException { for ( final String resource : ImmutableList.of("single.json", "multiple.json") ) { try ( final Reader reader = getPackageResourceReader(Q43634110.class, resource) ) { final Response response = gson.fromJson(reader, Response.class); System.out.println(resource); System.out.println("\t" + response.virtual); } } }
输出:
single.json
[{键-1 =值1}]
multiple.json
[{key-1 = value-1},{key-2 = value-2}]