Fastjson 專題



https://github.com/eishay/jvm-serializers/wiki 

TypeReference

1. 基礎使用

在fastjson中提供了一個用於處理泛型反序列化的類TypeReference。

import com.alibaba.fastjson.TypeReference; List<VO> list = JSON.parseObject("...", new TypeReference<List<VO>>() {});

如下寫法有更好的性能

import com.alibaba.fastjson.TypeReference; final static Type type = new TypeReference<List<VO>>() {}.getType(); List<VO> list = JSON.parseObject("...", type);

在這里例子中,通過TypeReference能夠解決List中T的類型問題。

    @Test
    public void TestListGenerics() {
        List<UserDO> userDOList = Arrays.asList(new UserDO(1L, "Name1"), new UserDO(2L, "Name2"));
        String userListStr = JSON.toJSONString(userDOList);
        List<UserDO> userDOS = JSON.parseArray(userListStr, UserDO.class);
        assertThat(userDOS.size()).isEqualTo(userDOList.size());
        assertThat(userDOS.get(0)).isEqualToComparingFieldByField(userDOList.get(0));
        assertThat(userDOS.get(1)).isEqualToComparingFieldByField(userDOList.get(1));
        System.out.println(userDOS);
        List<UserDO> result = JSON.parseObject(userListStr, new TypeReference<List<UserDO>>() {
        }.getType());
        assertThat(result.size()).isEqualTo(userDOList.size());
        assertThat(result.get(0)).isEqualToComparingFieldByField(userDOList.get(0));
        assertThat(result.get(1)).isEqualToComparingFieldByField(userDOList.get(1));
        System.out.println(result);
    }

 



2. 帶參數使用

在1.2.9 & 1.1.49.android版本中,TypeReference支持泛型參數,方便一些框架實現通用的反序列化類。用法如下:

2.1. 單參數例子

public class Response<T> { public T data; } public static <T> Response<T> parseToMap(String json, Class<T> type) { return JSON.parseObject(json, new TypeReference<Response<T>>(type) {}); }

2.2. 雙參數例子

public static <K, V> Map<K, V> parseToMap(String json, Class<K> keyType, Class<V> valueType) { return JSON.parseObject(json, new TypeReference<Map<K, V>>(keyType, valueType) { }); } // 可以這樣使用 String json = "{1:{name:\"ddd\"},2:{name:\"zzz\"}}"; Map<Integer, Model> map = parseToMap(json, Integer.class, Model.class); assertEquals("ddd", map.get(1).name); assertEquals("zzz", map.get(2).name);

https://github.com/alibaba/fastjson/wiki/TypeReference


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.lang.reflect.Type;

/**
 * @Auther: cheng.tang
 * @Date: 2019/7/31
 * @Description:
 */
public class GsonTest {

    private static final String source = "{\"code\":500,\"data\":\"\",\"msg\":\"未知異常\",\"success\":false}";


    /**
     * com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 21 path $.data
     * <p>
     * at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
     * at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
     * at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
     * at com.google.gson.Gson.fromJson(Gson.java:922)
     * at com.google.gson.Gson.fromJson(Gson.java:887)
     * at com.google.gson.Gson.fromJson(Gson.java:836)
     * at com.zkh360.gbb.user.utils.GsonTest.gsonDeserializationTest(GsonTest.java:36)
     * at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     * at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
     * at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     * at java.lang.reflect.Method.invoke(Method.java:498)
     * at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
     * at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
     * at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
     * at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
     * at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
     * at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
     * at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
     * at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
     * at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
     * at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
     * at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
     * at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
     * at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
     * at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
     * at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
     * at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
     * at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
     * at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
     * Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 21 path $.data
     * at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
     * at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:215)
     * ... 28 more
     */
    @Test(expected = JsonSyntaxException.class)
    public void gsonDeserializationTest() {
        Gson gson = new Gson();
        Type type = new TypeToken<ResultDTO<UserIdDTO>>() {
        }.getType();
        ResultDTO<UserIdDTO> resultDTO = gson.fromJson(source, type);
        System.out.println(JSON.toJSONString(resultDTO));
    }

