使用Gson将对象json字符串转化成对象遇到的问题

场景一:存在一个对象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, JsonDeserializer {
	/**
	 * Gson invokes this call-back method during deserialization when it encounters
	 * a field of the specified type.
	 * 

* 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. * *

* 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). *

* * @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, JsonDeserializer {
	/**
	 * Gson invokes this call-back method during deserialization when it encounters
	 * a field of the specified type.
	 * 

* 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. * *

* 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). *

* * @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));

	}

}

结果:
使用Gson将对象json字符串转化成对象遇到的问题_第1张图片
场景二:如果对象中含有日期或时间等属性值,最好将类型定义为String,如果定义为Date类型,那么它在json字符串中可能存在值为空字符串,反序列化时,会转换失败,如下图所示:
使用Gson将对象json字符串转化成对象遇到的问题_第2张图片

你可能感兴趣的:(java,Json)