赞
踩
场景一:存在一个对象User的json字符串,json字符串中存在对象类型为Integer或Double的属性值为空字符串,使用Gson将字符串转换为对象时报错,报错信息如下:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:241) at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:231) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172) at com.google.gson.Gson.fromJson(Gson.java:803) at com.google.gson.Gson.fromJson(Gson.java:768) at com.google.gson.Gson.fromJson(Gson.java:717) at com.google.gson.Gson.fromJson(Gson.java:689) at JsonMain.main(JsonMain.java:15) Caused by: java.lang.NumberFormatException: empty String at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842) at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.lang.Double.parseDouble(Double.java:538) at com.google.gson.stream.JsonReader.nextInt(JsonReader.java:1178) at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:239) ... 8 more
对象信息如下:
package com.gj.bean; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 6941951312521096768L; /** 用户id */ private Integer id; /** 用户名 */ private String name; /** 年龄 */ private Integer age; /** 体重 */ private Double weight; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getWeight() { return weight; } public void setWeight(Double weight) { this.weight = weight; } }
使用代码如下:
import com.gj.bean.User;
import com.google.gson.Gson;
public class JsonMain {
public static void main(String[] args) {
String json = "{\"id\":1,\"name\":\"test1\",\"age\":\"\"}";
User obj = new Gson().fromJson(json, User.class);
}
}
原因:Gson转换时将空字符串设置到Integer或Double类型的属性上,导致类型不匹配报错
解决办法:针对不同的数值类型的场景,写对应场景的类型转换器,实现Gson的序列化和反序列化接口:JsonSerializer接口和JsonDeserializer,在反序列化接口方法中,判断json值是否为空字符串值,如果是,则返回null或对应类型的默认值
如下所示:
DoubleDefaultNullAdapter.java
package com.gj.config; import java.lang.reflect.Type; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonSyntaxException; /** * @Description 将json字符串中Double类型字段值为空字符串的转化为null * @Author gj * @Date 2019/7/15 * @Version 1.0 **/ public class DoubleDefaultNullAdapter implements JsonSerializer<Double>, JsonDeserializer<Double> { /** * Gson invokes this call-back method during deserialization when it encounters * a field of the specified type. * <p> * In the implementation of this call-back method, you should consider invoking * {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to * create objects for any non-trivial field of the returned object. However, you * should never invoke it on the the same type passing {@code json} since that * will cause an infinite loop (Gson will call your call-back method again). * * @param json * The Json data being deserialized * @param typeOfT * The type of the Object to deserialize to * @param context * @return a deserialized object of the specified type typeOfT which is a * subclass of {@code T} * @throws JsonParseException * if json is not in the expected format of {@code typeofT} */ public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("")) { // 定义为double类型,如果后台返回"",则返回null return null; } } catch (Exception ignore) { } try { return json.getAsDouble(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } /** * Gson invokes this call-back method during serialization when it encounters a * field of the specified type. * * <p> * In the implementation of this call-back method, you should consider invoking * {@link JsonSerializationContext#serialize(Object, Type)} method to create * JsonElements for any non-trivial field of the {@code src} object. However, * you should never invoke it on the {@code src} object itself since that will * cause an infinite loop (Gson will call your call-back method again). * </p> * * @param src * the object that needs to be converted to Json. * @param typeOfSrc * the actual type (fully genericized version) of the source object. * @param context * @return a JsonElement corresponding to the specified object. */ public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
IntegerDefaultNullAdapter.java
package com.gj.config; import java.lang.reflect.Type; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonSyntaxException; /** * @Description 将json字符串中Integer类型字段值为空字符串的转化为null * @Author gj * @Date 2019/7/15 * @Version 1.0 **/ public class IntegerDefaultNullAdapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> { /** * Gson invokes this call-back method during deserialization when it encounters * a field of the specified type. * <p> * In the implementation of this call-back method, you should consider invoking * {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to * create objects for any non-trivial field of the returned object. However, you * should never invoke it on the the same type passing {@code json} since that * will cause an infinite loop (Gson will call your call-back method again). * * @param json * The Json data being deserialized * @param typeOfT * The type of the Object to deserialize to * @param context * @return a deserialized object of the specified type typeOfT which is a * subclass of {@code T} * @throws JsonParseException * if json is not in the expected format of {@code typeofT} */ public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("")) { // 定义为Integer类型,如果后台返回"",则返回null return null; } } catch (Exception ignore) { } try { return json.getAsInt(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } /** * Gson invokes this call-back method during serialization when it encounters a * field of the specified type. * * <p> * In the implementation of this call-back method, you should consider invoking * {@link JsonSerializationContext#serialize(Object, Type)} method to create * JsonElements for any non-trivial field of the {@code src} object. However, * you should never invoke it on the {@code src} object itself since that will * cause an infinite loop (Gson will call your call-back method again). * </p> * * @param src * the object that needs to be converted to Json. * @param typeOfSrc * the actual type (fully genericized version) of the source object. * @param context * @return a JsonElement corresponding to the specified object. */ public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
使用方式:
import com.gj.bean.User; import com.gj.config.DoubleDefaultNullAdapter; import com.gj.config.IntegerDefaultNullAdapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class JsonMain { public static void main(String[] args) { String json = "{\"id\":1,\"name\":\"test1\",\"age\":\"\"}"; // User obj = new Gson().fromJson(json, User.class); Gson gson = new GsonBuilder().registerTypeAdapter(Integer.class, new IntegerDefaultNullAdapter()) .registerTypeAdapter(Double.class, new DoubleDefaultNullAdapter()).create(); User obj = gson.fromJson(json, User.class); System.out.println(gson.toJson(obj)); } }
结果:
场景二:如果对象中含有日期或时间等属性值,最好将类型定义为String,如果定义为Date类型,那么它在json字符串中可能存在值为空字符串,反序列化时,会转换失败,如下图所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。