在 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_USfi_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
}