JSON-B是Java EE 8规范中的新API之一。它用于解决标准化Java对象如何在JSON中进行序列化。
JSON-B,即Java API for JSON Binding,用于JSON绑定的Java API,是一套最新的API,也是Java EE 8规范的一部分。JSON-B规范试图标准化Java对象在JSON中序列化/反序列化的方式,并在这方面定义了一套标准的API。
本文将展示JSON-B API提供的核心功能。
创建一个新的Maven项目,添加如下依赖关系:
<dependencies>
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
注意:由于Yasson(JSON-B参考实现)在内部依赖于JSON-P API,所以对类路径添加了对JSON-P参考实现的依赖。如果将来使用另一个JSON-B实现,或者如果要在运行时已经提供此依赖关系的应用程序服务器上部署应用程序,则可能不需要这样做。
Eclipse Yasson是JSON-B规范的参考实现,与XML领域的JAXB相似。Yasson是JSR-367规范(JSON Binding)官方的参考实现。
Yasson定义了一个在现有Java类和JSON文档之间的默认的映射算法,适合大多数情况:
Jsonb jsonb= JsonbBuilder.create();
String result = jsonb.toJson(someObject);
如果还不够,可以使用它提供的一组丰富的注释和API来实现定制的功能:
// 创建自定义配置
JsonbConfig config = new JsonbConfig()
.withNullValues(true)
.withFormating(true);
// 使用自定义配置来创建Jsonb
Jsonb jsonb = JsonbBuilder.create(config);
// 使用它
String result = jsonb.toJson(someObject);
JSON-B API在javax.json.bind包内提供。最重要的接口是Jsonb,它可以通过名为JsonbBuilder的构建器类来实例化。当有这个类的引用时,你可以调用toJson或fromJson方法之一来对JSON字符串进行序列化和反序列化。
Shape shape = new Shape();
shape.setArea(12);
shape.setType("RECTANGLE");
Jsonb jsonb = JsonbBuilder.create();
// 将对象shape序列化为JSON
String jsonString = jsonb.toJson(shape); // 输出:{"area":12, "type":"RECTANGLE"}
// 将一个JSON字符串反序列化为一个对象
Shape s = jsonb.fromJson("{\"area\":12, \"type\":\"RECTANGLE\"}");
请注意,对于反序列化过程,类应该有一个默认的构造函数,否则会抛出一个异常。
JSON-B的API非常精炼,几乎不涉及复杂性。在javax.jsonb包下提供的所有其他API和注解(数量很少)仅用于定制序列化和反序列化的过程。
Java基本类型及其相应的包装类被序列化为JSON的方式遵循其toString()方法文档定义的转换过程。同样,对于反序列化过程,使用其parse()方法(parseInt,parseLong等)定义的转换过程。然而,参考实现没有必要调用这些方法,只要遵守它们的转换过程即可。
为了演示如何将这些类型映射到JSON,请考虑一个名为Apartment的类,其结构如下:
public class Apartment {
private boolean rented;
private byte rooms;
private int price;
private long id;
private float loan;
private double area;
private char district;
private String ownerName;
public boolean isRented() {
return rented;
}
public void setRented(boolean rented) {
this.rented = rented;
}
public byte getRooms() {
return rooms;
}
public void setRooms(byte rooms) {
this.rooms = rooms;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public float getLoan() {
return loan;
}
public void setLoan(float loan) {
this.loan = loan;
}
public double getArea() {
return area;
}
public void setArea(double area) {
this.area = area;
}
public char getDistrict() {
return district;
}
public void setDistrict(char district) {
this.district = district;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
}
下面的代码片段试图序列化这个类的一个实例:
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class Application {
public static void main(String[] args) {
Apartment apartment = new Apartment();
apartment.setRented(true);
apartment.setRooms((byte) 4);
apartment.setPrice(7800000);
apartment.setId(234L);
apartment.setLoan(3580000.4f);
apartment.setArea(432.45);
apartment.setDistrict('S');
apartment.setOwnerName("Nerssi");
Jsonb jsonb = JsonbBuilder.create();
String jsonString = jsonb.toJson(apartment);
System.out.println(jsonString);
}
}
执行程序,JSON输出显示如下(添加注释使其更具可读性):
{
"area":432.45, // double
"district":"S", // char
"id":234, // long
"loan":3580000.5, // float
"ownerName":"Nerssi", // String
"price":7800000, // int
"rented":true, // boolean
"rooms":4 // byte
}
可以看出,每个字段使用的值与在相应的包装类上调用toString方法完全相同。此外,字符串String类和字符Character类都转换为UTF-8字符串。