    @Test
    public void fastjsonDeserializationTest() {
        ResultDTO<UserIdDTO> userIdDTOResultDTO = JSON.parseObject(source, new TypeReference<ResultDTO<UserIdDTO>>() {
        });
        System.out.println(JSON.toJSONString(userIdDTOResultDTO));
    }

}

 






fastjson實例化對象時,如果1,true 會轉換成true,其它的都為false 

import com.alibaba.fastjson.JSON;
import lombok.Data;
import org.junit.Test;

import static org.assertj.core.api.Java6Assertions.assertThat;

/**
 * @author: tangcheng
 * @description:
 * @since: Created in 2018/08/03 16:31
 */
public class JSONBooleanTypeTest {

    @Test
    public void testFastJson() {
        BooleanType booleanType = new BooleanType();
        booleanType.setEnable(true);
        String output = JSON.toJSONString(booleanType);
        assertThat(output).isEqualTo("{\"enable\":true}");

        /**
         * 字符串的值除了1和true外,都是false
         */
        BooleanType serialObj = JSON.parseObject("{\"enable\":true}", BooleanType.class);
        assertThat(serialObj.getEnable()).isTrue();
        serialObj = JSON.parseObject("{\"enable\":1}", BooleanType.class);
        assertThat(serialObj.getEnable()).isTrue();

        serialObj = JSON.parseObject("{\"enable\":false}", BooleanType.class);
        assertThat(serialObj.getEnable()).isFalse();
        serialObj = JSON.parseObject("{\"enable\":2}", BooleanType.class);
        assertThat(serialObj.getEnable()).isFalse();
        serialObj = JSON.parseObject("{\"enable\":0}", BooleanType.class);
        assertThat(serialObj.getEnable()).isFalse();

        serialObj = JSON.parseObject("{\"enable\":-1}", BooleanType.class);
        assertThat(serialObj.getEnable()).isFalse();
    }

    @Data
    public static class BooleanType {
        private Boolean enable;
    }
}

 

 

JSONObject.toJSONString(Object object, SerializerFeature... features)

SerializerFeature有用的一些枚舉值

QuoteFieldNames———-輸出key時是否使用雙引號,默認為true
WriteMapNullValue——–是否輸出值為null的字段,默認為false
WriteNullNumberAsZero—-數值字段如果為null,輸出為0,而非null
WriteNullListAsEmpty—–List字段如果為null,輸出為[],而非null
WriteNullStringAsEmpty—字符類型字段如果為null,輸出為”“,而非null
WriteNullBooleanAsFalse–Boolean字段如果為null,輸出為false,而非null

SerializerFeature.DisableCircularReferenceDetect ,
如果沒有設置這個參數會出現的問題【

FastJson如何解決循環引用/重復引用
fastjson支持循環引用/重復引用,並且是缺省打開的。
* 第一個例子序列化后輸出結果為:{"1":{},"2":{"$ref":"$.1"}}
第一個對象正常序列化,第二個對象則用引用表示
* 第二個列子序列化后輸出結果為:{"1":{"1":{"$ref":".."}}}

】:
如果對象中兩個字段存放的是相同的List 對象,則會出現這種情況
http://www.cnblogs.com/softidea/p/5873277.html

https://blog.csdn.net/qq_35873847/article/details/78850528



代碼:

                List<JobResVO> jobs = recommendJobBO.getJobs();
                resultResVO.setModern(jobs);
                resultResVO.setTraditional(jobs);

Converter中FastJson的配置:

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
                SerializerFeature.WriteEnumUsingToString,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
            if (source == null) {
                return "";
            }
            if (source instanceof Date) {
                return ((Date) source).getTime();
            }
            return source;
        });
        httpMessageConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(httpMessageConverter);
    }

 

解決辦法:

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
                SerializerFeature.WriteEnumUsingToString,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.DisableCircularReferenceDetect);
        fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
            if (source == null) {
                return "";
            }
            if (source instanceof Date) {
                return ((Date) source).getTime();
            }
            return source;
        });
        httpMessageConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(httpMessageConverter);
    }

 

上面的SerializerFeature主要是針對Object對象序列化轉換時的情況(這個時候才能判斷參數的類型),而在Map中,你放進入了null就是null,進行序列化時已經沒法判斷它原來的類型了,所以並沒有起作用。要使用SerializerFeature里相關null的參數,應該傳入對象進行序列化。

