翻新呼叫具有相同的名称,但数据类型不同

时间:2019-07-03 04:13:04

标签: java json gson retrofit2

API调用

@GET("users/{user_id}/grid")
    Call<ArrayList<Grid>> getGrid(@Path("user_id") Integer id, @Header("Authorization") String authHeader);

Grid.class
public class Grid {

        @SerializedName("category")
        @Expose
        private String category;

        @SerializedName("type")
        @Expose
        private String type;

        @SerializedName("title")
        @Expose
        private String title;

        @SerializedName("equation_list")
        @Expose
        private List<Integer> equationList = null;  // This is the issue
}

API响应equation_list字段包含整数数组或字符串。 例如:

"equation_list": "7", or 
"equation_list": [7],

但是我有例外

  

com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:   预期为BEGIN_ARRAY,但位于第1行第1586列路径的STRING   $ [5] .equation_list

我如何满足我的要求?

1 个答案:

答案 0 :(得分:1)

我认为您可以创建一个类型来处理两种数据类型:字符串 ArrayList 。然后,您可以为GSON实现自定义JsonAdapter,以处理该类型的自定义反序列化。

让我们创建从EquationList派生的java.util.ArrayList

/**
 * Custom type to handle both String and ArrayList<Integer> types
 *
 * @author Yavuz Tas
 *
 */
public class EquationList extends ArrayList<Integer> {

}

JsonAdapter类型实现EquationList

/**
 * Custom JsonAdapter for GSON to handle {@link EquationList} converstion
 * 
 * @author Yavuz Tas
 *
 */
public class EquationListJsonAdapter extends TypeAdapter<EquationList> {

    @Override
    public void write(JsonWriter out, EquationList user) throws IOException {

        // Since we do not serialize EquationList by gson we can omit this part.
        // If you need you can check
        // com.google.gson.internal.bind.ObjectTypeAdapter class
        // read method for a basic object serialize implementation

    }

    @Override
    public EquationList read(JsonReader in) throws IOException {

        EquationList deserializedObject = new EquationList();

        // type of next token
        JsonToken peek = in.peek();

        // if the json field is string
        if (JsonToken.STRING.equals(peek)) {
            String stringValue = in.nextString();
            // convert string to integer and add to list as a value
            deserializedObject.add(Integer.valueOf(stringValue));
        }

        // if it is array then implement normal array deserialization
        if (JsonToken.BEGIN_ARRAY.equals(peek)) {
            in.beginArray();

            while (in.hasNext()) {
                String element = in.nextString();
                deserializedObject.add(Integer.valueOf(element));
            }

            in.endArray();
        }

        return deserializedObject;
    }
}

最后,我们将适配器注册到equationList的{​​{1}}字段中

Grid

这应该正确处理您的回复,如下所示

public class Grid {

    @SerializedName("category")
    @Expose
    private String category;

    @SerializedName("type")
    @Expose
    private String type;

    @SerializedName("title")
    @Expose
    private String title;

    @JsonAdapter(value = EquationListJsonAdapter.class)
    @SerializedName("equation_list")
    @Expose
    private EquationList equationList;

}

请注意,任何"equation_list": "7", or "equation_list": [7] 响应都会自动转换为String并作为列表元素添加到Integer中。您可以通过更改EquationList的{​​{1}}方法中的实现来更改此行为。

我希望这会有所帮助。干杯!