Moshi 预期 BEGIN_OBJECT 但 BEGIN_ARRAY - 自定义转换器被忽略
Moshi Expected BEGIN_OBJECT but was BEGIN_ARRAY - custom converter ignored
我正在使用 Moshi 作为 Retrofit 的转换器,但是对于一个特定的请求它不起作用并且抛出异常:
com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $.results
我要解析的JSON:
{
"id": 423,
"results": [
{
"id": "53484dfec3a3684b930000bd",
"iso_639_1": "en",
"iso_3166_1": "US",
"key": "u_jE7-6Uv7E",
"name": "Trailer",
"site": "YouTube",
"size": 360,
"type": "Trailer"
},
{
"id": "57e16bb0c3a36808bc000641",
"iso_639_1": "en",
"iso_3166_1": "US",
"key": "BFwGqLa_oAo",
"name": "Trailer",
"site": "YouTube",
"size": 1080,
"type": "Trailer"
}
]
}
型号class是:
public class VideosResponse {
private int id;
private List<Video> results;
//+ getters & setters
}
public class Video {
private String id;
@Json(name = "iso_639_1")
private String iso6391;
@Json(name = "iso_3166_1")
private String iso31661;
private String key;
private String name;
private String site;
private Integer size;
private String type;
//+getters & setters
}
这是 Retrofit 调用:
@GET("3/movie/{id}/videos")
Call<List<Video>> movieVideos(
@Path("id") int id,
@Query("api_key") String apiKey);
所以你可以看到我期待对象列表,但 JSON 实际上是一个对象本身,因此我准备了我的自定义转换器:
public class VideosJsonConverter {
@FromJson
public List<Video> fromJson(VideosResponse json) {
return json.getResults();
}
}
...我将它添加到我的 Retrofit 中:
public Retrofit provideRetrofit(@Named("baseUrl") String basUrl) {
Moshi moshi = new Moshi.Builder().add(new VideosJsonConverter()).build();
return new Retrofit.Builder()
.baseUrl(basUrl)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build();
}
我的自定义转换器实际上并未被调用,所以看起来 Moshi 无法将 JSON 转换为我的 VideosResponse
包装器 class。如果我更改我的转换器以接受 Map<String, Object>
,它会转到那里,但不会用于 VideosResponse
。当我直接将改装 enpoint 更改为 return VideosResponse
时,它也有效。是否可能与其他 POJO classes 发生冲突(我有类似的 classes 但具有不同对象的列表)?
问题是您想要的结果和 VideosResponse 中的内部列表都将使用该适配器。因此,适配器期望 VideoResponse 中有一个 VideoResponse-formatted JSON blob,当它在重新进入时找到真正的数组时失败。
您可以限定其中一个列表以区分它们。
下面是限定结果列表的示例。
@Retention(RUNTIME)
@JsonQualifier
public @interface Wrapped {
}
public class VideosJsonConverter {
@Wrapped @FromJson
public List<Video> fromJson(VideosResponse json) {
return json.results;
}
@ToJson
public VideosResponse toJson(@Wrapped List<Video> value) {
throw new UnsupportedOperationException();
}
}
@GET("3/movie/{id}/videos")
@Wrapped
Call<List<Video>> movieVideos(
@Path("id") int id,
@Query("api_key") String apiKey);
我正在使用 Moshi 作为 Retrofit 的转换器,但是对于一个特定的请求它不起作用并且抛出异常:
com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $.results
我要解析的JSON:
{
"id": 423,
"results": [
{
"id": "53484dfec3a3684b930000bd",
"iso_639_1": "en",
"iso_3166_1": "US",
"key": "u_jE7-6Uv7E",
"name": "Trailer",
"site": "YouTube",
"size": 360,
"type": "Trailer"
},
{
"id": "57e16bb0c3a36808bc000641",
"iso_639_1": "en",
"iso_3166_1": "US",
"key": "BFwGqLa_oAo",
"name": "Trailer",
"site": "YouTube",
"size": 1080,
"type": "Trailer"
}
]
}
型号class是:
public class VideosResponse {
private int id;
private List<Video> results;
//+ getters & setters
}
public class Video {
private String id;
@Json(name = "iso_639_1")
private String iso6391;
@Json(name = "iso_3166_1")
private String iso31661;
private String key;
private String name;
private String site;
private Integer size;
private String type;
//+getters & setters
}
这是 Retrofit 调用:
@GET("3/movie/{id}/videos")
Call<List<Video>> movieVideos(
@Path("id") int id,
@Query("api_key") String apiKey);
所以你可以看到我期待对象列表,但 JSON 实际上是一个对象本身,因此我准备了我的自定义转换器:
public class VideosJsonConverter {
@FromJson
public List<Video> fromJson(VideosResponse json) {
return json.getResults();
}
}
...我将它添加到我的 Retrofit 中:
public Retrofit provideRetrofit(@Named("baseUrl") String basUrl) {
Moshi moshi = new Moshi.Builder().add(new VideosJsonConverter()).build();
return new Retrofit.Builder()
.baseUrl(basUrl)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build();
}
我的自定义转换器实际上并未被调用,所以看起来 Moshi 无法将 JSON 转换为我的 VideosResponse
包装器 class。如果我更改我的转换器以接受 Map<String, Object>
,它会转到那里,但不会用于 VideosResponse
。当我直接将改装 enpoint 更改为 return VideosResponse
时,它也有效。是否可能与其他 POJO classes 发生冲突(我有类似的 classes 但具有不同对象的列表)?
问题是您想要的结果和 VideosResponse 中的内部列表都将使用该适配器。因此,适配器期望 VideoResponse 中有一个 VideoResponse-formatted JSON blob,当它在重新进入时找到真正的数组时失败。
您可以限定其中一个列表以区分它们。 下面是限定结果列表的示例。
@Retention(RUNTIME)
@JsonQualifier
public @interface Wrapped {
}
public class VideosJsonConverter {
@Wrapped @FromJson
public List<Video> fromJson(VideosResponse json) {
return json.results;
}
@ToJson
public VideosResponse toJson(@Wrapped List<Video> value) {
throw new UnsupportedOperationException();
}
}
@GET("3/movie/{id}/videos")
@Wrapped
Call<List<Video>> movieVideos(
@Path("id") int id,
@Query("api_key") String apiKey);