我有一个来自SDK的类,我无法访问更改,但我想将json有效的字符串序列化为。
但是,外部API有时会为Date字段输入错误的类型。
长话短说:我可以忽略GSON中的错误,或者告诉GSON忽略字段上的错误,只是得到部分对象吗?
例如,该字段应该是双精度类型,但我得到的却是Date(number)。但反正我不会用它,所以我不在乎,我也不希望整个过程失败。我只是想把可分割的字段拿出来,错误的字段为空。
注意:编写一个反序列化器来创建我想由Gson创建的对象,这违背了我提出的目的。
这是一行失败的代码,因为单个字段是错误的:
Customer customer = gson.fromJson(settings.getCustomerObjectJSONString(), Customer.class);
我希望它只是跳过它无法解析的字段,因为我无法访问Customer类,因为它来自生成的SDK/库。
我知道有两个选择。
你可以使用一个JSON反序列化器实现来自己解析JSON元素。然而,对于传递给单个gson
实例的任何dto,下面的示例将影响所有double
和Double
字段,并且这样的行为可能是可取的。不幸的是,我不知道是否有可能在"上下文中"使用JsonDeserializer
。方法:例如,让它对所有double
和Double
字段工作,如果这些字段是某个父类的字段。
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);
}
因此,两个示例都生成以下输出:
foo bar
0.0 null foo bar
-
{"primitive": 23, "nullable": 42, "string": "foo bar"}
- 和
{"primitive": "whatever", "nullable": {"subValue": "whatever"}, "string": "foo bar"}
分别载荷。
我从另一个角度看问题,即OP中提到的主要要求是
1)你不关心特定字段
中的值2)您不打算使用特定的字段值,并且不希望反序列化器因为无效数据
而失败在上面的例子中,您可以将特定字段标记为TRANSIENT或STATIC。默认情况下,Gson将排除所有标记为瞬态或静态的字段。
: -
private transient Date joiningDate;