我正在使用Gson读取JSON响应,该响应返回somtimes NumberFormatException
,因为预期的int
值设置为空字符串。现在我想知道处理这种异常的最佳方法是什么。如果值为空字符串,则反序列化应为0。
预期的JSON响应:
{
"name" : "Test1",
"runtime" : 90
}
但有时运行时是一个空字符串:
{
"name" : "Test2",
"runtime" : ""
}
java类看起来像这样:
public class Foo
{
private String name;
private int runtime;
}
反序列化是这样的:
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
Gson gson = new Gson();
Foo foo = gson.fromJson(input, Foo.class);
抛出com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
因为返回空String而不是int值。
有没有办法告诉Gson,“如果您反序列化类型runtime
的字段Foo
并且存在NumberFormatException,则只返回默认值0 ” ?
我的解决方法是使用String
作为runtime
字段的类型而不是int
,但也许有更好的方法来处理此类错误。
答案 0 :(得分:30)
这是我为Long类型做的例子。这是更好的选择:
public class LongTypeAdapter extends TypeAdapter<Long>{
@Override
public Long read(JsonReader reader) throws IOException {
if(reader.peek() == JsonToken.NULL){
reader.nextNull();
return null;
}
String stringValue = reader.nextString();
try{
Long value = Long.valueOf(stringValue);
return value;
}catch(NumberFormatException e){
return null;
}
}
@Override
public void write(JsonWriter writer, Long value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(value);
}
}
您可以参考this link了解更多信息。
答案 1 :(得分:14)
首先,我尝试为Integer值编写一个通用的自定义类型适配器,以捕获NumberFormatException
并返回0,但Gson不允许TypeAdaptors用于原始类型:
java.lang.IllegalArgumentException: Cannot register type adapters for class java.lang.Integer
之后我为FooRuntime
字段引入了新的runtime
类型,因此Foo
类现在看起来像这样:
public class Foo
{
private String name;
private FooRuntime runtime;
public int getRuntime()
{
return runtime.getValue();
}
}
public class FooRuntime
{
private int value;
public FooRuntime(int runtime)
{
this.value = runtime;
}
public int getValue()
{
return value;
}
}
类型适配器处理自定义反序列化过程:
public class FooRuntimeTypeAdapter implements JsonDeserializer<FooRuntime>, JsonSerializer<FooRuntime>
{
public FooRuntime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
int runtime;
try
{
runtime = json.getAsInt();
}
catch (NumberFormatException e)
{
runtime = 0;
}
return new FooRuntime(runtime);
}
public JsonElement serialize(FooRuntime src, Type typeOfSrc, JsonSerializationContext context)
{
return new JsonPrimitive(src.getValue());
}
}
现在有必要使用GsonBuilder
注册类型适配器,因此空字符串被解释为0而不是抛出NumberFormatException
。
String input = "{\n" +
" \"name\" : \"Test\",\n" +
" \"runtime\" : \"\"\n" +
"}";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(FooRuntime.class, new FooRuntimeTypeAdapter());
Gson gson = builder.create();
Foo foo = gson.fromJson(input, Foo.class);
答案 2 :(得分:10)
快速简便的解决方法 - 只需将运行时的成员类型字段更改为String,然后通过将运行时返回为int的getter访问它:
public class Foo
{
private String name;
private String runtime;
public int getRuntime(){
if(runtime == null || runtime.equals("")){
return 0;
}
return Integer.valueOf(trackId);
}
}
=&GT;没有json反序列化需要
答案 3 :(得分:6)
我已经制作了这个TypeAdapter来检查空字符串并返回0
public class IntegerTypeAdapter extends TypeAdapter<Number> {
@Override
public void write(JsonWriter jsonWriter, Number number) throws IOException {
if (number == null) {
jsonWriter.nullValue();
return;
}
jsonWriter.value(number);
}
@Override
public Number read(JsonReader jsonReader) throws IOException {
if (jsonReader.peek() == JsonToken.NULL) {
jsonReader.nextNull();
return null;
}
try {
String value = jsonReader.nextString();
if ("".equals(value)) {
return 0;
}
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
}
答案 4 :(得分:2)
在NumberFormatException的情况下,对于字段0
,始终假设默认值为runtime
可能会有所帮助,因为它可能是唯一的错误来源。
答案 5 :(得分:1)
如另一条评论所述,从GSON 2.3.1开始,您可以注册基本类型的类型适配器,这是一个处理int和Integer类型的类型适配器,并且对于字符串,布尔值和空值。这将继续解析其中包含数字的字符串,例如“ runtime”:“ 5”。
public static final TypeAdapter<Number> UNRELIABLE_INTEGER = new TypeAdapter<Number>() {
@Override
public Number read(JsonReader in) throws IOException {
JsonToken jsonToken = in.peek();
switch (jsonToken) {
case NUMBER:
case STRING:
String s = in.nextString();
try {
return Integer.parseInt(s);
} catch (NumberFormatException ignored) {
}
try {
return (int)Double.parseDouble(s);
} catch (NumberFormatException ignored) {
}
return null;
case NULL:
in.nextNull();
return null;
case BOOLEAN:
in.nextBoolean();
return null;
default:
throw new JsonSyntaxException("Expecting number, got: " + jsonToken);
}
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
out.value(value);
}
};
public static final TypeAdapterFactory UNRELIABLE_INTEGER_FACTORY = TypeAdapters.newFactory(int.class, Integer.class, UNRELIABLE_INTEGER);
您可以使用以下代码进行注册
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(UNRELIABLE_INTEGER_FACTORY)
.create();
请注意,此示例替换的普通JsonReader.nextInt()尝试在令牌上调用parseInt和parseDouble,因此这将复制用于解析整数的内部逻辑。
答案 6 :(得分:0)
对于正在为kotlin寻找答案的人,请与最高答案相同,但不要这样做
registerTypeAdapter(Long.class.java, adapter)
做
registerTypeAdapter(java.lang.Long::class.java, adapter)
答案 7 :(得分:0)
此解决方案适用于Double类型。这仅适用于非基本类型:
public class DoubleGsonTypeAdapter implements JsonDeserializer<Double> {
@Override
public Double deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
Double result = null;
try {
result = jsonElement.getAsDouble();
} catch (NumberFormatException e) {
return result;
}
return result;
}
}
型号:
@SerializedName("rateOfInterest")
public Double rateOfInterest;
@SerializedName("repaymentTenure")
public Double repaymentTenure;
@SerializedName("emiAmount")
public Double emiAmount;
改装客户端:
Gson gson = new GsonBuilder().registerTypeAdapter(Double.class, new DoubleGsonTypeAdapter()) .create();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();