【FastJson】学习笔记

FastJson 介绍

是什么

fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean

使用场景

Fastjson已经被广泛使用在各种场景,包括cache存储、RPC通讯、MQ通讯、网络协议通讯、Android客户端、Ajax服务器处理程序等等

优点

速度快、功能强、简单

使用

引入FastJson依赖后,参考API就可以使用了


<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>版本号</version>
</dependency>

序列化和反序列化

序列化:bean 转成 json
反序列化:json 转成 bean

将 Java 对象转换为 JSON 格式

定义一个java bean


// java bean
public class Person {
    // @JSONField的作用是在对象转换成json时,使用@JSONField中的name的值作为json的字段名
    @JSONField(name = "AGE")
    private int age;
 
    @JSONField(name = "FULL NAME")
    private String fullName;
 
    @JSONField(name = "DATE OF BIRTH")
    private Date dateOfBirth;
 
    public Person(int age, String fullName, Date dateOfBirth) {
        super();
        this.age = age;
        this.fullName= fullName;
        this.dateOfBirth = dateOfBirth;
    }
 
    // 标准 getters & setters
}

可以使用 JSON.toJSONString() 将 Java 对象转换换为 JSON 对象


private List<Person> listOfPersons = new ArrayList<Person>();
 
@Before
public void setUp() {
    listOfPersons.add(new Person(15, "John Doe", new Date()));
    listOfPersons.add(new Person(20, "Janette Doe", new Date()));
}
 
@Test
public void whenJavaList_thanConvertToJsonCorrect() {
    String jsonOutput= JSON.toJSONString(listOfPersons);
}

输出结果为


// 注意这里的“AGE”使用的是java bean 的属性上的@JSONField注解的值
// 如果不适用这个注解,会默认使用属性名“age”
[  
    {  
        "AGE":15,
        "DATE OF BIRTH":1468962431394,
        "FULL NAME":"John Doe"
    },
    {  
        "AGE":20,
        "DATE OF BIRTH":1468962431394,
        "FULL NAME":"Janette Doe"
    }
]

@JSONField 注解的功能


// name="AGE" 设置字段转换后的json字段的名字
// serialize=false 设置字段不参与json转换
@JSONField(name="AGE", serialize=false)
private int age;
 
// ordinal = 2 定义字段转换成json,在json中的顺序
@JSONField(name="LAST NAME", ordinal = 2)
private String lastName;

@JSONField(name="FIRST NAME", ordinal = 1)
private String firstName; 

// format="dd/MM/yyyy" 定义字段值转换成json后的显示格式
@JSONField(name="DATE OF BIRTH", format="dd/MM/yyyy", ordinal = 3)
private Date dateOfBirth;

将java bean转换成json后输出


// 根据ordinal排序
// 设置是否参与序列化
[
    {
        "FIRST NAME":"Doe",
        "LAST NAME":"Jhon",
        "DATE OF BIRTH":"19/07/2016"
    },
    {
        "FIRST NAME":"Doe",
        "LAST NAME":"Janette",
        "DATE OF BIRTH":"19/07/2016"
    }
]

@JSONField 的作用对象:

  • Field
  • Setter 和 Getter 方法

注意:FastJson 在进行操作时,是根据 getter 和 setter 的方法进行的,并不是依据 Field 进行。
注意:若属性是私有的,必须有 set 方法。否则无法反序列化。

FastJson 还支持 BeanToArray 序列化功能

可以把 JSONArray 看成 JSONObject 对象的一个集合


@Test
public void whenGenerateJson_thanGenerationCorrect() throws ParseException {
    JSONArray jsonArray = new JSONArray();
    for (int i = 0; i < 2; i++) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("AGE", 10);
        jsonObject.put("FULL NAME", "Doe " + i);
        jsonObject.put("DATE OF BIRTH", "2016/12/12 12:12:12");
        jsonArray.add(jsonObject);
    }
    // 上述代码向jsonArray中添加了两个jsonObject
    String jsonOutput = jsonArray.toJSONString();
}

输出:
[
   {
      "AGE":"10",
      "DATE OF BIRTH":"2016/12/12 12:12:12",
      "FULL NAME":"Doe 0"
   },
   {
      "AGE":"10",
      "DATE OF BIRTH":"2016/12/12 12:12:12",
      "FULL NAME":"Doe 1"
   }
]

JSON 字符串转换为 Java 对象

