FASTJSON v2 JSONSchema Support
Since version 2.0.4, fastjson has provided support for JSONSchema. For the specific JSON Schema specification, please refer to https://json-schema.org/
1. Performance of FASTJSON2 JSONSchema
As always, the performance of FASTJSON2 JSONSchema is excellent, far surpassing its competitors. As the following test results show, fastjson2’s performance is 9 times that of networknt and 6 times that of everit.
Benchmark Mode Cnt Score Error Units
JSONSchemaBenchmark.everit thrpt 5 3.182 ± 0.018 ops/ms
JSONSchemaBenchmark.fastjson2 thrpt 5 21.408 ± 0.147 ops/ms
JSONSchemaBenchmark.networknt thrpt 5 2.337 ± 0.007 ops/ms
- Test code: https://github.com/alibaba/fastjson2/blob/main/benchmark/src/main/java/com/alibaba/fastjson2/benchmark/jsonschema/JSONSchemaBenchmark.java
2. Direct Validation by Constructing a JSONSchema Object
@Test
public void test() {
// Define that the object must contain 'longitude' and 'latitude' properties,
// where longitude's value range is [-180, 180] and latitude's is [-90, 90]
JSONSchema schema = JSONSchema.of(JSON.parseObject("{" +
" \"type\": \"object\"," +
" \"properties\": {" +
" \"longitude\": { \"type\": \"number\", \"minimum\":-180, \"maximum\":180}," +
" \"latitude\": { \"type\": \"number\", \"minimum\":-90, \"maximum\":90}," +
" }," +
" \"required\": [\"longitude\", \"latitude\"]" +
"}"));
// Validate a JSONObject, validation passes
assertTrue(
schema.isValid(
JSONObject.of("longitude", 120.1552, "latitude", 30.2741)
)
);
// Validate a JSONObject, fails because longitude exceeds the maximum value
assertFalse(
schema.isValid(
JSONObject.of("longitude", 220.1552, "latitude", 30.2741)
)
);
// Validate a JavaBean object, validation passes
assertTrue(
schema.isValid(
new Point(120.1552, 30.2741)
)
);
// Validate a JavaBean object, fails because latitude exceeds the maximum value
assertFalse(
schema.isValid(
new Point(120.1552, 130.2741)
)
);
}
public static class Point {
public final double longitude;
public final double latitude;
public Point(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
}
3. Configuring schema on JSONField
Since version 2.0.4, you can configure a schema on the JSONField annotation to validate the input JSON data.
public static class Point1 {
@JSONField(schema = "{'minimum':-180,'maximum':180}")
public double longitude;
@JSONField(schema = "{'minimum':-90,'maximum':90}")
public double latitude;
}
@Test
public void test1() {
// parseObject validation passes
JSON.parseObject("{\"longitude\":120.1552,\"latitude\":30.2741}", Point1.class);
// JSONObject to JavaObject, validation passes
JSONObject.of("longitude", 120.1552, "latitude", 30.2741)
.to(Point1.class);
// parseObject validation fails, longitude exceeds the maximum value
assertThrows(JSONSchemaValidException.class, () ->
JSON.parseObject("{\"longitude\":220.1552,\"latitude\":30.2741}", Point1.class)
);
// Validate JSONObject fails, longitude exceeds the maximum value
assertThrows(JSONSchemaValidException.class, () ->
JSONObject.of("longitude", 220.1552, "latitude", 30.2741)
.to(Point1.class)
);
}
4. Configuring schema on JSONType
Since version 2.0.4, you can configure a schema on the JSONType annotation to validate the input JSON data.
@JSONType(schema = "{'properties':{'longitude':{'type':'number','minimum':-180,'maximum':180},'latitude':{'type':'number','minimum':-90,'maximum':90}}}")
public static class Point2 {
@JSONField(schema = "{'minimum':-180,'maximum':180}")
public double longitude;
@JSONField(schema = "{'minimum':-90,'maximum':90}")
public double latitude;
}
@Test
public void test2() {
// parseObject validation passes
JSON.parseObject("{\"longitude\":120.1552,\"latitude\":30.2741}", Point2.class);
// JSONObject to JavaObject, validation passes
JSONObject.of("longitude", 120.1552, "latitude", 30.2741)
.to(Point2.class);
// parseObject validation fails, longitude exceeds the maximum value
assertThrows(JSONSchemaValidException.class, () ->
JSON.parseObject("{\"longitude\":220.1552,\"latitude\":30.2741}", Point2.class)
);
// Validate JSONObject fails, longitude exceeds the maximum value
assertThrows(JSONSchemaValidException.class, () ->
JSONObject.of("longitude", 220.1552, "latitude", 30.2741)
.to(Point2.class)
);
}
5. Constructing JSONSchema from a Type
When interacting between the backend and frontend, it is often necessary to convert a Java type into a JSONSchema and return it to the client.
@Test
public void test() {
JSONSchema schema = JSONSchema.of(Bean.class);
String string = schema.toString();
assertEquals(
"{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"integer\"},\"name\":{\"type\":\"string\"}},\"required\":[\"id\"]}",
string
);
JSONSchema pased = JSONSchema.of(JSON.parseObject(string));
assertTrue(Differ.diff(schema, pased));
Bean bean = new Bean();
JSONSchema valueSchema = JSONSchema.ofValue(bean);
assertTrue(Differ.diff(schema, valueSchema));
}
public static class Bean {
public int id;
public String name;
}
6. Constructing JSONSchema from a Value Object
@Test
public void fromValueMap() {
Map map = new HashMap();
map.put("id", 123);
assertEquals("{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"integer\"}}}", JSONSchema.ofValue(map).toString());
}