Fastjson là một thư viện JSON hiệu suất cao được phát triển bởi Alibaba, dùng rộng rãi trong các ứng dụng Java để tạo JSON từ đối tượng Java (serialization) và chuyển JSON thành đối tượng Java (deserialization). Mặc dù trong thời gian gần đây do các lỗ hổng bảo mật, thư viện này đã bị thay thế bằng Jackson trong một số trường hợp, nhưng API đơn giản và hiệu suất cao vẫn khiến nó được sử dụng trong nhiều dự án.
I. Nguyên lý cốt lõi của Fastjson
1.1 Cấu trúc thành phần
JSONclass: Lớc công cụ chính, cung cấp các phương thức tĩnh nhưtoJSONString(),parseObject(),parseArray().JSONObject/JSONArray: Đại diện cho đối tượng/mảng JSON động, tương tự như Map/List.SerializerFeature/Feature: Các tùy chọn để điều khiển hành vi serialization/deserialization.ObjectSerializer/ObjectDeserializer: Giao diện cho logic serialization/deserialization tùy chỉnh.- ASM + tối ưu reflection: Fastjson sử dụng rộng rãi tạo bytecode (ASM) và cache thông tin reflection để tăng hiệu suất.
1.2 Quy trình làm việc (đơn giản hóa)
- Serialization:
- Sử dụng reflection để lấy các thuộc tính của đối tượng;
- Gọi
ObjectSerializertích hợp hoặc tùy chỉnh; - Xuất ra chuỗi hoặc ghi vào
Writer/OutputStream.
- Deserialization:
- Phân tích chuỗi JSON thành luồng token;
- Tạo instance dựa trên loại đích (Class);
- Gán giá trị qua setter hoặc trực tiếp vào thuộc tính (hỗ trợ thuộc tính private);
- Hỗ trợ suy đoán tự động kiểu (cần cẩn thận, có rủi ro bảo mật).
⚠️ Lưu ý: Tính năng
autoTypecủa Fastjson (tự động nhận diện trường@type) đã nhiều lần gây ra lỗ hổng thực thi từ xa (RCE), trong môi trường sản xuất cần tắt hoặc kiểm soát nghiêm ngặt bằng danh sách trắng.
II. Phụ thuộc Maven (khuyến nghị sử dụng phiên bản bảo mật mới nhất)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.57</version> <!-- Fastjson 2.x là phiên bản được viết lại, an toàn hơn -->
</dependency>
Nên sử dụng Fastjson 2.x (tên gói
com.alibaba.fastjson2), phiên bản 1.x đã ngừng bảo trì và có lỗ hổng nghiêm trọng.
Bài viết này tập trung vào Fastjson 2.x (API rõ ràng hơn, bảo mật cao hơn), đồng thời ghi nhận sự khác biệt với 1.x.
III. Ví dụ sử dụng cơ bản (Fastjson 2.x)
3.1 Import package (lưu ý thay đổi tên gói)
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.JSONReader;
Tên gói của Fastjson 1.x là
com.alibaba.fastjson.
3.2 Đối tượng Java → Chuỗi JSON (serialization)
public class NguoiDung {
public String ten;
public int tuoi;
public Date thoiGianTao;
public NguoiDung(String ten, int tuoi) {
this.ten = ten;
this.tuoi = tuoi;
this.thoiGianTao = new Date();
}
}
// Serialization
NguoiDung nguoiDung = new NguoiDung("Trần Văn A", 25);
String json = JSON.toJSONString(nguoiDung);
System.out.println(json);
// Output: {"tuoi":25,"thoiGianTao":1706000000000,"ten":"Trần Văn A"}
Định dạng đầu ra (Pretty)
String jsonDep = JSON.toJSONString(nguoiDung, JSONWriter.Feature.PrettyFormat);
Bỏ qua giá trị null
String json = JSON.toJSONString(nguoiDung, JSONWriter.Feature.WriteNulls); // Mặc định không ghi null
// Để bỏ qua null:
String json = JSON.toJSONString(nguoiDung, JSONWriter.Feature.NotWriteDefaultValue);
3.3 Chuỗi JSON → Đối tượng Java (deserialization)
String json = "{\"ten\":\"Nguyễn Văn B\",\"tuoi\":30}";
NguoiDung nguoiDung = JSON.parseObject(json, NguoiDung.class);
System.out.println(nguoiDung.ten); // Nguyễn Văn B
Hỗ trợ generic (List, Map)
String jsonArray = "[{\"ten\":\"X\",\"tuoi\":1},{\"ten\":\"Y\",\"tuoi\":2}]";
// Cách 1: TypeReference (khuyến nghị)
List<NguoiDung> danhSach = JSON.parseObject(jsonArray,
new TypeReference<List<NguoiDung>>() {});
// Cách 2: Class trực tiếp (chỉ cho non-generic)
JSONArray mang = JSON.parseArray(jsonArray);
NguoiDung dauTien = mang.get(0).to(NguoiDung.class);
3.4 Thao tác JSON động (JSONObject / JSONArray)
// Tạo JSONObject
JSONObject obj = new JSONObject();
obj.put("ten", "Lê Văn C");
obj.put("diem", 95);
// Lấy giá trị
String ten = obj.getString("ten");
int diem = obj.getIntValue("diem");
// Chuyển thành đối tượng Java
NguoiDung nguoiDung = obj.to(NguoiDung.class);
// JSONArray
JSONArray arr = new JSONArray();
arr.add(obj);
arr.add(new JSONObject(Map.of("ten", "Phạm Văn D")));
// Duyệt
for (Object o : arr) {
JSONObject item = (JSONObject) o;
System.out.println(item.getString("ten"));
}
IV. Tùy chọn cấu hình thường dùng (Feature)
4.1 Cấu hình serialization (JSONWriter.Feature)
| Tùy chọn | Mô tả |
|---|---|
WriteNulls |
Xuất trường có giá trị null (mặc định không xuất) |
PrettyFormat |
Định dạng đầu ra (thụt lề) |
WriteClassName |
Ghi trường @type (nguy hiểm! cẩn thận dùng) |
FieldBased |
Sử dụng trường thay vì getter (truy cập được trường private) |
NotWriteDefaultValue |
Không xuất giá trị mặc định (như 0, false, null) |
Ví dụ:
JSON.toJSONString(nguoiDung,
JSONWriter.Feature.PrettyFormat,
JSONWriter.Feature.WriteNulls
);
4.2 Cấu hình deserialization (JSONReader.Feature)
| Tùy chọn | Mô tả |
|---|---|
SupportAutoType |
Bật tự động nhận diện @type (nguy hiểm! mặc định tắt) |
UseNativeObject |
Sử dụng JSONObject/JSONArray thay vì Map/List |
IgnoreSetNullValue |
Bỏ qua giá trị null trong JSON (không gọi setter) |
Khuyến nghị bảo mật: Không bao giờ bật
SupportAutoType, trừ khi bạn biết rõ rủi ro và đã cấu hình danh sách trắng.
V. Điều khiển hành vi serialization bằng annotation
Fastjson cung cấp nhiều annotation:
| Annotation | Tác dụng |
|---|---|
@JSONField(name = "ho_va_ten") |
Tùy chỉnh tên trường |
@JSONField(serialize = false) |
Bỏ qua khi serialization |
@JSONField(deserialize = false) |
Bỏ qua khi deserialization |
@JSONField(format = "yyyy-MM-dd") |
Định dạng ngày |
@JSONField(ordinal = 1) |
Kiểm soát thứ tự trường |
Ví dụ:
public class NguoiDung {
@JSONField(name = "ho_va_ten")
public String ten;
@JSONField(serialize = false)
public String matKhau;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
public Date thoiGianDangNhap;
}
VI. Serialization/deserialization tùy chỉnh
6.1 Triển khai ObjectWriter (serialization)
public class SoDienThoaiWriter implements ObjectWriter<String> {
@Override
public void write(JSONWriter writer, Object object, Object fieldName, Type fieldType, long features) {
String soDienThoai = (String) object;
if (soDienThoai != null && soDienThoai.length() == 11) {
String biMat = soDienThoai.substring(0, 3) + "****" + soDienThoai.substring(7);
writer.writeString(biMat);
} else {
writer.writeString(soDienThoai);
}
}
}
Cách đăng ký (toàn cầu):
// Fastjson 2.x hiện chưa hỗ trợ đăng ký toàn cầu đơn giản, thường dùng annotation
@JSONField(serializeUsing = SoDienThoaiWriter.class)
public String soDienThoai;
6.2 Triển khai ObjectReader (deserialization)
public class SoDienThoaiMaHoaReader implements ObjectReader<String> {
@Override
public String readObject(JSONReader reader, Type fieldType, Object fieldName, long features) {
String maHoa = reader.readString();
// Giả giải mã
return giaiMa(maHoa);
}
}
Sử dụng:
@JSONField(deserializeUsing = SoDienThoaiMaHoaReader.class)
public String soDienThoai;
VII. So sánh Fastjson 1.x và 2.x chính
| Đặc điểm | Fastjson 1.x | Fastjson 2.x |
|---|---|---|
| Tên gói | com.alibaba.fastjson |
com.alibaba.fastjson2 |
| Hiệu suất | Nhanh | Nhanh hơn (tối ưu lại) |
| Bảo mật | Nhiều lỗ hổng nghiêm trọng | Mặc định tắt autoType, an toàn hơn |
| API | SerializerFeature |
JSONWriter.Feature |
| Annotation | @JSONField giống nhau |
Tương thích, thêm tính năng |
| Hỗ trợ Android | Hỗ trợ | Hỗ trợ tốt hơn |
Dự án mới nên ưu tiên sử dụng Fastjson 2.x
VIII. Vấn đề thường gặp và thực hành tốt nhất
Vấn đề bảo mật
- **Không bao giờ bật
SupportAutoType**, trừ khi kết hợp với danh sách trắng:
ParserConfig.getGlobalInstance().addAccept("com.yourpackage.");
- Tránh deserialization JSON từ nguồn không đáng tin cậy.
Thực hành tốt nhất
- Sử dụng
TypeReferencexử lý generic. - Trường nhạy cảm dùng
@JSONField(serialize = false). - Ngày tháng thống nhất dùng
@JSONField(format = "..."). - Môi trường sản xuất tắt
WriteClassName. - Nâng cấp lên Fastjson 2.x.
IX. Ví dụ hoàn chỉnh (Fastjson 2.x)
import com.alibaba.fastjson2.*;
import java.util.*;
public class FastjsonDemo {
public static void main(String[] args) {
// 1. Serialization
NguoiDung nguoiDung = new NguoiDung("Alice", 28);
String json = JSON.toJSONString(nguoiDung, JSONWriter.Feature.PrettyFormat);
System.out.println(json);
// 2. Deserialization
NguoiDung daPhong = JSON.parseObject(json, NguoiDung.class);
// 3. Generic List
List<NguoiDung> danhSach = Arrays.asList(nguoiDung, new NguoiDung("Bob", 30));
String jsonDanhSach = JSON.toJSONString(danhSach);
List<NguoiDung> danhSachDaPhong = JSON.parseObject(jsonDanhSach,
new TypeReference<List<NguoiDung>>() {});
// 4. Thao tác động
JSONObject obj = JSON.parseObject(json);
obj.put("thongTinThem", "them");
System.out.println(obj.getString("ten"));
}
public static class NguoiDung {
@JSONField(name = "ho_ten")
public String ten;
public int tuoi;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
public Date thoiGianTao;
public NguoiDung(String ten, int tuoi) {
this.ten = ten;
this.tuoi = tuoi;
this.thoiGianTao = new Date();
}
}
}
Tổng kết
- Fastjson 2.x là phiên bản được khuyến nghị hiện nay, hiệu suất cao, API rõ ràng, bảo mật được cải thiện.
- Lớp cốt lõi:
JSON,JSONObject,JSONArray. - Kiểm soát chi tiết hành vi serialization qua
@JSONFieldvàFeature. - Bảo mật là ưu tiên: Tắt autoType, tránh tấn công deserialization.
- Logic tùy chỉnh có thể thực hiện qua
ObjectWriter/ObjectReader.
Mặc dù Fastjson vẫn có场景 sử dụng, nhưng trong dự án mới, nếu không có yêu cầu hiệu suất đặc biệt, Jackson (mặc định của Spring Boot) vẫn là lựa chọn an toàn và chuẩn hơn.