日常开发中,json数据格式经常会被用到,其简单易懂的写法(对人与计算机皆如此)以及其轻量级特性非常适用于网络间的数据传递。json数据格式与java对象会经常进行相互转换,本文探讨的是json to java的转换。
Jsonschema2pojo即是一种json转换java的工具
在解决json2java的问题时,一般使用四种主流的JSON库来进行json解析:
其底层使用的json2java工具即为Jackson 2.x,Jsonschema2pojo基于Jackson 2.x提供的java注解与规范对json数据进行解析,相应的,json数据也就需要有它本身一定的写法规范,Jsonschema2pojo定义了json schema的规范和书写方式
这里,我就常用的以及一些扩展的书写规范向大家一一说明,也提供了一些例子供参考。
下表为json schema书写过程中固定的一些rule,请先简单阅读:
JSON Schema rule | Supported | Since | Note |
---|---|---|---|
type (Simple) | Yes | 0.1.0 | |
type (Union) | No | ||
properties | Yes | 0.1.0 | |
patternProperties | No | ||
additionalProperties | Yes | 0.1.3 | |
items | Yes | 0.1.0 | |
additionalItems | No | ||
required | Yes | 0.1.6 | |
optional | Yes | 0.1.0 | Deprecated |
dependencies | No | ||
minimum, maximum | Yes | 0.3.2 | Via optional JSR-303 annotations |
exclusiveMinimum, exclusiveMaximum | No | ||
minItems, maxItems | Yes | 0.3.2 | Via optional JSR-303 annotations |
uniqueItems | Yes | 0.1.0 | |
pattern | Yes | 0.3.2 | Via optional JSR-303 annotations |
minLength, maxLength | Yes | 0.3.4 | Via optional JSR-303 annotations |
enum | Yes | 0.1.0 | |
default | Yes | 0.1.7 | |
title | Yes | 0.1.6 | |
description | Yes | 0.1.0 | |
format | Yes | 0.1.0 | |
divisibleBy | No | ||
disallow | No | ||
extends | Yes | 0.1.8 | |
id | No | ||
$ref | Yes | 0.1.6 | Supports absolute, relative, slash & dot delimited fragment paths, self-ref |
$schema | No |
1
2
3
4
5
6
7
8
|
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string"
}
}
}
|
1
2
3
4
5
6
7
8
9
|
public class MyObject {
private String foo;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
|
properties用于指定schema的参数,转换为pojo后,properties中的属性foo会转换为java对象的属性foo,”type”用来指定对象或属性的类型
指定所定义的有类型概念的数据类型,下表为json schema中type声明类型与pojo中声明类型间的对应关系:
Schema Type | Java Type |
---|---|
string | java.lang.String |
number | java.lang.Double |
integer | java.lang.Integer |
boolean | java.lang.Boolean |
object | generated Java type |
array | java.util.List |
array (with “uniqueItems”:true) | java.util.Set |
null | java.lang.Object |
any | java.lang.Object |
1
2
3
4
|
{
"type" : "object",
"additionalProperties" : {}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class MyObject {
private java.util.Map
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
|
additionalProperties为true,会生成Map作为传入参数中附加参数的接受器,false则不生成,写成“{}”等同于true。 你也可以通过指定additionalProperties的数据类型来约束生成的结果。
1
2
3
4
5
6
|
{
"type" : "object",
"additionalProperties" : {
"type" : "number"
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class MyObject {
private java.util.Map
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, Double value) {
this.additionalProperties.put(name, value);
}
}
|
上面将additionalProperties的类型改为Double,pojo中属性的泛型就会变为
如果将type指定为object(我的json文件名为source.json)
1
2
3
4
5
6
|
{
"type" : "object",
"additionalProperties" : {
"type" : "object"
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Source{
private java.util.Map
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, SourceProperty value) {
this.additionalProperties.put(name, value);
}
}
|
如上,会生成一个以主文件名为前缀,Property为后缀的类(SourceProperty)作为additionalProperties的value类型,该类中则有:
1
|
private Map |
1
2
3
4
5
6
7
8
9
10
11
|
{
"type" : "object",
"properties" : {
"myArrayProperty" : {
"type" : "array",
"items" : {
"type" : "string"
}
}
}
}
|
array写法如上即会生成Array
类型的参数myArrayProperty,如果在myArrayProperty指定“uniqueItems”:true,生成的集合则为Set<>. 对于items,可以$ref(后面介绍)引用其他jsonschema文件,也可以直接在其下编写jsonschema,会生成一个以集合参数为名称(MyArrayProperty)的对象作为该集合的泛型
1
2
3
4
5
6
7
8
9
|
{
"type" : "object",
"properties" : {
"myEnum" : {
"type" : "string",
"enum" : ["one", "secondOne", "3rd one"]
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@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);
}
}
|
enum作为枚举写法经常被使用,比较简单,不详细介绍
可以给属性指定format规则,它会影响你的参数类型,和type对比,format的优先级更高,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 |
anything else (unrecognised format) | type is unchanged |
extends属性声明在schema层表明继承
flower.json:
1
2
3
|
{
"type" : "object"
}
|
rose.json
1
2
3
4
5
6
|
{
"type" : "object",
"extends" : {
"$ref" : "flower.json"
}
}
|
Rose.java:
1
2
3
|
public class Rose extends Flower {
....
}
|
- http://, https://
- file://
- classpath:, resource:, java: (all synonyms used to resolve schemas from the classpath)
1
2
3
4
5
6
7
8
9
10
11
|
{
"type" : "object",
"properties" : {
"child1" : {
"type" : "string"
},
"child2" : {
"$ref" : "#/properties/child1"
}
}
}
|
上面这种child2引用了child1的属性
1
2
3
4
5
6
7
8
9
10
11
12
|
{
"description" : "Tree node",
"type" : "object",
"properties" : {
"children" : {
"type" : "array",
"items" : {
"$ref" : "#"
}
}
}
}
|
这种写法将shema类型作为集合类型泛型的引用,类似于tree结构 也可以直接定位到集合的items属性作为类型(#/properties/children/items)
1
2
3
4
|
{
"javaType" : "com.other.package.CustomTypeName",
"type" : "object"
}
|
javaType允许指定属性类型或类名称为java类(已存在或不存在的),如此生成会创建一个CustomTypeName类,并将属性类型指定为该类 如果不加”type” : “object”,则不会生成对应类,但是属性类型依然为该类名,报错而已 当然,你也可以直接指定已有的封装类
1
2
3
4
5
6
7
8
9
10
|
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string",
"enum" : ["H","L"],
"javaEnumNames" : ["HIGH","LOW"]
}
}
}
|
1
2
3
4
5
|
public enum Foo {
HIGH("H"),
LOW("L")
...
}
|
javaEnumNames是对于enum的扩展,可以指定java中的enum列表具体名称
1
2
3
4
|
{
"javaInterfaces" : ["java.io.Serializable", "Cloneable"],
"type" : "object"
}
|
1
2
3
4
|
public class FooBar implements Serializable, Cloneable
{
...
}
|
这个好理解,声明接口
该属性用于指定类或属性的生成名称
1
2
3
4
5
6
7
8
9
|
{
"type": "object",
"properties": {
"a": {
"javaName": "b",
"type": "string"
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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;
}
}
|
如果使用在主schema级别,可以直接指定对应的类名
转载自:https://eternityrain.github.io/2016/09/27/Jsonschema2pojo/
作者:拉手研发技术部