解析json,将json字符串转换成对象
注意将json反序列化为对象时,必须要有默认无参的构造函数,否则会报异常


@Test
public void whenJson_thanConvertToObjectCorrect() {
    Person person = new Person(20, "John", "Doe", new Date());
    String jsonObject = JSON.toJSONString(person);
    Person newPerson = JSON.parseObject(jsonObject, Person.class);
     
    // 如果我们设置序列化为 false,则age字段不参与序列化,不会被赋值,所以断言会成功 
    assertEquals(newPerson.getAge(), 0);
    assertEquals(newPerson.getFullName(), listOfPersons.get(0).getFullName());
}

输出:
Person [age=20, fullName=John Doe, dateOfBirth=Wed Jul 20 08:51:12 WEST 2022]

--------------------------------------------

// deserialize=false  设置该字段不参与反序列化
@JSONField(name = "DATE OF BIRTH", deserialize=false)
private Date dateOfBirth;

// 设置了不参与反序列化后,输出的结果
Person [age=20, fullName=John Doe, dateOfBirth=null]

使用 ContextValueFilter 配置 JSON 转换

在某些场景下,对Value做过滤,需要获得所属JavaBean的信息,包括类型、字段、方法等


@Test
public void givenContextFilter_whenJavaObject_thanJsonCorrect() {
    ContextValueFilter valueFilter = new ContextValueFilter () {
        public Object process(
          BeanContext context, Object object, String name, Object value) {
            // 如果名字的值是DATE OF BIRTH,则返回NOT TO DISCLOSE值
            if (name.equals("DATE OF BIRTH")) {
                return "NOT TO DISCLOSE";
            }
            // 如果值包含 John 的字段,转换成大写返回
            if (value.equals("John")) {
                return ((String) value).toUpperCase();
            } else {
                return null;
            }
        }
    };
    String jsonOutput = JSON.toJSONString(listOfPersons, valueFilter);
}

使用 NameFilter 和 SerializeConfig

NameFilter: 序列化时修改 Key。
SerializeConfig:内部是个map容器主要功能是配置并记录每种Java类型对应的序列化类


@Test
public void givenSerializeConfig_whenJavaObject_thanJsonCorrect() {
    // 创建formatName 过滤器使用 NameFilter 匿名类,来处理字段名称
    NameFilter formatName = new NameFilter() {
        public String process(Object object, String name, Object value) {
            return name.toLowerCase().replace(" ", "_");
        }
    };
     
    // 新创建的过滤器与 Person 类相关联,然后添加到全局实例,它是 SerializeConfig 类中的静态属性
    SerializeConfig.getGlobalInstance().addFilter(Person.class,  formatName);
    String jsonOutput = JSON.toJSONStringWithDateFormat(listOfPersons, "yyyy-MM-dd");
}

Fastjson 定制序列化

fastjson支持多种方式定制序列化。

  • 通过@JSONField定制序列化
  • 通过@JSONType定制序列化
  • 通过SerializeFilter定制序列化
  • 通过ParseProcess定制反序列化

通过@JSONField定制序列化

上述记录过

通过@JSONType定制序列化

和JSONField类似,但JSONType配置在类上,而不是field或者getter/setter方法上

通过SerializeFilter定制序列化

通过SerializeFilter可以使用扩展编程的方式实现定制序列化。fastjson提供了多种SerializeFilter:

  • PropertyPreFilter 根据PropertyName判断是否序列化
  • PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
  • NameFilter 修改Key,如果需要修改Key,process返回值则可
  • ValueFilter 修改Value
  • BeforeFilter 序列化时在最前添加内容
  • AfterFilter 序列化时在最后添加内容

和servlet中的过滤器时一个道理,在json和对象转换的过程中,添加各种过滤器

通过ParseProcess定制反序列化

ParseProcess是编程扩展定制反序列化的接口

  • ExtraProcessor 用于处理多余的字段
  • ExtraTypeProvider 用于处理多余字段时提供类型信息

使用ExtraProcessor 处理多余字段


// java bean
public static class VO {
    private int id;
    private Map<String, Object> attributes = new HashMap<String, Object>();
    
    public int getId() { return id; }
    public void setId(int id) { this.id = id;}
    public Map<String, Object> getAttributes() { return attributes;}
}

