1. 问题描述
在前后端分离的开发模式下,前后端交互通常采用JSON格式数据自然会涉及到json字符串与JAVA对象之间的转换。java处理json字符串与java对象的互转,google家的Gson是个很好的工具。但是,在使用Gson反序列化字符串时,json中原本的Integer类型被转化为了Double类型。
2. 问题原因
Gson在实现具体的Json数据反序列化时,首先会根据传入的对象类型Type
获取类型适配器TypeAdapter
,然后根据获取的TypeAdapter
实现Json值到一个对象的转换。解析中比较关键的就是根据待解析的类型找到对应的类型适配器TypeAdapter<T>
类,如果找到类型适配器不合适,就可能造成解析后的数据出问题,类型适配器TypeAdapter
是一个抽象类。
反序列化过程中,如果找到类型适配器,则通过getAdapter()
方法查找到的是ObjectTypeAdapter
类型适配器,所以默认情况下是由ObjectTypeAdapter
类完成数据的解析。在调用ObjectTypeAdapter
的read()
方法时,所有数值类型NUMBER
都转换成了Double
类型,所以就有了前面出现的问题。到此,我们找到了问题的原因所在。出现这个问题,最根本的是Gson
在使用ObjectTypeAdapter
解析数值类型时,将其都当Double类型处理,而没有对类型进行细分处理。
Gson将Java中对应的double、long、int都统一为数值类型NUMBER。
3. 解决方法
3.1 重新实现TypeAdapter
(方法一)
package techscan.tsbarcode.utils;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MapTypeAdapter extends TypeAdapter<Object> {
@Override
public Object read(JsonReader in) throws IOException {
JsonToken token = in.peek();
switch (token) {
case BEGIN_ARRAY:
List<Object> list = new ArrayList<Object>();
in.beginArray();
while (in.hasNext()) {
list.add(read(in));
}
in.endArray();
return list;
case BEGIN_OBJECT:
Map<String, Object> map = new LinkedTreeMap<String, Object>();
in.beginObject();
while (in.hasNext()) {
map.put(in.nextName(), read(in));
}
in.endObject();
return map;
case STRING:
return in.nextString();
case NUMBER:
/**
* 改写数字的处理逻辑,将数字值分为整型与浮点型。
*/
String numberStr = in.nextString();
if (numberStr.contains(".") || numberStr.contains("e")
|| numberStr.contains("E")) {
return Double.parseDouble(numberStr);
}
if (Long.parseLong(numberStr) <= Integer.MAX_VALUE) {
return Integer.parseInt(numberStr);
}
return Long.parseLong(numberStr);
case BOOLEAN:
return in.nextBoolean();
case NULL:
in.nextNull();
return null;
default:
throw new IllegalStateException();
}
}
@Override
public void write(JsonWriter out, Object value) throws IOException {
// 序列化无需实现
}
}
使用方法:
String json = "{\n" +
" \"z\": 100,\n" +
" \"x\": 200,\n" +
" \"c\": 300,\n" +
" \"v\":\"中文\",\n" +
" \"b\":true\n" +
"}";
Gson gson = new GsonBuilder()
.registerTypeAdapter(new TypeToken<Map<String, Object>>() {
}.getType(), new MapTypeAdapter()).create();
Map<String, Object> map = gson.fromJson(json, new TypeToken<Map<String, Object>>() {
}.getType());
3.2 使用java bean
接收(方法二)
保留
参考:
- https://my.oschina.net/MIKEWOO/blog/2994643
- https://blog.csdn.net/weixin_33796177/article/details/87123608
- http://www.lidetao.com/java-gson-json2map-int2double.html
版权声明:本文为lijingjingchn原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。