【问题标题】:GSON converting Integer value to Boolean value dynamically for specific fieldsGSON 为特定字段动态地将整数值转换为布尔值
【发布时间】:2019-08-01 04:15:35
【问题描述】:

如何处理获得相同名称但类型不同的字段?在同一个请求中,我有时会从 API 获取整数值,有时会获取布尔值。我想知道当我得到这样的 Json 时如何处理。我创建了类型适配器,但它不起作用

我想过创建不同的 POJO 类。但是这个问题不仅仅针对一个请求。由于这个原因,我不喜欢创建 POJO。顺便说一句,我看到了类似的问题,但它并没有解决我的问题。

{
  "name" : "john doe",
  "isValid" : true 
}

有时我会明白

{
  "name" : "john doe",
  "isValid" : 1 
}

获取整数时出现意外的 json 异常

class XModel{
    private boolean isValid;
    ...
    ...
}

我想为每个请求返回一个布尔值。有谁知道如何解决这个问题?

编辑: 我想通过类型适配器阻止 instanceOf 关键字


解决方案:@Michał Ziober 的回复对我有用。

class BooleanJsonDeserializer implements JsonDeserializer<Boolean> {

    private final Set<String> TRUE_STRINGS = new HashSet<>(Arrays.asList("true", "1", "yes"));

    @Override
    public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        System.out.println(json);
        JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
        if (jsonPrimitive.isBoolean()) {
            return jsonPrimitive.getAsBoolean();
        } else if (jsonPrimitive.isNumber()) {
            return jsonPrimitive.getAsNumber().intValue() == 1;
        } else if (jsonPrimitive.isString()) {
            return TRUE_STRINGS.contains(jsonPrimitive.getAsString().toLowerCase());
        }

        return false;
    }
}

【问题讨论】:

  • 该类在 Kotlin 或 Java 中无效
  • 我同意 :) 我编辑了,只是缺乏关注。
  • 另见stackoverflow.com/questions/23920740/…。可以从 JSON 中删除空对象和数组,但需要从一个字符串转换为另一个字符串。我仍在寻找创建生成器。

标签: java android json serialization gson


【解决方案1】:

我认为执行此映射并不容易,但以下内容可能会有所帮助。

public void setIsValid(Object isValid) {
    String isValidString = String.valueOf(isValid).replace("0", "false").replace("1", "true");
    return Boolean.valueOf(isValidString);
}

【讨论】:

  • 感谢您回复@Yassin Hajaj。您知道它不是最佳解决方案。它会导致重复代码。但它有效。
【解决方案2】:

如果XModel 类不大,您可以编写自定义反序列化器,如下所示,您可以控制传入元素:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class GsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(XModel.class, new XModelJsonDeserializer())
                .create();

        System.out.println(gson.fromJson(new FileReader(jsonFile), XModel.class));
    }
}

class XModelJsonDeserializer implements JsonDeserializer<XModel> {

    private final Set<String> TRUE_STRINGS = new HashSet<>(Arrays.asList("true", "1", "yes"));

    @Override
    public XModel deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        XModel response = new XModel();
        JsonObject jsonResponse = (JsonObject) json;
        response.setName(jsonResponse.get("name").getAsString());
        // other fields

        JsonElement dataElement = jsonResponse.get("isValid");
        if (dataElement.isJsonNull()) {
            response.setValid(false);
        } else if (dataElement.isJsonPrimitive()) {
            JsonPrimitive jsonPrimitive = dataElement.getAsJsonPrimitive();
            if (jsonPrimitive.isBoolean()) {
                response.setValid(jsonPrimitive.getAsBoolean());
            } else if (jsonPrimitive.isNumber()) {
                response.setValid(jsonPrimitive.getAsNumber().intValue() == 1);
            } else if (jsonPrimitive.isString()) {
                response.setValid(TRUE_STRINGS.contains(jsonPrimitive.getAsString()));
            }
            System.out.println("Json data is primitive: " + dataElement.getAsString());
        } else if (dataElement.isJsonObject() || dataElement.isJsonArray()) {
            response.setValid(true); //?!?!
        }

        return response;
    }
}

对于JSON以下有效载荷:

{
  "name" : "john doe",
  "isValid" : true
}

上面的程序打印:

Json data is primitive: true
XModel{name='john doe', isValid=true}

对于JSON 有效载荷:

{
  "name" : "john doe",
  "isValid" : 1
}

打印:

Json data is primitive: 1
XModel{name='john doe', isValid=true}

您的模型很清晰,因为所有工作都在反序列化器级别完成。

更精确的解决方案是仅序列化primitive。假设模型如下所示:

class XModel {

    private String name;

    @JsonAdapter(value = BooleanJsonDeserializer.class)
    private boolean isValid;

    // getters, setters
}

我们的BooleanJsonDeserializer反序列化器如下所示:

class BooleanJsonDeserializer implements JsonDeserializer<Boolean> {

    private final Set<String> TRUE_STRINGS = new HashSet<>(Arrays.asList("true", "1", "yes"));

    @Override
    public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        System.out.println(json);
        JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
        if (jsonPrimitive.isBoolean()) {
            return jsonPrimitive.getAsBoolean();
        } else if (jsonPrimitive.isNumber()) {
            return jsonPrimitive.getAsNumber().intValue() == 1;
        } else if (jsonPrimitive.isString()) {
            return TRUE_STRINGS.contains(jsonPrimitive.getAsString().toLowerCase());
        }

        return false;
    }
}

您只需在模型中使用此适配器注释每个 boolean 属性,即可处理:1True 等。

【讨论】:

  • 感谢@Michał Ziober 的回复。如果只有几个类,这种方法是可以接受的。但我需要一个适用于整个模型的解决方案。
  • @Beyazidy,我知道这可能是一个有问题的解决方案。我的更新仅显示布尔原语的新反序列化器。它可以处理您需要的所有情况。希望你的情况会好得多。
  • 谢谢@Michał Ziober,这个反序列化器有效:)
【解决方案3】:

您可以从Apache Commons Lang 中查看BooleanUtilities。有一种方法可以将不同类型的字符串(和其他对象)解析为布尔值。

System.out.println(BooleanUtils.toBoolean(1));
System.out.println(BooleanUtils.toBoolean(true));
System.out.println(BooleanUtils.toBoolean("TrUe"));
System.out.println(BooleanUtils.toBoolean("true"));

输出

true
true
true
true

但是 BooleanUtils.toBoolean("1");false 所以你可以像这样组合它:

String isValid = jsonPrimitive.get("isValid").getAsString();
System.out.println(BooleanUtils.toBoolean(isValid) || isValid.equals("1"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 2020-04-08
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多