Android 如何在改装2中使用gson类型适配器?
我有一个工作代码,我的改造客户端可以从api中检索对象列表(国家)。问题是,api使用的参数返回一个数组,如果我用来检索所有国家,那么当我要查询单个国家时,它将返回单个对象。因此,将显示以下异常Android 如何在改装2中使用gson类型适配器?,android,gson,retrofit2,Android,Gson,Retrofit2,我有一个工作代码,我的改造客户端可以从api中检索对象列表(国家)。问题是,api使用的参数返回一个数组,如果我用来检索所有国家,那么当我要查询单个国家时,它将返回单个对象。因此,将显示以下异常 java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 4 column 17 path $.RestResponse.result 顺便说一下,我用的是改装2 我试着用这条线索来回答这个问题
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 4 column 17 path $.RestResponse.result
顺便说一下,我用的是改装2
我试着用这条线索来回答这个问题
但还是不行。这是我的实现
原料药
ApiInterface
public interface ApiInterface {
@GET("country/get/all")
Call<Example> getCountry();
@GET("country/get/iso2code/{alpha2_code}")
Call<Example> searchCountryByIso2Code(@Path("alpha2_code") String alpha2Code);
@GET("country/get/iso3code/{alpha3_code}")
Call<Example> searchCountryByIso3Code(@Path("alpha3_code") String alpha3Code);
@GET("country/search?text={text to search}")
Call<Example> searchCountry(@Path("text to search") String searchText);
}
编辑:
重新响应
public class RestResponse {
@SerializedName("messages")
@Expose
private List<String> messages = null;
@SerializedName("result")
@Expose
private List<Result> result = null;
public RestResponse() {
}
public RestResponse(List<String> messages, List<Result> result) {
this.messages = messages;
this.result = result;
}
public RestResponse(Result... result) {
this.result = Arrays.asList(result);
}
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
}
公共类重新响应{
@SerializedName(“消息”)
@暴露
私有列表消息=null;
@SerializedName(“结果”)
@暴露
私有列表结果=null;
公共厕所(){
}
公共重新响应(列出消息、列出结果){
this.messages=消息;
this.result=结果;
}
公共重新响应(结果…结果){
this.result=Arrays.asList(result);
}
公共列表getMessages(){
返回消息;
}
公共消息(列出消息){
this.messages=消息;
}
公共列表getResult(){
返回结果;
}
公共void setResult(列表结果){
this.result=结果;
}
}
您的代码中存在一些问题,其中一些问题可以修复或重新设计,以简化很多事情。首先,让我们看看服务(名字不同)。对于带有查询参数的请求,改装接口必须使用@Query
,而不是@Path
。此外,您的服务方法必须返回一个调用
,其中它的T
声明实际的结果类型,提供有关该方法返回的内容的一些信息。您提到的服务可以返回单个元素,也可以不返回任何元素(但由于某些原因永远不会返回HTTP 404),或者根据端点URL返回列表。让我们假设,单值和无值并不意味着是1或0大小的列表:
接口设备{
@获取(“国家/获取/全部”)
调用getCountries();
@GET(“国家/地区/GET/iso2code/{code}”)
调用getCountryByIso2Code(
@路径(“代码”)字符串代码
);
@GET(“国家/地区/GET/iso3code/{code}”)
调用getCountryByIso3Code(
@路径(“代码”)字符串代码
);
@获取(“国家/地区/搜索”)
呼叫搜索国家/地区(
@查询(“文本”)字符串查询
);
}
接下来,Country
类可能如下所示:
final class国家/地区{
@序列化名称(“名称”)
最终字符串名称=null;
@序列化名称(“字母2_代码”)
最终字符串code2=null;
@序列化名称(“字母3_代码”)
最终字符串code3=null;
@凌驾
公共字符串toString(){
返回name+'('+code2+'、'+code3+');
}
}
请注意,@SerializedName
可以将外部名称映射到本地字段名,字段是final
和null
ified-Gson可以自己处理它们。接下来,我假设您并不真正关心响应结构,只需要分别调整的$.response.result
TypeAdapterFactory
是您所需要的,可以处理任何响应,不一定适用于以下国家:
最终类响应ExtractorTypeAdapterFactory
实现TypeAdapterFactory{
私人最终Gson Gson;
私人响应ExtractortTypeAdapterFactory(最终Gson Gson){
this.gson=gson;
}
静态类型适配器工厂getResponseExtractorTypeAdapterFactory(最终Gson Gson){
返回新的响应ExtractortTypeAdapterFactory(gson);
}
@凌驾
公共类型适配器创建(最终Gson响应,最终TypeToken TypeToken){
//使用responseGson将导致无限递归,因为此类型适配器工厂将覆盖任何类型
返回新的responseExtractortTypeAdapter(gson,typeToken.getType());
}
私有静态最终类响应ExtractortTypeAdapter
扩展类型适配器{
私人最终Gson Gson;
私有最终类型;
专用响应ExtractortTypeAdapter(最终Gson Gson,最终类型){
this.gson=gson;
this.type=type;
}
@凌驾
公共无效写入(最终JsonWriter out,最终T值){
抛出新的UnsupportedOperationException();
}
@凌驾
公共T读(最终JsonReader in)
抛出IOException{
T结果=null;
//剥去最上面的{$
in.beginObject();
最终字符串名称1=in.nextName();
开关(名称1){
案例“重新响应”:
//Response{for$.Response
in.beginObject();
while(在.hasNext()中){
最终字符串名称2=in.nextName();
开关(名称2){
案例“信息”:
//如果只是$.Response.message,则跳过它
in.skipValue();
打破
案例“结果”:
//如果是$.Response.result,则将其委托给“real”Gson
result=gson.fromJson(in,type);
打破
违约:
抛出新的MalformedJsonException(“在$.RestResponse处意外:“+name2”);
}
}
//$.Response的Response}
in.endObject();
打破
违约:
抛出新的MalformedJsonException(“在$:“+name1处意外”);
}
//剥去最上面的封闭区域}$
in.endObject();
返回结果;
}
}
}
总而言之:
publicstaticvoidmain(最终字符串…args){
最终Gson Gson=新的GsonBuilder(
public class CountryTypeAdapter extends TypeAdapter<RestResponse> {
private Gson mGson = new Gson();
@Override
public void write(JsonWriter jsonWriter, RestResponse restResponse) throws IOException {
mGson.toJson(restResponse, RestResponse.class, jsonWriter);
}
@Override
public RestResponse read(JsonReader jsonReader) throws IOException {
RestResponse result;
jsonReader.beginObject();
jsonReader.nextName();
if (jsonReader.peek() == JsonToken.BEGIN_ARRAY) {
result = new RestResponse((Result[]) mGson.fromJson(jsonReader, Result.class));
} else if (jsonReader.peek() == JsonToken.BEGIN_OBJECT) {
result = new RestResponse((Result) mGson.fromJson(jsonReader, Result.class));
} else {
throw new JsonParseException("Unexpected token " + jsonReader.peek());
}
jsonReader.endObject();
return result;
}
}
public class ApiClient {
public static final String BASE_URL = "http://services.groupkt.com/";
private static Retrofit mRetrofit;
public static Retrofit getmRetrofitClient(){
if (mRetrofit == null) {
mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().registerTypeAdapter(CountryTypeAdapter.class, new CountryTypeAdapter()).create()))
.build();
}
return mRetrofit;
}
}
public class RestResponse {
@SerializedName("messages")
@Expose
private List<String> messages = null;
@SerializedName("result")
@Expose
private List<Result> result = null;
public RestResponse() {
}
public RestResponse(List<String> messages, List<Result> result) {
this.messages = messages;
this.result = result;
}
public RestResponse(Result... result) {
this.result = Arrays.asList(result);
}
public List<String> getMessages() {
return messages;
}
public void setMessages(List<String> messages) {
this.messages = messages;
}
public List<Result> getResult() {
return result;
}
public void setResult(List<Result> result) {
this.result = result;
}
}