// 使用ExtraProcessor 处理多余字段,此处多余字段是name
ExtraProcessor processor = new ExtraProcessor() {
    public void processExtra(Object object, String key, Object value) {
        VO vo = (VO) object;
        vo.getAttributes().put(key, value);
    }
};

VO vo = JSON.parseObject("{\"id\":123,\"name\":\"abc\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals("abc", vo.getAttributes().get("name"));

使用ExtraTypeProvider 为多余的字段提供类型


public static class VO {
    private int id;
    private Map<String, Object> attributes = new HashMap<String, Object>();
    public int getId() { return id; }
    public void setId(int id) { this.id = id;}
    public Map<String, Object> getAttributes() { return attributes;}
}

class MyExtraProcessor implements ExtraProcessor, ExtraTypeProvider {
    public void processExtra(Object object, String key, Object value) {
        VO vo = (VO) object;
        vo.getAttributes().put(key, value);
    }

	// 如果参数key的值是value,就将值的类型转成int
    public Type getExtraType(Object object, String key) {
        if ("value".equals(key)) {
            return int.class;
        }
        return null;
    }
};

ExtraProcessor processor = new MyExtraProcessor();

VO vo = JSON.parseObject("{\"id\":123,\"value\":\"123456\"}", VO.class, processor);
Assert.assertEquals(123, vo.getId());
Assert.assertEquals(123456, vo.getAttributes().get("value")); // value本应该是字符串类型的,通过getExtraType的处理变成Integer类型了。

FastJson 在Spring中使用fastJSON

FastJson 提供了Spring MVC HttpMessageConverter的实现

可在Spring Controller中使用FastJson进行数据的序列化和反序列化FastJsonConfig配置


<bean id="fastJsonConfig" class="com.alibaba.fastjson.support.config.FastJsonConfig">
    <!-- Default charset -->
    <property name="charset" value="UTF-8" />
    <!-- Default dateFormat -->
    <property name="dateFormat" value="yyyy-MM-dd HH:mm:ss" />
    <!-- Feature -->
    <property name="features">
        <list>
            <value>Your feature</value>
        </list>
    </property>
    <!-- SerializerFeature -->
    <property name="serializerFeatures">
        <list>
            <value>Your serializer feature</value>
        </list>
    </property>
    <!-- Global SerializeFilter -->
    <property name="serializeFilters">
        <list>
            <ref bean="Your serializer filter"/>    
        </list>
    </property>
    <!-- Class Level SerializeFilter -->
    <property name="classSerializeFilters">
        <map>
            <entry key="Your filter class" value-ref="Your serializer filter"/>
        </map>
    </property>
</bean>

HttpMessageConverter配置


<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
            <!-- MediaTypes -->
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json</value>
                </list>
            </property>
            <!-- FastJsonConfig -->
            <property name="fastJsonConfig" ref="fastJsonConfig" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

<mvc:default-servlet-handler />

Fastjson 处理超大JSON文本

Fastjson当需要处理超大JSON文本时,需要Stream API

序列化

超大JSON数组序列化

如果你的JSON格式是一个巨大的JSON数组,有很多元素,则先调用startArray,然后挨个写入对象,然后调用endArray


// 创建JSONWriter对象,并设置要写入文件的位置
JSONWriter writer = new JSONWriter(new FileWriter("/tmp/huge.json"));
// 表明我要写的是一个数组
writer.startArray();
for (int i = 0; i < 1000 * 1000; ++i) {
    writer.writeValue(new VO());
}
writer.endArray();
writer.close();

超大JSON对象序列化

如果你的JSON格式是一个巨大的JSONObject,有很多Key/Value对,则先调用startObject,然后挨个写入Key和Value,然后调用endObject


JSONWriter writer = new JSONWriter(new FileWriter("/tmp/huge.json"));
writer.startObject();// 表明要写入是对象
for (int i = 0; i < 1000 * 1000; ++i) {
      writer.writeKey("x" + i);
      writer.writeValue(new VO());
}
writer.endObject();
writer.close();

反序列化

超大JSON数组序列化


JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startArray();
while(reader.hasNext()) {
      VO vo = reader.readObject(VO.class);
      // handle vo ...
}
reader.endArray();
reader.close();

超大JSON对象序列化


JSONReader reader = new JSONReader(new FileReader("/tmp/huge.json"));
reader.startObject();
while(reader.hasNext()) {
      String key = reader.readString();
      VO vo = reader.readObject(VO.class);
      // handle vo ...
}
reader.endObject();
reader.close();

常用API

序列化API


public abstract class JSON {
    // 将Java对象序列化为JSON字符串,支持各种各种Java基本类型和JavaBean
    public static String toJSONString(Object object, SerializerFeature... features);

    // 将Java对象序列化为JSON字符串,返回JSON字符串的utf-8 bytes
    public static byte[] toJSONBytes(Object object, SerializerFeature... features);

    // 将Java对象序列化为JSON字符串,写入到Writer中
    public static void writeJSONString(Writer writer, 
                                       Object object, 
                                       SerializerFeature... features);

    // 将Java对象序列化为JSON字符串,按UTF-8编码写入到OutputStream中
    public static final int writeJSONString(OutputStream os,
                                            Object object,
                                            SerializerFeature... features);
}

反序列化API


public abstract class JSON {
    // 将JSON字符串反序列化为JavaBean
    public static <T> T parseObject(String jsonStr, 
                                    Class<T> clazz, 
                                    Feature... features);

    // 将JSON字符串反序列化为JavaBean
    public static <T> T parseObject(byte[] jsonBytes,  // UTF-8格式的JSON字符串
                                    Class<T> clazz, 
                                    Feature... features);

    // 将JSON字符串反序列化为泛型类型的JavaBean
    public static <T> T parseObject(String text, 
                                    TypeReference<T> type, 
                                    Feature... features);

    // 将JSON字符串反序列为JSONObject
    public static JSONObject parseObject(String text);
}

// 解析树
JSONObject jsonObj = JSON.parseObject(jsonStr);
// 解析POJO
Model model = JSON.parseObject(jsonStr, Model.class);
// 解析POJO泛型
Type type = new TypeReference<List<Model>>() {}.getType(); 
List<Model> list = JSON.parseObject(jsonStr, type);
// 将POJO转换为json字符串
Model model = new Model();
String jsonStr = JSON.toJSONString(model);
// 将POJO作为json字符串写入OutputStream

使用示例


// 解析树
JSONObject jsonObj = JSON.parseObject(jsonStr);
// 解析POJO
Model model = JSON.parseObject(jsonStr, Model.class);
// 解析POJO泛型
Type type = new TypeReference<List<Model>>() {}.getType(); 
List<Model> list = JSON.parseObject(jsonStr, type);
// 将POJO转换为json字符串
Model model = new Model();
String jsonStr = JSON.toJSONString(model);
// 将POJO作为json字符串写入OutputStream
Model model = ...; 
OutputStream os = JSON.writeJSONString(os, model);
// 将POJO作为json字符串写入Writer
Model model = ...; 
Writer writer = ...;
JSON.writeJSONString(writer, model);

Fastjson JSONField


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支持新的定制化配置serializeUsing,可以单独对某一个类的某个属性定制序列化


public static class Model {
    @JSONField(serializeUsing = ModelValueSerializer.class)
    public int value;
}

public static class ModelValueSerializer implements ObjectSerializer {
    @Override
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
                      int features) throws IOException {
        // 对model.value末尾拼接上“元”,设置为字符串类型,序列化时写出
        Integer value = (Integer) object;
        String text = value + "元";
        serializer.write(text);
    }
}

