- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个工作代码,其中我的改造客户端可以从 api 检索对象列表(国家/地区)。问题是,如果我曾经检索所有国家,那么 api 使用的参数返回一个 ARRAY,然后当我想查询一个国家时它返回一个 OBJECT。结果显示以下异常。
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 4 column 17 path $.RestResponse.result
顺便说一下,我正在使用 Retrofit 2。
我在这个线程中尝试了接受的答案 How to handle parameters that can be an ARRAY or OBJECT in Retrofit on Android?
但是还是不行。这是我的实现。
应用程序接口(interface)
http://services.groupkt.com/country/get/all
http://services.groupkt.com/country/get/iso2code/{alpha2_code}
API接口(interface)
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 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;
}
}
API 客户端
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;
}
}
最佳答案
您的代码中存在一些问题,其中一些可以修复或重新设计以简化很多事情。首先,让我们看一下服务(名称不同)。对于带有查询参数的请求,Retrofit 接口(interface)必须使用@Query
,而不是@Path
。此外,您的服务方法必须返回一个 Call
,其中它的 T
声明实际结果类型,提供有关该方法返回内容的一些信息。您提到的服务可以返回单个元素或不返回(但由于某种原因从不返回 HTTP 404),或者取决于端点 URL 的列表。让我们假设,单个值和无值并不意味着是 1 或 0 大小的列表:
interface IService {
@GET("country/get/all")
Call<List<Country>> getCountries();
@GET("country/get/iso2code/{code}")
Call<Country> getCountryByIso2Code(
@Path("code") String code
);
@GET("country/get/iso3code/{code}")
Call<Country> getCountryByIso3Code(
@Path("code") String code
);
@GET("country/search")
Call<List<Country>> searchCountries(
@Query("text") String query
);
}
接下来,Country
类可能如下所示:
final class Country {
@SerializedName("name")
final String name = null;
@SerializedName("alpha2_code")
final String code2 = null;
@SerializedName("alpha3_code")
final String code3 = null;
@Override
public String toString() {
return name + '(' + code2 + ',' + code3 + ')';
}
}
请注意,@SerializedName
可以将外部名称映射到本地字段名称,并且字段是final
和null
化的 - Gson 可以自己对付他们。接下来,我假设你并不真正关心响应结构,只需要分别适配的$.Response.result
。 TypeAdapterFactory
是您所需要的,可以处理任何响应,不一定适用于国家/地区:
final class ResponseExtractorTypeAdapterFactory
implements TypeAdapterFactory {
private final Gson gson;
private ResponseExtractorTypeAdapterFactory(final Gson gson) {
this.gson = gson;
}
static TypeAdapterFactory getResponseExtractorTypeAdapterFactory(final Gson gson) {
return new ResponseExtractorTypeAdapterFactory(gson);
}
@Override
public <T> TypeAdapter<T> create(final Gson responseGson, final TypeToken<T> typeToken) {
// Using responseGson would result in infinite recursion since this type adapter factory overrides any type
return new ResponseExtractorTypeAdapter<>(gson, typeToken.getType());
}
private static final class ResponseExtractorTypeAdapter<T>
extends TypeAdapter<T> {
private final Gson gson;
private final Type type;
private ResponseExtractorTypeAdapter(final Gson gson, final Type type) {
this.gson = gson;
this.type = type;
}
@Override
public void write(final JsonWriter out, final T value) {
throw new UnsupportedOperationException();
}
@Override
public T read(final JsonReader in)
throws IOException {
T result = null;
// Strip the top most enclosing { for $
in.beginObject();
final String name1 = in.nextName();
switch ( name1 ) {
case "RestResponse":
// RestResponse { for $.Response
in.beginObject();
while ( in.hasNext() ) {
final String name2 = in.nextName();
switch ( name2 ) {
case "messages":
// If it's just $.Response.message, then skip it
in.skipValue();
break;
case "result":
// If it's $.Response.result, then delegate it to "real" Gson
result = gson.fromJson(in, type);
break;
default:
throw new MalformedJsonException("Unexpected at $.RestResponse: " + name2);
}
}
// RestResponse } for $.Response
in.endObject();
break;
default:
throw new MalformedJsonException("Unexpected at $: " + name1);
}
// Strip the top most enclosing } for $
in.endObject();
return result;
}
}
}
综合起来:
public static void main(final String... args) {
final Gson gson = new GsonBuilder()
// configure whatever you like
.create();
final Gson responseGson = new GsonBuilder()
.registerTypeAdapterFactory(getResponseExtractorTypeAdapterFactory(gson))
.create();
final Retrofit retrofit = new Builder()
.baseUrl("http://services.groupkt.com/")
.addConverterFactory(GsonConverterFactory.create(responseGson))
.build();
final IService apiInterface = retrofit.create(IService.class);
apiInterface.getCountries().enqueue(callback("getCountries()")); // http://services.groupkt.com/country/get/all
apiInterface.getCountryByIso2Code("UA").enqueue(callback("getCountryByIso2Code()")); // http://services.groupkt.com/country/get/iso2code/UA
apiInterface.getCountryByIso3Code("UKR").enqueue(callback("getCountryByIso3Code()")); // http://services.groupkt.com/country/get/iso3code/UKR
apiInterface.searchCountries("land").enqueue(callback("searchCountries()")); // http://services.groupkt.com/country/search?text=land
}
private static <T> Callback<T> callback(final String name) {
return new Callback<T>() {
@Override
public void onResponse(final Call<T> call, final Response<T> response) {
// Just make sure the output is not written in middle
synchronized ( System.out ) {
System.out.print(name);
System.out.print(": ");
System.out.println(response.body());
System.out.println();
}
}
@Override
public void onFailure(final Call<T> call, final Throwable ex) {
ex.printStackTrace(System.err);
}
};
}
结果(假设接收到响应并按顺序处理 + 长响应被剪切):
getCountries(): [Afghanistan(AF,AFG), Åland Islands(AX,ALA), Albania(AL,ALB), ..., Yemen(YE,YEM), Zambia(ZM,ZMB), Zimbabwe(ZW,ZWE)]
getCountryByIso2Code(): Ukraine(UA,UKR)
getCountryByIso3Code(): Ukraine(UA,UKR)
searchCountries(): [Åland Islands(AX,ALA), Bouvet Island(BV,BVT), Cayman Islands(KY,CYM), ..., United States Minor Outlying Islands(UM,UMI), Virgin Islands (British)(VG,VGB), Virgin Islands (U.S.)(VI,VIR)]
关于android - 如何在 Retrofit 2 中使用 gson TypeAdapter?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42642933/
我试图让 gson 在 java 项目上工作,但每次运行时都会出现上述错误。我没有使用任何闪存 IDE,只是 vim,我看到的与我的问题相关的每个问题都与 eclipse 及其部署设置有关。我希望有人
我一直在关注将对象数组转换为 JSON 的教程,但我遇到了一些找不到解决方案的错误。 代码 第 60 - 64 行 Gson gson = new Gson().toJson(data); respo
我正在创建一个新的 Netty 管道,我正在尝试: 避免过早优化。 编写易于向我的一位实习生解释的代码。 这种工厂方法当然很容易解释: public String toJSON() { Gso
我尝试在程序中使用 Unirest,但不断收到此错误 java.lang.NoSuchMethodError: com.google.gson.Gson.newBuilder()Lcom/google
// Retrofit compile 'com.squareup.retrofit2:retrofit:2.1.0' // JSON Parsing compile 'com.google.code
我正在尝试将 Gson 与接口(interface)一起使用: public interface Photo { public int getWidth(); } public class D
我正在执行一个 Web 服务,这是我的响应,但是当我尝试使用 Gson 库将此 JSONObject(org.json.JSONObject) 转换为特定对象时,我的应用程序崩溃了。所以,我不知道为什
我有以下 .json 文件 - { "IDs":[ "1716136233", "2030187302", "204897807
我试图在我的项目中使用 GSON,但我的应用程序崩溃了,logcat 说找不到 com.google.gson.Gson。我已将 import com.google.gson.Gson 放在我的类文件
在下面的示例中,我尝试序列化我的自定义类Couple,其中包含Point2D 类型的字段。 我发现,SErialzing 的过程取决于 DEserializer 的存在。 此外,如果存在反序列化器,则
我有课 class ThreadComment( banned: Int, closed: Int, comment: String?, date: String?,
使用 gson 解析 json 时,我有一个奇怪的行为。我使用这个代码: private static Container parseContainer(String containerJson) {
我注意到 GSON HTML 转义 字符,可以通过使用disableHtmlEscaping()来禁用它构建器配置方法。但我的问题是 - 为什么 GSON 默认情况下会进行 HTML 转义?不进行 H
我注意到一个奇怪的问题。我可以使用 Junit 运行我的测试用例,但是当我使用 maven 运行时,其中一个测试用例失败。它提示找不到 Gson 类 def。 我能够在 Maven 依赖项中看到 Gs
我有一个看起来像这样的 json {response:{"status":{"....."},data:[{"name":"Alice","id":"123"},{"name":"Jack","id"
所以,我的应用已经发布了将近一年,但没有看到这个问题,现在它出现了。 即使是现在,我的手机上的调试版本也没有这个问题。我对从 Android Studio 打开的任何模拟器没有任何问题。然而,Goog
我是 Android 开发环境的新手,因此需要专家的帮助。 java.lang.NoClassDefFoundError: com.google.gson.Gson 项目中包含 Gson 库,但是当从
总结 我在我的 android 应用程序中使用 Retrofit 和 Gson 有一段时间了,但是我从服务器获得的 ID 是 13 位数字。 Gson 自动将这些数字转换为科学计数法,然后将其转换为
我正在使用一个大的 JSON 对象,它具有来自多个请求的响应。 我正在处理的部分只需要很少的对象,而且它们并不总是在前面。例如 json 结构是: ** json = { mainDocume
我有一个休息网络服务: @Path("/tranreq") public class TranscriptRequesterResource { private static final Gs
我是一名优秀的程序员,十分优秀!