是否有可能允许Gson跳过错误类型的字段?

时间:2016-10-26 10:25:04

标签: java json gson android

我有一个来自SDK但没有权限进行更改的课程,但是我想将一个JSON有效的字符串序列化为。

但是,外部API有时会为Date字段输入错误的类型。

长话短说:我可以忽略GSON中的错误,或者告诉Gson忽略字段上的错误,然后获取部分对象吗?

例如,该字段应为double,但我得到一个Date(数字)。但是我还是没有使用它,所以我不在乎,我也不需要整个过程失败。我只想要parcable字段,故障字段保留为null。

注意:编写一个反序列化器来创建我想要由Gson创建的对象,这违背了我提出的目的。

这是一行失败的代码,因为单个字段是错误的:

Customer customer = gson.fromJson(settings.getCustomerObjectJSONString(), Customer.class);

我希望它只是跳过它无法解析的字段,因为我无法访问Customer类,因为它来自生成的SDK /库。

2 个答案:

答案 0 :(得分:1)

我知道有两种选择。

您可以使用 JSON反序列化程序实现来自行解析JSON元素。但是,以下示例将影响传递给该单个double实例的任何DTO的所有Doublegson字段,并且此类行为可以是可解除的。不幸的是,我不知道是否可以以“上下文”的方式使用JsonDeserializer:例如如果这些字段是某个父类的字段,则让它适用于所有doubleDouble字段。

private static final class Dto {

    private double primitive;
    private Double nullable;
    private String string;

}

private static final class FailSafeDoubleJsonDeserializer
        implements JsonDeserializer<Double> {

    @Override
    public Double deserialize(final JsonElement element, final Type type, final JsonDeserializationContext context)
            throws JsonParseException {
        if ( !element.isJsonPrimitive() ) {
            return null;
        }
        try {
            final JsonPrimitive primitive = (JsonPrimitive) element;
            final Number number = primitive.getAsNumber();
            return number.doubleValue();
        } catch ( final NumberFormatException ignored ) {
            return null;
        }
    }

}

private static final JsonDeserializer<Double> failSafeDoubleJsonDeserializer = new FailSafeDoubleJsonDeserializer();

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapter(double.class, failSafeDoubleJsonDeserializer)
        .registerTypeAdapter(Double.class, failSafeDoubleJsonDeserializer)
        .create();

public static void main(final String... args) {
    dump(gson.fromJson("{\"primitive\": 23, \"nullable\": 42, \"string\": \"foo bar\"}", Dto.class));
    dump(gson.fromJson("{\"primitive\": \"whatever\", \"nullable\": \"whatever\", \"string\": \"foo bar\"}", Dto.class));
}

private static void dump(final Dto dto) {
    out.println(dto.primitive + " " + dto.nullable + " " + dto.string);
}

另一个更低级别的选项可以是类型适配器实现。与前一个示例相比,这一优势的一个优点是,您可以使用已知可能已损坏的DTO类中的@JsonAdapter注释来注释失败的字段。

private static final class Dto {

    @JsonAdapter(FailSafeDoubleTypeAdapter.class)
    private double primitive;

    @JsonAdapter(FailSafeDoubleTypeAdapter.class)
    private Double nullable;

    private String string;

}

private static final class FailSafeDoubleTypeAdapter
        extends TypeAdapter<Double> {

    @Override
    public void write(final JsonWriter writer, final Double value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Double read(final JsonReader reader)
            throws IOException {
        final JsonToken peek = reader.peek();
        if ( peek != NUMBER ) {
            reader.skipValue();
            return null;
        }
        return reader.nextDouble();
    }

}

private static final Gson gson = new Gson();

public static void main(final String... args) {
    dump(gson.fromJson("{\"primitive\": 23, \"nullable\": 42, \"string\": \"foo bar\"}", Dto.class));
    dump(gson.fromJson("{\"primitive\": \"whatever\", \"nullable\": {\"subValue\": \"whatever\"}, \"string\": \"foo bar\"}", Dto.class));
}

private static void dump(final Dto dto) {
    out.println(dto.primitive + " " + dto.nullable + " " + dto.string);
}

因此,两个示例都生成以下输出:

  

23.0 42.0 foo bar

     

0.0 null foo bar

  • {"primitive": 23, "nullable": 42, "string": "foo bar"}
  • {"primitive": "whatever", "nullable": {"subValue": "whatever"}, "string": "foo bar"}
分别是

有效载荷。

答案 1 :(得分:1)

我从另一个角度看问题,即OP中提到的主要要求是

1)您不关心特定领域中存在的值

2)您不会使用特定字段值,也不希望解串器因数据无效而失败

在上述情况下,您可以将特定字段标记为TRANSIENT或STATIC。默认情况下,Gson将排除所有标记为瞬态或静态的字段。

示例: -

private transient Date joiningDate;