【问题标题】:Retrofit Call has same name different data type改造调用具有相同的名称不同的数据类型
【发布时间】:2019-07-03 04:13:04
【问题描述】:

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

我如何满足我的要求?

【问题讨论】:

    标签: java json gson retrofit2


    【解决方案1】:

    我认为您可以创建一个类型来处理 StringArrayList 两种数据类型。然后你可以为 GSON 实现一个自定义的JsonAdapter 来处理这个类型的自定义反序列化。

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

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

    在我们为EquationList 类型实现JsonAdapter 之后

    /**
     * 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;
        }
    }
    

    最后我们将适配器注册到Grid 中的equationList 字段

    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。您可以通过更改 EquationListJsonAdapterread 方法中的实现来更改此行为。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-12
      • 1970-01-01
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      • 2021-10-09
      • 2011-11-20
      相关资源
      最近更新 更多