對規則的理解:

  1. SerializerFeature.WriteMapNullValue 是否輸出值為null的字段,默認為false也就是說有null時會輸出而不是忽略(默認策略是忽略,所以看不到為null的字段)

  2. WriteNullStringAsEmpty—字符類型字段如果為null,輸出為”“,而非null 
    注意是字段字段字段,而不是json.put("key",null),所以用它時,字段為null的可以轉換為空字符串。

  3. 如果讓輸出的json中所有為null的字符串都變成空字符串,最簡單的做法就是加一個值過濾器,這樣就避免了有的字段為null,有的字段為空字符的現象。

示例代碼

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;

public class Demo1 {

    public class Student {
        private String name;
        private int age;
        private boolean isMale;
        private Student gf;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public boolean isMale() {
            return isMale;
        }

        public void setMale(boolean isMale) {
            this.isMale = isMale;
        }

        public Student getGf() {
            return gf;
        }

        public void setGf(Student gf) {
            this.gf = gf;
        }
    }

    private static ValueFilter filter = new ValueFilter() {
        @Override
        public Object process(Object obj, String s, Object v) {
            if (v == null)
                return "";
            return v;
        }
    };

    public static void main(String[] args) {
        new Demo1().foo();
        new Demo1().bar();
    }

    private void foo() {
        System.out.println("foo()---------------------------");
        JSONObject j1 = new JSONObject();
        j1.put("name", "zhangsan");
        j1.put("age", 13);
        j1.put("isMale", true);
        j1.put("gf", null);
        Map<String, Object> fav = new HashMap<String, Object>();
        Set<String> books = new HashSet<String>();
        books.add("三國");
        books.add("史記");
        fav.put("history", books);
        String[] arts = new String[] {};
        fav.put("arts", arts);
        String[] musics = new String[] { "北京歡迎你", "畫心" };
        fav.put("musics", musics);
        List<String> sports = new ArrayList<String>();
        fav.put("sports", sports);
        j1.put("fav", fav);
        List<Student> classmates = new ArrayList<Student>();
        classmates.add(new Student());
        Student lisi = new Student();
        lisi.setMale(false);
        lisi.setAge(11);
        classmates.add(lisi);
        Student zhangsan = new Student();
        zhangsan.setAge(13);
        zhangsan.setName("張三");
        zhangsan.setMale(true);
        zhangsan.setGf(lisi);
        classmates.add(zhangsan);
        j1.put("classmates", classmates);
        String str = null;
        j1.put("str", str);
        System.out.println(j1.toString());
        System.out
            .println(JSON.toJSONString(j1, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty));
        System.out.println(
            JSON.toJSONString(j1, filter, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty));
        System.out.println(JSON.toJSONString(j1, SerializerFeature.WriteNullStringAsEmpty));
        System.out.println(JSON.toJSONString(j1, filter, SerializerFeature.WriteNullStringAsEmpty));

        Map<String, JSONObject> m = new HashMap<String, JSONObject>();
        m.put("key", j1);
        System.out.println(
            JSON.toJSONString(m, SerializerFeature.WriteNonStringKeyAsString, SerializerFeature.WriteNullStringAsEmpty));
        System.out.println(JSON.toJSONString(m, filter, SerializerFeature.WriteNonStringKeyAsString,
            SerializerFeature.WriteNullStringAsEmpty));

    }

    private void bar() {
        System.out.println("bar()---------------------------");
        Student zhangsan = new Student();
        zhangsan.setAge(13);
        zhangsan.setName("張三");
        zhangsan.setMale(true);
        Student lisi = new Student();
        // lisi.setName("lisi");
        lisi.setMale(false);
        lisi.setAge(11);
        zhangsan.setGf(lisi);
        System.out.println(
            JSON.toJSONString(zhangsan, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty));
        System.out.println(JSON.toJSONString(zhangsan, SerializerFeature.WriteMapNullValue));
        System.out.println(JSON.toJSONString(zhangsan, SerializerFeature.WriteNullStringAsEmpty));
        System.out.println(JSON.toJSONString(zhangsan));
        System.out.println(JSON.toJSONString(zhangsan, filter));
        System.out.println(JSON.toJSONString(zhangsan, filter, SerializerFeature.WriteMapNullValue,
            SerializerFeature.WriteNullStringAsEmpty));
    }

}

 

