在 Android 上将改造响应解析为包含自定义对象的自定义对象
Parsing retrofit response into custom object containing custom object on Android
我在解析自定义响应时遇到问题,因为我的响应具有本地化属性。
我收到的回复看起来像这样:
[
{
"id": "dummyID1",
"name.en_US": "dummyNameEn1",
"name.fi_FI": "dummyNameFi1"
},
{
"id": "dummyID2",
"name.en_US": "dummyNameEn2",
"name.fi_FI": "dummyNameFi2"
},
{
"id": "dummyID3",
"name.en_US": "dummyNameEn3",
"name.fi_FI": "dummyNameFi3"
}...
]
为了解析我创建了一个自定义 class Device.java
:
public class Device {
public String id;
public LocalizedString name;
public Device(String id, LocalizedString name) {
this.id = id;
this.name = name;
}
//Getters and setters
}
现在我们有一个名为 LocalizedString.java
:
的自定义对象
public class LocalizedString implements Parcelable {
public static final Creator<LocalizedString> CREATOR = new Creator<LocalizedString>() {
@Override
public LocalizedString createFromParcel(Parcel in) {
return new LocalizedString(in);
}
@Override
public LocalizedString[] newArray(int size) {
return new LocalizedString[size];
}
};
private String en_US;
private String fi_FI;
public LocalizedString(String en, String fi) {
this.en_US = en;
this.fi_FI = fi;
}
protected LocalizedString(Parcel in) {
en_US = in.readString();
fi_FI = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(en_US);
dest.writeString(fi_FI);
}
//Getters, setters
}
现在,在我的回复中,我想创建一个 Device's
的列表,但它似乎不理解“LocalizedString”的工作原理。由于我的请求返回 <List<Device>>
我也不能真正自定义解析它。
以下是我尝试解析它的方法:
Call<List<Device>> call = getMainActivity().getRestClient().getDevices();
call.enqueue(new Callback<List<Device>>() {
@Override
public void onResponse(Call<List<Device>> call, Response<List<Device>> response) {
if (isAttached()) {
if (response.isSuccessful()) {
// get data
List<Device> items = response.body();
}
}
}
@Override
public void onFailure(Call<List<Device>> call, Throwable t) {
if (isAttached()) {
Logger.debug(getClass().getName(), "Could not fetch installation document devices past orders", t);
getMainActivity().showError(R.string.error_network);
}
}
});
并且:
@GET("document/devices")
Call<List<Device>> gettDevices();
在这种情况下,我应该怎么做才能将 name
绑定到 Device
,然后才能获得 en_US
或 fi_FI
。
如果你能控制 JSON 的来源,那么修改 JSON 结构很容易解决你的问题。
如果你不能,我们可以用来解决你的问题的一种方法是使用 Jackson 和自定义反序列化器:
public class DeviceDeserializer extends StdDeserializer<Device> {
public DeviceDeserializer() {
this(null);
}
public DeviceDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Device deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String id = getStringValue(node, "id");
String en = getStringValue(node, "name.en_EN");
String fi = getStringValue(node, "name.fi_FI");
LocalizedString localized = new LocalizedString(en, fi);
return new Device(id, localizedString);
}
private String getStringValue(JsonNode node, String key) {
// Throws exception or use null is up to you to decide
return Optional.ofNullable(node.get("id"))
.map(JsonNode::asText)
.orElse(null);
}
}
自己手动注册反序列化器或使用注解:
@JsonDeserialize(using = DeviceDeserializer.class)
public class Device {
...
请注意,您必须启用 retrofit jackson 转换器插件:(请参阅 Retrofit Configuration 部分)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(JacksonConverterFactory.create())
.build();
读这个:Get nested JSON object with GSON using retrofit
最好这样写
public class Device {
@SerializedName("id")
public String id;
@SerializedName("name.en_US")
public String en;
@SerializedName("name.fi_FI")
public String fi;
public Device(String id, String english, String fi) {
this.id = id;
this.en = english;
this.fi = fi;
}
//Getters and setters
}
我在解析自定义响应时遇到问题,因为我的响应具有本地化属性。
我收到的回复看起来像这样:
[
{
"id": "dummyID1",
"name.en_US": "dummyNameEn1",
"name.fi_FI": "dummyNameFi1"
},
{
"id": "dummyID2",
"name.en_US": "dummyNameEn2",
"name.fi_FI": "dummyNameFi2"
},
{
"id": "dummyID3",
"name.en_US": "dummyNameEn3",
"name.fi_FI": "dummyNameFi3"
}...
]
为了解析我创建了一个自定义 class Device.java
:
public class Device {
public String id;
public LocalizedString name;
public Device(String id, LocalizedString name) {
this.id = id;
this.name = name;
}
//Getters and setters
}
现在我们有一个名为 LocalizedString.java
:
public class LocalizedString implements Parcelable {
public static final Creator<LocalizedString> CREATOR = new Creator<LocalizedString>() {
@Override
public LocalizedString createFromParcel(Parcel in) {
return new LocalizedString(in);
}
@Override
public LocalizedString[] newArray(int size) {
return new LocalizedString[size];
}
};
private String en_US;
private String fi_FI;
public LocalizedString(String en, String fi) {
this.en_US = en;
this.fi_FI = fi;
}
protected LocalizedString(Parcel in) {
en_US = in.readString();
fi_FI = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(en_US);
dest.writeString(fi_FI);
}
//Getters, setters
}
现在,在我的回复中,我想创建一个 Device's
的列表,但它似乎不理解“LocalizedString”的工作原理。由于我的请求返回 <List<Device>>
我也不能真正自定义解析它。
以下是我尝试解析它的方法:
Call<List<Device>> call = getMainActivity().getRestClient().getDevices();
call.enqueue(new Callback<List<Device>>() {
@Override
public void onResponse(Call<List<Device>> call, Response<List<Device>> response) {
if (isAttached()) {
if (response.isSuccessful()) {
// get data
List<Device> items = response.body();
}
}
}
@Override
public void onFailure(Call<List<Device>> call, Throwable t) {
if (isAttached()) {
Logger.debug(getClass().getName(), "Could not fetch installation document devices past orders", t);
getMainActivity().showError(R.string.error_network);
}
}
});
并且:
@GET("document/devices")
Call<List<Device>> gettDevices();
在这种情况下,我应该怎么做才能将 name
绑定到 Device
,然后才能获得 en_US
或 fi_FI
。
如果你能控制 JSON 的来源,那么修改 JSON 结构很容易解决你的问题。
如果你不能,我们可以用来解决你的问题的一种方法是使用 Jackson 和自定义反序列化器:
public class DeviceDeserializer extends StdDeserializer<Device> {
public DeviceDeserializer() {
this(null);
}
public DeviceDeserializer(Class<?> vc) {
super(vc);
}
@Override
public Device deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String id = getStringValue(node, "id");
String en = getStringValue(node, "name.en_EN");
String fi = getStringValue(node, "name.fi_FI");
LocalizedString localized = new LocalizedString(en, fi);
return new Device(id, localizedString);
}
private String getStringValue(JsonNode node, String key) {
// Throws exception or use null is up to you to decide
return Optional.ofNullable(node.get("id"))
.map(JsonNode::asText)
.orElse(null);
}
}
自己手动注册反序列化器或使用注解:
@JsonDeserialize(using = DeviceDeserializer.class)
public class Device {
...
请注意,您必须启用 retrofit jackson 转换器插件:(请参阅 Retrofit Configuration 部分)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(JacksonConverterFactory.create())
.build();
读这个:Get nested JSON object with GSON using retrofit
最好这样写
public class Device {
@SerializedName("id")
public String id;
@SerializedName("name.en_US")
public String en;
@SerializedName("name.fi_FI")
public String fi;
public Device(String id, String english, String fi) {
this.id = id;
this.en = english;
this.fi = fi;
}
//Getters and setters
}