Gson和FastJson 数据转换的坑

1 Gson

1.1 Gson介绍:

  • GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库。可以将一个Json字符转成一个Java对象,或者将一个Java转化为Json字符串。

1.2 遇到的问题:本人在工作时遇到过这类问题:将Json转换为Java对象会发现精度丢失的问题,具体案例如下:

    public static void transferJsonToMap() {
        String json = "{"birthday":"1996-03-18","date":"May 10, 2019 3:32:17 PM","name":"joebig7","weight":65.5,"id":1412102169,"age":24,"height":179.2}";

        //将Json转换为Map
        Map<String, Object> map = JsonUtil.fromJson(json, new TypeToken<Map<String, Object>>() {
        }.getType());
        System.out.println(map);
    }
  
   输出结果如下:
   {birthday=1996-03-18, date=May 10, 2019 3:32:17 PM, name=joebig7, weight=65.5, id=1.412102169E9, age=24.0, height=179.2}

可以发现通过Gson进行转换后Map中的int类型变为了Double,然后Long类型变为了科学计数法的。

1.3 解决方法

  • 1 重写类型适配器:首先需要明确的是,Gson通过一个类ObjectTypeAdapter来进行类型的转换,主要代码如下:

ERdecn.png

可以看见,Gson对于数据类型没有做具体的区分,统一转换成了Long类型。可以通过自定义一个类型转换器来解决这个问题,具体d代码如下: 代码重写了对Number类型对的处理逻辑

 public final class GeneralTypeAdapter 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 var1 = in.nextString();
                if (var1.contains(".") || var1.contains("e") || var1.contains("E")) {
                    return Double.parseDouble(var1);
                }
                return Long.parseLong(var1);

            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 {

    }

}
    public static <T> T fromJson(String json, Type T) {
        GsonBuilder gsonBuilder = new GsonBuilder();

        Gson gson = gsonBuilder.registerTypeAdapter(new TypeToken<Map<String, Object>>() {
        }.getType(), new GeneralTypeAdapter()).create();

        return gson.fromJson(json, T);
    }

在实际使用中,最好将json转换到具体的Bean对象就不会存在类型的问题。

2 FastJson

2.1 FastJson介绍: 和Gson类型,Fastjson是一个Java语言编写的JSON处理器。

  • 遇到的问题:通过FastJson将json转换成JSONObject或者Map类型的时候,对于浮点类型会被默认转换成BigDecimal类型

2.2 解决方式:

    // 1 可以通过全局设置,禁用BigDeccimal的方式来解决这个问题
     public static void getJsonObject(String str){
        JSON.DEFAULT_PARSER_FEATURE &= ~Feature.UseBigDecimal.getMask();
        Map map = JSON.parseObject(str, Map.class);
        System.out.println(map.toString());
    }
    
    
    // 2 可以通过局部设置,禁用BigDeccimal
    public static void getJsonObject(String str){
        int disableDecimalFeature = JSON.DEFAULT_PARSER_FEATURE & ~Feature.UseBigDecimal.getMask();
        Map map = JSON.parseObject(str, Map.class,disableDecimalFeature);
        System.out.println(map.toString());
    }

不过在实际项目中,最好是定义具体的bean来进行转换就不会出现这类问题

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章