foo()---------------------------
{"isMale":true,"name":"zhangsan","classmates":[{"age":0,"male":false},{"age":11,"male":false},{"age":13,"gf":{"$ref":"$.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13}
{"str":null,"isMale":true,"name":"zhangsan","classmates":[{"age":0,"gf":null,"male":false,"name":""},{"age":11,"gf":null,"male":false,"name":""},{"age":13,"gf":{"$ref":"$.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13,"gf":null}
{"str":"","isMale":true,"name":"zhangsan","classmates":[{"age":0,"gf":"","male":false,"name":""},{"age":11,"gf":"","male":false,"name":""},{"age":13,"gf":{"$ref":"$.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13,"gf":""}
{"isMale":true,"name":"zhangsan","classmates":[{"age":0,"male":false},{"age":11,"male":false},{"age":13,"gf":{"$ref":"$.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13}
{"str":"","isMale":true,"name":"zhangsan","classmates":[{"age":0,"gf":"","male":false,"name":""},{"age":11,"gf":"","male":false,"name":""},{"age":13,"gf":{"$ref":"$.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13,"gf":""}
{"key":{"isMale":true,"name":"zhangsan","classmates":[{"age":0,"male":false},{"age":11,"male":false},{"age":13,"gf":{"$ref":"$.key.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13}}
{"key":{"str":"","isMale":true,"name":"zhangsan","classmates":[{"age":0,"gf":"","male":false,"name":""},{"age":11,"gf":"","male":false,"name":""},{"age":13,"gf":{"$ref":"$.key.classmates[1]"},"male":true,"name":"張三"}],"fav":{"sports":[],"musics":["北京歡迎你","畫心"],"history":["史記","三國"],"arts":[]},"age":13,"gf":""}}
bar()---------------------------
{"age":13,"gf":{"age":11,"gf":null,"male":false,"name":""},"male":true,"name":"張三"}
{"age":13,"gf":{"age":11,"gf":null,"male":false,"name":null},"male":true,"name":"張三"}
{"age":13,"gf":{"age":11,"male":false},"male":true,"name":"張三"}
{"age":13,"gf":{"age":11,"male":false},"male":true,"name":"張三"}
{"age":13,"gf":{"age":11,"gf":"","male":false,"name":""},"male":true,"name":"張三"}
{"age":13,"gf":{"age":11,"gf":"","male":false,"name":""},"male":true,"name":"張三"}

 

 

JsonPathTestData.json

{
  "store": {
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      {
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99,
        "isbn": "0-553-21311-3"
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}

 

 

    @Test
    public void testJsonPath() throws IOException {
        InputStream resourceAsStream = this.getClass().getResourceAsStream("/JsonPathTestData.json");
        String jsonStr = IOUtils.toString(resourceAsStream, "utf-8");
        System.out.println(jsonStr);

        System.out.println(jsonStr);
        JSONObject jsonObject = JSON.parseObject(jsonStr);

        System.out.println("\nBook數目:" + JSONPath.eval(jsonObject, "$.store.book.size()"));
        System.out.println("第一本書title:" + JSONPath.eval(jsonObject, "$.store.book[0].title"));
        System.out.println("price大於10元的book:" + JSONPath.eval(jsonObject, "$.store.book[price > 10]"));
        System.out.println("price大於10元的title:" + JSONPath.eval(jsonObject, "$.store.book[price > 10][0].title"));
        System.out.println("category(類別)為fiction(小說)的book:" + JSONPath.eval(jsonObject, "$.store.book[category = 'fiction']"));
        System.out.println("bicycle的所有屬性值" + JSONPath.eval(jsonObject, "$.store.bicycle.*"));
        System.out.println("bicycle的color和price屬性值" + JSONPath.eval(jsonObject, "$.store.bicycle['color','price']"));
    }


    @Test
    public void testGenerics() {
        Result<User> result = new Result<>();
        result.setMsg("Success");
        List<User> users = new ArrayList<>();
        users.add(new User(1L, "Name1"));
        users.add(new User(2L, "Name2"));
        result.setModule(users);
        String js = JSON.toJSONString(result);
        System.out.println(js);
        //java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.tangcheng.learning.json.User
//        Result<User> obj = (Result<User>) JSON.parseObject(js, Result.class);
        Result<User> userResult = JSON.parseObject(js, new TypeReference<Result<User>>() {
        });
        System.out.println(userResult);
    }

 

public class User {
    private Long id;
    private String name;

    public User() {
    }

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

}
import java.util.List;

public class Result<T> {

    private String msg;

    private List<T> module;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public List<T> getModule() {
        return module;
    }

    public void setModule(List<T> module) {
        this.module = module;
    }


    @Override
    public String toString() {
        return "Result{" +
                "msg='" + msg + '\'' +
                ", module=" + module +
                '}';
    }
}

 

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import lombok.Data;

@Data
public class Response<T> {
    private T data;

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }

    public static void main(String[] args) {
        String jsonText = "{\"data\":{\"id\":1,\"name\":\"張三\"}}";
        Response<User> response = JSON.parseObject(jsonText, new ParameterizedTypeImpl(new Class[]{User.class}, null, Response.class));
        /**
         * {"data":{"id":1,"name":"張三"}}
         */
        System.out.println(response);

        response = JSON.parseObject(jsonText, new TypeReference<Response<User>>() {
        });
        /**
         * {"data":{"id":1,"name":"張三"}}
         */
        System.out.println(response);
    }
}

@Data
class User {
    private Integer id;
    private String name;

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

 

 

 

https://www.slideshare.net/randfish/inside-googles-numbers-in-2017?next_slideshow=1



由於json中的key與bean中的屬性不能匹配,因此在轉換過程中出現了部分屬性為null的情況。經過查看官方文檔,發現可以使用@JSONField進行解釋,但是並沒有詳細的使用說明。

@JSONField的作用對象:
1. Field
2. Setter 和 Getter方法
注:FastJson在進行操作時,是根據getter和setter的方法進行的,並不是依據Field進行。

一、作用Field
@JSONField作用在Field時,其name不僅定義了輸入key的名稱,同時也定義了輸出的名稱。

二、作用在setter和getter方法上
顧名思義,當作用在setter方法上時,就相當於根據 name 到 json中尋找對應的值,並調用該setter對象賦值。
當作用在getter上時,在bean轉換為json時,其key值為name定義的值

在fastjson-1.2.12版本中,JSONField支持一個新的配置項jsonDirect
它的用途是:當你有一個字段是字符串類型,里面是json格式數據,你希望直接輸入,而不是經過轉義之后再輸出。
Model:

import com.alibaba.fastjson.annotation.JSONField;

public static class Model {
    public int id;
    @JSONField(jsonDirect=true)
    public String value;
}

Usage:

Model model = new Model();
model.id = 1001;
model.value = "{}";

String json = JSON.toJSONString(model);
Assert.assertEquals("{\"id\":1001,\"value\":{}}", json);

https://github.com/alibaba/fastjson/wiki/JSONField_jsonDirect_cn
https://github.com/alibaba/fastjson/issues/1244
http://www.cnblogs.com/softidea/p/5681928.html

fastjson 過濾不需要的字段或者只要某些字段

//第一種:在對象響應字段前加注解,這樣生成的json也不包含該字段。
@JSONField(serialize=false) private String name;  

 

第二種:在對象對應字段前面加transient,表示該字段不用序列化,即在生成json的時候就不會包含該字段了。
private transient  String name;  
transient使用小結
1)一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化后無法獲得訪問。
2)transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量如果是用戶自定義類變量,則該類需要實現Serializable接口。
3)被transient關鍵字修飾的變量不再能被序列化,一個靜態變量不管是否被transient修飾,均不能被序列化。
第三點可能有些人很迷惑,因為發現在User類中的username字段前加上static關鍵字后,程序運行結果依然不變,即static類型的username也讀出來為“Alexia”了,這不與第三點說的矛盾嗎?
實際上是這樣的:第三點確實沒錯(一個靜態變量不管是否被transient修飾,均不能被序列化),反序列化后類中static型變量username的值為當前JVM中對應static變量的值,這個值是JVM中的不是反序列化得出的

https://www.cnblogs.com/lanxuezaipiao/p/3369962.html

 

//第三種:使用fastjson的攔截器
PropertyFilter profilter = new PropertyFilter(){  
  
            @Override  
            public boolean apply(Object object, String name, Object value) {  
                if(name.equalsIgnoreCase("last")){  
                    //false表示last字段將被排除在外  
                    return false;  
                }  
                return true;  
            }  
              
        };  
        json = JSON.toJSONString(user, profilter);  
        System.out.println(json);   

https://blog.csdn.net/stubbornness1219/article/details/52947013

 

 

jackson也是一個很優秀的jackson庫,但是如果你因為某些理由想遷移到fastjson,這個指南將會為你介紹如何從jackson遷移到fastjson。

Annotions

在fastjson中,有四個Annotation,JSONType、JSONField、JSONCreator、JSONPOJOBuilder,能夠完成jackson大多數Annotation對應的功能。

1. JsonView遷移

在fastjson中,提供有一個LabelFilter,能夠實現Jackson JsonView的功能,用於定制序列化。詳細文檔 https://github.com/alibaba/fastjson/wiki/LabelFilter

2. JsonPOJOBuilder

在Jackson中提供了對Builder模式支持的JsonPOJOBuilder,在fastjson中對應的是JSONPOJOBuilder。詳細文檔 https://github.com/alibaba/fastjson/wiki/BuilderSupport

3. JsonAnyGetter & JsonAnySetter & JsonUnwrapped

在fastjson 1.2.32版本中引入JSONField.unwrapped配置,支持類似JsonAnyGetter/JsonAnySetter的功能,詳細文檔 https://github.com/alibaba/fastjson/wiki/JSONField_unwrapped_cn

4. JsonPropertyOrder

在fastjson的JSONType.orders提供了同樣的功能。例如:

@JSONType(orders={"name", "id"}) public static class VO { public int id; public String name; }

5. JsonRawValue

在fastjson中,通過JSONField.jsonDirect配置能實現同樣的功能。

public static class Model { public int id; @JSONField(jsonDirect=true) public String value; }

6. JsonSerialize

在fastjson中,可以通過使用JSONField.serializeUsing和JSONType.serializer實現同樣的功能。

7. JsonCreator

在fastjson中有對應的JSONCreator

8. JsonSetter

在fastjson中,可以用JSONField實現同樣的功能。

9. JsonDeserialize

在fastjson中,可以通過使用JSONField.deserializeUsing和JSONType.deserializer實現同樣的功能。

10. JsonIgnoreProperties

在fastjson中,可以通過使用JSONType.ignores實現同樣的功能

11. JsonIgnore

在fastjson中,可以通過使用JSONField.serilaize=false和JSONField.deserilaize=false和實現同樣的功能

12. JsonFormat

在fastjson中,可以通過使用JSONField.format實現同樣的功能

13. Jackson Polymorphic Type Handling Annotations

在fastjson中,可以通過JSONType.seeAlso實現類似的功能。詳細文檔 https://github.com/alibaba/fastjson/wiki/JSONType_seeAlso_cn

https://github.com/alibaba/fastjson/wiki/guid_to_migrating_from_jackson_to_fastjson_cn

 

2.4. @JsonRawValue

@JsonRawValue is used to instruct the Jackson to serialize a property exactly as is.

In the following example – we use @JsonRawValue to embed some custom JSON as a value of an entity:

1
2
3
4
5
6
public class RawBean {
     public String name;
 
     @JsonRawValue
     public String json;
}

The output of serializing the entity is:

1
2
3
4
5
6
{
     "name" : "My bean" ,
     "json" :{
         "attr" : false
     }
}

And a simple test:

1
2
3
4
5
6
7
8
9
10
@Test
public void whenSerializingUsingJsonRawValue_thenCorrect()
   throws JsonProcessingException {
  
     RawBean bean = new RawBean( "My bean" , "{" attr ":false}" );
 
     String result = new ObjectMapper().writeValueAsString(bean);
     assertThat(result, containsString( "My bean" ));
     assertThat(result, containsString( "{" attr ":false}" ));
}

http://www.baeldung.com/jackson-annotations

 

9.4 日期格式處理

Fastjson能識別下面這么多種日期格式的字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private final static String defaultPatttern = "yyyy-MM-dd HH:mm:ss";
private final static DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern(defaultPatttern);
private final static DateTimeFormatter formatter_dt19_tw = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
private final static DateTimeFormatter formatter_dt19_cn = DateTimeFormatter.ofPattern("yyyy年M月d日 HH:mm:ss");
private final static DateTimeFormatter formatter_dt19_cn_1 = DateTimeFormatter.ofPattern("yyyy年M月d日 H時m分s秒");
private final static DateTimeFormatter formatter_dt19_kr = DateTimeFormatter.ofPattern("yyyy년M월d일 HH:mm:ss");
private final static DateTimeFormatter formatter_dt19_us = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
private final static DateTimeFormatter formatter_dt19_eur = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
private final static DateTimeFormatter formatter_dt19_de = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
private final static DateTimeFormatter formatter_dt19_in = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");

private final static DateTimeFormatter formatter_d8 = DateTimeFormatter.ofPattern("yyyyMMdd");
private final static DateTimeFormatter formatter_d10_tw = DateTimeFormatter.ofPattern("yyyy/MM/dd");
private final static DateTimeFormatter formatter_d10_cn = DateTimeFormatter.ofPattern("yyyy年M月d日");
private final static DateTimeFormatter formatter_d10_kr = DateTimeFormatter.ofPattern("yyyy년M월d일");
private final static DateTimeFormatter formatter_d10_us = DateTimeFormatter.ofPattern("MM/dd/yyyy");
private final static DateTimeFormatter formatter_d10_eur = DateTimeFormatter.ofPattern("dd/MM/yyyy");
private final static DateTimeFormatter formatter_d10_de = DateTimeFormatter.ofPattern("dd.MM.yyyy");
private final static DateTimeFormatter formatter_d10_in = DateTimeFormatter.ofPattern("dd-MM-yyyy");

private final static DateTimeFormatter ISO_FIXED_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());

private final static String formatter_iso8601_pattern = "yyyy-MM-dd'T'HH:mm:ss";
private final static DateTimeFormatter formatter_iso8601 = DateTimeFormatter.ofPattern(formatter_iso8601_pattern);

默認序列化Date輸出使用”yyyy-MM-dd HH:mm:ss”格式,可以用UseISO8601DateFormat特性換成”yyyy-MM-dd’T’HH:mm:ss”格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
JSON.defaultTimeZone = TimeZone.getTimeZone("Asia/Shanghai");
JSON.defaultLocale = Locale.US;

public static class Model {
@JSONField(format = "MMM dd, yyyy h:mm:ss aa")
private java.util.Date date;

public java.util.Date getDate() {
return date;
}

public void setDate(java.util.Date date) {
this.date = date;
}

@JSONField(format = "MMM-dd-yyyy h:mm:ss aa")
public java.sql.Date date2;
}

9.5 常見序列化特性的使用

Fastjson的序列化特性定義在枚舉類com\alibaba\fastjson\serializer\SerializerFeature.java中,目前正好有30項。
可以通過設置多個特性到FastjsonConfig中全局使用,也可以在某個具體的JSON.writeJSONString時作為參數使用。

  1. QuoteFieldNames, //key使用引號
  2. UseSingleQuotes, //使用單引號
  3. WriteMapNullValue, //輸出Map的null值
  4. WriteEnumUsingToString, //枚舉屬性輸出toString的結果
  5. WriteEnumUsingName, //枚舉數據輸出name
  6. UseISO8601DateFormat, //使用日期格式
  7. WriteNullListAsEmpty, //List為空則輸出[]
  8. WriteNullStringAsEmpty, //String為空則輸出””
  9. WriteNullNumberAsZero, //Number類型為空則輸出0
  10. WriteNullBooleanAsFalse, //Boolean類型為空則輸出false
  11. SkipTransientField,
  12. SortField, //排序字段
  13. WriteTabAsSpecial,
  14. PrettyFormat, // 格式化JSON縮進
  15. WriteClassName, // 輸出類名
  16. DisableCircularReferenceDetect, // 禁止循環引用
  17. WriteSlashAsSpecial, // 對斜杠’/’進行轉義
  18. BrowserCompatible,
  19. WriteDateUseDateFormat, // 全局修改日期格式,默認為false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
  20. NotWriteRootClassName,
  21. DisableCheckSpecialChar,
  22. BeanToArray,
  23. WriteNonStringKeyAsString,
  24. NotWriteDefaultValue,
  25. BrowserSecure,
  26. IgnoreNonFieldGetter,
  27. WriteNonStringValueAsString,
  28. IgnoreErrorGetter,
  29. WriteBigDecimalAsPlain,
  30. MapSortField

使用示例如下(可以參見此處):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Word word = new Word();
word.setA("a");
word.setB(2);
word.setC(true);
word.setD("d");
word.setE("");
word.setF(null);
word.setDate(new Date());

System.out.println(JSON.toJSONString(word));
System.out.println(JSON.toJSONString(word, SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteNullListAsEmpty));

9.6 Annotation注解的使用

1) JSONField

可以配置在屬性(setter、getter)和字段(必須是public field)上。
詳情參見此處:JSONField用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.alibaba.fastjson.annotation;

public @interface JSONField {
// 配置序列化和反序列化的順序,1.1.42版本之后才支持
int ordinal() default 0;

// 指定字段的名稱
String name() default "";

// 指定字段的格式,對日期格式有用
String format() default "";

// 是否序列化
boolean serialize() default true;

// 是否反序列化
boolean deserialize() default true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@JSONField(name="ID")
public int getId() {return id;}

// 配置date序列化和反序列使用yyyyMMdd日期格式
@JSONField(format="yyyyMMdd")
public Date date1;

// 不序列化
@JSONField(serialize=false)
public Date date2;

// 不反序列化
@JSONField(deserialize=false)
public Date date3;

// 按ordinal排序
@JSONField(ordinal = 2)
private int f1;

@JSONField(ordinal = 1)
private int f2;

 

http://kimmking.github.io/2017/06/06/json-best-practice/

7. fastjson序列化的需要像json-lib一樣配置java bean的序列化么?

不需要,fastjson的序列化和反序列化都不需要做特別配置,唯一的要求是,你序列化的類符合java bean規范。

8. fastjson如何處理日期

fastjson處理日期的API很簡單,例如:

JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS")

使用ISO-8601日期格式

JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);

全局修改日期格式

JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);

反序列化能夠自動識別如下日期格式:

  • ISO-8601日期格式
  • yyyy-MM-dd
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss.SSS
  • 毫秒數字
  • 毫秒數字字符串
  • .NET JSON日期格式
  • new Date(198293238)

 

11. IE 6不支持JSON帶中文字符串,要怎么處理?

 

fastjson提供了BrowserCompatible這個配置,打開之后,所有的中文都會序列化為\uXXXX這種格式,字節數會多一些,但是能兼容IE 6。

 

String  jsonString = JSON.toJSONString(obj, SerializerFeature.BrowserCompatible);

 

10. 當對象存在引用時,序列化后的結果瀏覽器不支持,怎么辦?

 

使用SerializerFeature.DisableCircularReferenceDetect特性關閉引用檢測和生成。
例如:

 

String  jsonString = JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);

https://github.com/alibaba/fastjson/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98

 

 

做個分析 FastJson 在使用 toJSONString 會使用 寫入操作,而 我的類里面有這樣一個方法 public int getLengthOfByte()
這樣FastJson 就會認為 這個類 有一個 lengthOfByte 的屬性,於是就出現了異常,解決方法

@JSONType(ignores = "lengthOfByte")
public class DRMessageBody {

  public int getLengthOfByte(){
        String json = toJson();
        int num = -1;
        num = json.getBytes().length;
        if(num==-1){
            new RuntimeException("Messagebody of json length is error!");
        }
        return num;
    }
}

https://www.jianshu.com/p/f96e257c7682

 


免責聲明!

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



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