去fastjson筆記


fastjson近些年頻頻爆出安全漏洞,現在已經是互聯網的過街老鼠了,建議早去早好,網上搜索了下,相對而言google出品的gson目前還沒聽說有重大安全問題。下面是gson替換fastjson可能會遇到的一些坑。

 

一、美化輸出格式

new GsonBuilder().setPrettyPrinting().create();

 

二、自定義date的輸出格式

new GsonBuilder()
    .setPrettyPrinting() //美化輸出格式
    .setDateFormat("yyyy-MM-dd HH:mm:ss.SSS") //設置date字段的輸出格式
    .create();

寫一段單元測試代碼:

package test.nio.study;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.util.*;

public class GsonTest {

    public Gson gson() {
        return new GsonBuilder()
                .setPrettyPrinting() //美化輸出格式
                .setDateFormat("yyyy-MM-dd HH:mm:ss.SSS") //設置date字段的輸出格式
                .create();
    }

    @Data
    @NoArgsConstructor
    public class InnerTestClass {
        private Integer intField;
        private Long longField;
        private String strField;
        private Date dateField;
        private List<InnerTestClass> listField;
        private Map<String, String> mapField;
    }

    @Test
    public void testGson() {
        InnerTestClass test = new InnerTestClass();
        test.intField = 1;
        test.longField = 2L;
        test.dateField = new Date();
        test.mapField = new HashMap<>();
        test.mapField.put("test", "hello world");
        test.listField = new ArrayList<>();

        InnerTestClass test2 = new InnerTestClass();
        test2.dateField = new Date();
        test.listField.add(test2);

        System.out.println(gson().toJson(test));
    }
}

輸出如下:

{
  "intField": 1,
  "longField": 2,
  "dateField": "2020-06-14 23:04:17.202",
  "listField": [
    {
      "dateField": "2020-06-14 23:04:17.202"
    }
  ],
  "mapField": {
    "test": "hello world"
  }
}

  

三、兼容多種date字符串/timestamp的反序列化

{
    "dateField": "2020-06-14 23:04:17",
    "listField": [
        {
            "dateField": "2020-06-14 23:04:17.202"
        },
        {
            "dateField": 1592148201102
        },
        {
            "dateField": ""
        }
    ]
}

如果上面這段json,嘗試用剛才生成的gson實例反序列化的話,會報錯Invalid time zone indicator ' ',原因是 第1個dateField沒有帶.SSS的毫秒部分,第3個dateField是一個timestamp的long型數字,更無法匹配yyyy-MM-dd HH:mm:ss.SSS,第4個是空字符串,仍然無法匹配。

可以參考下面這樣:

public Gson gson() {
    String dateFormatWithMS = "yyyy-MM-dd HH:mm:ss.SSS";
    String dateFormatNoMS = "yyyy-MM-dd HH:mm:ss";
    GsonBuilder builder = new GsonBuilder();
    builder.registerTypeAdapter(Date.class, (JsonDeserializer<Date>) (json, typeOfT, context) -> {
        if (json == null || json.toString().equalsIgnoreCase("\"\"")) {
            //空字符判斷
            return null;
        }
        JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
        SimpleDateFormat sdfMS = new SimpleDateFormat(dateFormatWithMS);
        SimpleDateFormat sdfNoMS = new SimpleDateFormat(dateFormatNoMS);
        Date dt = null;
        try {
            if (jsonPrimitive.isString()) {
                if (jsonPrimitive.getAsString().length() == 19) {
                    //這里只是示例,簡單用長度來判斷是哪種格式
                    //yyyy-MM-dd HH:mm:ss格式
                    dt = sdfNoMS.parse(json.getAsString());
                } else {
                    //yyyy-MM-dd HH:mm:ss.SSS格式
                    dt = sdfMS.parse(json.getAsString());
                }
            } else if (jsonPrimitive.isNumber()) { //兼容timestamp類型
                dt = new Date(jsonPrimitive.getAsLong());
            }
        } catch (Exception e) {
            //錯誤日志記錄,略
            e.printStackTrace();
        }
        return dt;
    });
    Gson gson = builder
            .setDateFormat(dateFormatWithMS)
            .setPrettyPrinting()
            .create();
    return gson;
}

這樣,剛才這4種情況的date解析都能兼容了。

 

四、字段別名

@SerializedName(value = "int_field", alternate = {"aaa", "bbb"})
private Integer intField;    

這樣的話,json字符串中的int_field, aaa, bbb這3種名字,都能映射到intField上。 

 

五、數組解析

    @Test
    public void testParseList() {
        String json = "[\"A\",\"B\",\"C\"]";
        List<String> list1 = gson().fromJson(json, new TypeToken<List<String>>() {
        }.getType());
        System.out.println(list1.size());
    }

TypeToken是個很有用的東西,建議大家多研究


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM