前面我們介紹了 Json Schema
的基本內容,這篇文章我們結合 jsonschema2pojo
工具深入分析如何使用 Json Schema
生成 API,學習更多關於 Json Schema
的關鍵字等知識。
jsonschema2pojo
該庫提供了多種使用Json Schame
文件生成 Java 類的方法,比如 Maven
插件, Gradle
插件, Ant
任務, 以及直接使用命令行,甚至還可以在代碼中直接使用,具體參照 jsonschema2pojo Getting Started
這里我直接采用 Mac 命令行的方式,在 Mac 下安裝此命令的方式比較簡單,直接運行 brew install jsonschema2pojo
安裝即可。
properties
在一個類中,最關鍵的就是屬性了,每個類都可能有多個屬性,在 Json Schema
中就是通過 properties
來定義類的屬性的, properties 中的每個條目都是所定義類的一個屬性。
比如,對於此 Json Schema MyObject.json
:
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string"
}
}
}
我們執行 jsonschema2pojo
任務后,可以生成對應的 Java 類:
public class MyObject {
private String foo;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
type
像我們 Java 中有多種類型,那不同的類型在 Json Schema 中如何表示呢?一般通用的轉換如下所示,這也是 jsonschema2pojo 工具默認使用的轉換方式:
Schema Type | Java Type
:-: | :-:
string | java.lang.String
number | java.lang.Double
integer| java.lang.Integer
boolean| java.lang.Boolean
object | 自己生成的類
array | java.util.List
array(with “uniqueItems”:true)|java.util.Set
null | java.lang.object
any | java.lang.object
值的注意的是,如果我們增加了 usePrimitives
選項,對於 Integer, Double, Boolean
這三個包裝類將會轉換成基本類型 int, double, boolean
。
additionalProperties
我們平時開發中,為了類利於擴展,有時會給類增加一個Map
類型的屬性,這樣當外部需要傳更多的參數給我們時,不需要更改API,直接將參數放到這個 Map
里就可以快速實現。jsonschema2pojo
同樣也實現了這個功能,當我們沒有指定additionalProperties
屬性為false
或者沒有指定additionalProperties
屬性時,jsonschema2pojo
會為我們定義的類自動生成一個類型為Map
的additionalProperties
屬性。
比如:
{
"type" : "object"
}
或者
{
"type" : "object",
"additionalProperties" : {}
}
生成的類:
public class MyObject {
private java.util.Map<String, Object> additionalProperties = new java.util.HashMap<String, Object>();
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
items
items
用於指定我們定義 List
以及 Set
類型時的子元素詳情,比如子元素的類型以及描述等。
例如:
{
"type" : "object",
"properties" : {
"myArrayProperty" : {
"type" : "array",
"items" : {
"type" : "string"
}
}
}
}
生成的屬性:
List<String> myArrayProperty;
required
如果一個屬性在required
中指定了,那么這個屬性會有一個 Required
的注解,表明該屬性是必需的。
uniqueItems
這個就是我們上面表格中的用於區分 List
和 Set
的關鍵字了,如果我們定義的array
中聲明uniqueItems
為true
,那么最終轉換為的屬性的類型就為Set
。
enum
對於枚舉類型的定義需要使用到此關鍵字,比如:
{
"type" : "object",
"properties" : {
"myEnum" : {
"type" : "string",
"enum" : ["one", "secondOne", "3rd one"]
}
}
}
生成的枚舉類:
@Generated("com.googlecode.jsonschema2pojo")
public static enum MyEnum {
ONE("one"),
SECOND_ONE("secondOne"),
_3_RD_ONE("3rd one");
private final String value;
private MyEnum(String value) {
this.value = value;
}
@JsonValue
@Override
public String toString() {
return this.value;
}
@JsonCreator
public static MyObject.MyEnum fromValue(String value) {
for (MyObject.MyEnum c: MyObject.MyEnum.values()) {
if (c.value.equals(value)) {
return c;
}
}
throw new IllegalArgumentException(value);
}
}
default
如果我們需要某個屬性有默認值,可以加上此參數,生成類的屬性會自動實例化。具體可參照下表:
Json Schema | Java
:-: | :-:
myString : { “type”:“string”, “default”:“abc”} | myString : { “type”:“string”, “default”:“abc”};
myInteger : { “type”:“integer”, “default”:“100”} | private Integer myInteger = 100;
myNumber : { “type”:“number”, “default”:“10.3”}|private Double myNumber = 10.3D;
myMillis : { “type”:“string”, “format”:“utc-millisec”, “default”:“500”}|private Long myMillis = 500L;
myDate : { “type”:“string”, “format”:“date-time”, “default”:“500”}|private Date myDate = new Date(500L);
myDate : { “type”:“string”, “format”:“date-time”, “default”:“2011-02-24T09:25:23.112+0000”}|private Date myDate = new Date(1298539523112L);
myList : { “type”:“array”, “default”:[“a”,“b”,“c”]}|private List myList = new ArrayList(Arrays.asList(“a”,“b”,“c”));
title && description
title
和 description
用於描述一個屬性,當我們指定了這兩個參數時,jsonschema2pojo
會在屬性的上面生成 Java 文檔,並且title
在description
之上。
format
format
是jsonschema2pojo
提供給我們擴展更多類型的一個參數,在上面介紹的type
中可以看到我們生成的 Java 類型並不多,像 Date 等這些參數都沒有,但是當我們加上 jsonschema2pojo
能識別的format
參數后,就可以擴展我們的屬性類型,具體參照:
Format value | Java Type
:-: | :-:
“date-time” | java.util.Date
“date” | String
“time” | String
“utc-millisec” | long
“regex” | java.util.regex.Pattern
“color” | String
“style” | String
“phone” | String
“uri” | java.net.URI
“email” | String
“ip-address” | String
“ipv6” | String
“host-name” | String
“uuid” | java.util.UUID
extends
使用extends
關鍵字可以實現 Java
中的繼承。
比如,我們定義 flower.json
{
"type" : "object"
}
然后定義 rose.json
,使其繼承自 flower
{
"type" : "object",
"extends" : {
"$ref" : "flower.json"
}
}
最終我們生成的 Rose.java 為以下內容:
public class Rose extends Flower {
....
}
$ref
$ref
關鍵字用於指定某一個屬性的引用來源,在jsonschema2pojo
中支持以下協議:
- http://, https://
- file://
- classpath:, resource:, java: (all synonyms used to resolve schemas from the classpath).
我們定義 API 的時候一般是需要引用到其他我們定義的 Json Schema
文檔。比如:
{
"type" : "object",
"properties" : {
"loggedInUser" : {
"$ref" : "user.json"
}
}
}
表明loggedInUser
屬性的類型是一個由user.json
定義的類型。
{
"description" : "Tree node",
"type" : "object",
"properties" : {
"children" : {
"type" : "array",
"items" : {
"$ref" : "#"
}
}
}
}
這個表明 children
屬性引用的是該 object 自身,所以這可以生成一個 Tree 類型的類。
public class TreeNode {
public List<TreeNode> getChildren() {...}
public void setChildren(List<TreeNode> children) {...}
}
更多
-
javaEnumNames
{ "type" : "object", "properties" : { "foo" : { "type" : "string", "enum" : ["H","L"], "javaEnumNames" : ["HIGH","LOW"] } } }
生成的類:
public enum Foo { HIGH("H"), LOW("L") ... }
-
javaInterfaces
{ "javaInterfaces" : ["java.io.Serializable", "Cloneable"], "type" : "object" }
生成的類:
public class FooBar implements Serializable, Cloneable { ...
-
javaName
{ "type": "object", "properties": { "a": { "javaName": "b", "type": "string" } } }
生成的類:
public class MyClass { @JsonProperty("a") private String b; @JsonProperty("a") public String getB() { return b; } @JsonProperty("a") public void setB(String b) { this.b = b; } }
聲明
本文絕大部分內容是引用的
jsonschame2pojo
的文檔,更多內容請看官方文檔 jsonschema2pojo.