JSONField alternateNames支持反序列化时使用多个不同的字段名称,使用的方式是配置JSONField的alternateNames


public static class Model {
    public int id;

	// 反序列化时,字段值是"user"或者"person"时,都会被映射给name
    @JSONField(alternateNames = {"user", "person"})
    public String name;
}

String jsonVal0 = "{\"id\":5001,\"name\":\"Jobs\"}";
String jsonVal1 = "{\"id\":5382,\"user\":\"Mary\"}";
String jsonVal2 = "{\"id\":2341,\"person\":\"Bob\"}";

Model obj0 = JSON.parseObject(jsonVal0, Model.class);
assertEquals(5001, obj0.id);
assertEquals("Jobs", obj0.name);

Model obj1 = JSON.parseObject(jsonVal1, Model.class);
assertEquals(5382, obj1.id);
assertEquals("Mary", obj1.name);

Model obj2 = JSON.parseObject(jsonVal2, Model.class);
assertEquals(2341, obj2.id);
assertEquals("Bob", obj2.name);

JSONField支持一个新的配置项jsonDirect,它的用途是:当你有一个字段是字符串类型,里面是json格式数据,你希望直接输入,而不是经过转义之后再输出


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

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

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

Fastjson JSONPath

这是一个很强大的功能,可以在java框架中当作对象查询语言(OQL)来使用


