首页 > 其他分享 >Fastjson 专题

Fastjson 专题

时间:2023-01-02 15:31:54浏览次数:53  
标签:Fastjson fastjson 专题 name JSON com public String

​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 对象,则会出现这种情况​
Fastjson  专题_fastjosn

Fastjson  专题_java_02



代码:

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

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中的不是反序列化得出的

 

//第三种:使用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);


 

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:

​​public​​​ ​​class​​​ ​​RawBean {​​
​​public​​​ ​​String name;​​

​​@JsonRawValue​​
​​public​​​ ​​String json;​​
​​}​​

The output of serializing the entity is:

​​{​​
​​"name"​​​​:​​​​"My bean"​​​​,​​
​​"json"​​​​:{​​
​​"attr"​​​​:​​​​false​​
​​}​​
​​}​​

And a simple test:

​​@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能识别下面这么多种日期格式的字符串:

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”格式。

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;
}

 

Fastjson的序列化特性定义在枚举类com\alibaba\fastjson\serializer\SerializerFeature.java中,目前正好有30项。9.5 常见序列化特性的使用

可以通过设置多个特性到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

使用示例如下(可以​​参见此处​​):

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用法​

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;
}

 

 

@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​

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
* spring-boot-cookbook
*
* @author: tangcheng
* @date: 2021/6/9 19:34 下午
* @see
* @since
*/
@Slf4j
public class ModelToMapUtil {

public static <T> Map<String, Object> transfer2Map(T model) {
String jsonStr = JSON.toJSONString(model, SerializerFeature.DisableCircularReferenceDetect);
JSONObject jsonObject = JSON.parseObject(jsonStr);
return transferJSONObject2Map(jsonObject);
}


private static Map<String, Object> transferJSONObject2Map(JSONObject jsonObject) {
Set<Map.Entry<String, Object>> entrySet = jsonObject.entrySet();
Map<String, Object> result = new HashMap<>(entrySet.size());
for (Map.Entry<String, Object> entry : entrySet) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof JSONArray) {
List<Object> objects = transferJSONArray2Map((JSONArray) value);
result.put(key, objects);
} else if (value instanceof JSONObject) {
Map<String, Object> jsonObject2Map = transferJSONObject2Map((JSONObject) value);
result.put(key, jsonObject2Map);
} else {
result.put(key, value);
}
}
return result;
}


private static List<Object> transferJSONArray2Map(JSONArray jsonArray) {
List<Object> arrayList = new ArrayList<>(jsonArray.size());
for (Object obj : jsonArray) {
if (obj instanceof JSONObject) {
Map<String, Object> jsonObject2Map = transferJSONObject2Map((JSONObject) obj);
arrayList.add(jsonObject2Map);
} else if (obj instanceof JSONArray) {
List<Object> objects = transferJSONArray2Map((JSONArray) obj);
arrayList.add(objects);
} else {
arrayList.add(obj);
}
}
return arrayList;
}


}

 




标签:Fastjson,fastjson,专题,name,JSON,com,public,String
From: https://blog.51cto.com/u_15147537/5983751

相关文章

  • 【深入浅出Sentinel原理及实战】「基础实战专题」零基础实现服务流量控制实战开发指南
    你若要喜爱你自己的价值,你就得给世界创造价值。Sentinel的组成部分Sentinel主要由以下两个部分组成。Sentinel核心库(Java客户端):Sentinel的核心库不依赖任何框架或......
  • BootStrap 专题
     验证码的输入框和验证码图片在一行,用bootstrap原生的怎么写呢?看了教程,没有完全一样的可以让右侧的按钮“输入验证码”固定大小。左侧的输入框动态大小吗?​​​​ <divc......
  • HttpClient 专题
    HttpClientisaHTTP/1.1compliantHTTPagentimplementationbasedonHttpCore.Italsoprovidesreusablecomponentsforclient-sideauthentication,HTTPstate......
  • 毕设系列-检测专题-基于YOLOV5的火灾检测系统
    我们之前做过一期基于Yolov5的口罩检测系统(​​手把手教你使用YOLOV5训练自己的目标检测模型-口罩检测-视频教程_dejahu的博客-博客​​),里面的代码是基于YOLOV56.0开发的,并......
  • 毕设系列-检测专题-基于卷积神经网络的动物识别系统
    我们之前做过一期基于Yolov5的口罩检测系统(​​手把手教你使用YOLOV5训练自己的目标检测模型-口罩检测-视频教程_dejahu的博客-博客​​),里面的代码是基于YOLOV56.0开发的,并......
  • 计算机视觉与图形学-神经渲染专题-非刚体NeRF
    《FastNon-RigidRadianceFieldsfromMonocularizedData》链接:https://graphics.tu-bs.de/publications/kappel2022fast摘要单目动态场景下的3D重建和新颖视图合成最......
  • #yyds干货盘点# 名企真题专题:进制转换
    1.简述:描述给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数输入描述:输入为一行,M(32位整数)、N(2≤N≤16),以空格隔开。输出描述:为每个测试实例输出转......
  • #yyds干货盘点# 名企真题专题: 回文串
    1.简述:描述给定一个字符串,问是否能通过添加一个字母将其变为回文串。输入描述:一行一个由小写字母构成的字符串,字符串长度小于等于10。输出描述:输出答案(YES\NO).示例1输入:co......
  • #yyds干货盘点# 名企真题专题:删除重复字符
    1.简述:描述牛牛有一个由小写字母组成的字符串s,在s中可能有一些字母重复出现。比如在"banana"中,字母'a'和字母'n'分别出现了三次和两次。但是牛牛不喜欢重复。对于同一个字......
  • #yyds干货盘点# 名企真题专题:顺时针打印数字矩阵
    1.简述:描述给定一个数字矩阵,请设计一个算法从左上角开始顺时针打印矩阵元素输入描述:输入第一行是两个数字,分别代表行数M和列数N;接下来是M行,每行N个数字,表示这个矩阵的所有元......