public class JSONPath {          
     //  求值,静态方法
     public static Object eval(Object rootObject, String path);

     // 计算Size,Map非空元素个数,对象非空元素个数,Collection的Size,数组的长度。其他无法求值返回-1
     public static int size(Object rootObject, String path);

     // 是否包含,path中是否存在对象
     public static boolean contains(Object rootObject, String path) { }

     // 是否包含,path中是否存在指定值,如果是集合或者数组,在集合中查找value是否存在
     public static boolean containsValue(Object rootObject, String path, Object value) { }

     // 修改制定路径的值,如果修改成功,返回true,否则返回false
     public static boolean set(Object rootObject, String path, Object value) {}

     // 在数组或者集合中添加元素
     public static boolean array_add(Object rootObject, String path, Object... values);
}

List<Person> entities = new ArrayList<Person>();
entities.add(new Person("ljw2083",1));
entities.add(new Person("wenshao",2));
entities.add(new Person("yakolee",3));
entities.add(new Person(null,4));

// 返回age是2和3的
List<Object> result = (List<Object>) JSONPath.eval(entities, "[age in (2,3)]");
System.out.println(result);

// 返回enties的所有名称
List<String> names = (List<String>)JSONPath.eval(entities, "$.name"); 

// 返回下标为1和2的元素
List<Entity> result = (List<Entity>)JSONPath.eval(entities, "[1,2]"); 

// 返回下标从0到2的元素
List<Entity> result = (List<Entity>)JSONPath.eval(entities, "[0:2]");

//将id字段修改为123456
JSONPath.set(entity, "id", 123456);

//将value字段赋值为长度为0的数组
JSONPath.set(entity, "value", new int[0]); 

//将value字段的数组添加元素1,2,3
JSONPath.arrayAdd(entity, "value", 1, 2, 3); 


输出:
[{"age":2},{"age":3}]

Fastjson toJSONString

Fastjson 将java对象序列化为JSON字符串,fastjson提供了一个最简单的入口


Model model = new Model();
model.id = 1001;

String json = JSON.toJSONString(model);

Fastjson writeJSONString

JSON类新增对OutputStream/Writer直接支持


class Model {
    public int value;
}

Model model = new Model();
model.value = 1001;

OutputStream os = ...;
JSON.writeJSONString(os, model);
JSON.writeJSONString(os, Charset.from("GB18030"), model);

Writer writer = ...;
JSON.writeJSONString(os, model);

Fastjson parseObject

fastjson新增加了对InputStream的支持


class Model {
    public int value;
}

InputStream is = ...
Model model = JSON.parseObject(is, Model.class);
Model model2 = JSON.parseObject(is, Charset.from("UTF-8"), Model.class);

Fastjson BeanToArray

在fastjson中,支持一种叫做BeanToArray的映射模式。普通模式下,JavaBean映射成json object,BeanToArray模式映射为json array


Model model = new Model();
model.id = 1001;
model.name = "gaotie";

// 输出 {"id":1001,"name":"gaotie"}
String text_normal = JSON.toJSONString(model); 

// 输出 [1001,"gaotie"]
String text_beanToArray = JSON.toJSONString(model, SerializerFeature.BeanToArray); 

Fastjson 对象或数组转JSON


// 用户组对象转JSON串  
String jsonString = JSON.toJSONString(group);  

// JSON串转用户组对象  
UserGroup group2 = JSON.parseObject(jsonString, UserGroup.class);  

// 用户对象数组转JSON串  
String jsonString2 = JSON.toJSONString(users);  

// JSON串转用户对象列表  
List<User> users2 = JSON.parseArray(jsonString2, User.class);  

Fastjson Obejct/Map/JSON/String 互转


// 数组转json字符串
String json_arr_String = JSON.toJSONString(arr,true);

// json字符串转数组
JSONArray jsonArray = JSON.parseArray(json_arr_String); 

// map转json
String json=JSON.toJSONString(map);

// json转map
Map map1 = JSON.parseObject(json);

// bean转json
String jsonString = JSON.toJSONString(person);  

// json转bean
Person person =JSON.parseObject(jsonString,Person.class);

// json转集合
List<Person> persons2 = JSON.parseArray(jsonString,Person.class);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值