Json schema规范写法

部署运行你感兴趣的模型镜像

简介

日常开发中,json数据格式经常会被用到,其简单易懂的写法(对人与计算机皆如此)以及其轻量级特性非常适用于网络间的数据传递。json数据格式与java对象会经常进行相互转换,本文探讨的是json to java的转换。
Jsonschema2pojo即是一种json转换java的工具

主流JSON库

在解决json2java的问题时,一般使用四种主流的JSON库来进行json解析:

  • JSON.simple
  • GSON
  • Jackson
  • JSONP

Jsonschema2pojo

其底层使用的json2java工具即为Jackson 2.x,Jsonschema2pojo基于Jackson 2.x提供的java注解与规范对json数据进行解析,相应的,json数据也就需要有它本身一定的写法规范,Jsonschema2pojo定义了json schema的规范和书写方式

Json Schema feature support

这里,我就常用的以及一些扩展的书写规范向大家一一说明,也提供了一些例子供参考。

下表为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  

properties

schema
     
1
2
3
4
5
6
7
8
     
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string"
}
}
}
java
     
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”用来指定对象或属性的类型

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

additionalProperties

schema1
     
1
2
3
4
     
{
"type" : "object",
"additionalProperties" : {}
}
java1
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     
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);
}
}

additionalProperties为true,会生成Map作为传入参数中附加参数的接受器,false则不生成,写成“{}”等同于true。 你也可以通过指定additionalProperties的数据类型来约束生成的结果。

schema2
     
1
2
3
4
5
6
     
{
"type" : "object",
"additionalProperties" : {
"type" : "number"
}
}
java2
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     
public class MyObject {
private java.util.Map<String, Double> additionalProperties = new java.util.HashMap<String, Double>();
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map<String, Double> getAdditionalProperties() {
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, Double value) {
this.additionalProperties.put(name, value);
}
}

上面将additionalProperties的类型改为Double,pojo中属性的泛型就会变为<String, Double> 如果将type指定为object(我的json文件名为source.json)

schema3
     
1
2
3
4
5
6
     
{
"type" : "object",
"additionalProperties" : {
"type" : "object"
}
}
java3
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     
public class Source{
private java.util.Map<String, SourceProperty> additionalProperties = new java.util.HashMap<String, SourceProperty>();
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map<String, SourceProperty> getAdditionalProperties() {
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, SourceProperty value) {
this.additionalProperties.put(name, value);
}
}

如上,会生成一个以主文件名为前缀,Property为后缀的类(SourceProperty)作为additionalProperties的value类型,该类中则有:

java4
     
1
     
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

array

schema
     
1
2
3
4
5
6
7
8
9
10
11
     
{
"type" : "object",
"properties" : {
"myArrayProperty" : {
"type" : "array",
"items" : {
"type" : "string"
}
}
}
}

array写法如上即会生成Array<string>类型的参数myArrayProperty,如果在myArrayProperty指定“uniqueItems”:true,生成的集合则为Set<>. 对于items,可以$ref(后面介绍)引用其他jsonschema文件,也可以直接在其下编写jsonschema,会生成一个以集合参数为名称(MyArrayProperty)的对象作为该集合的泛型

enum

schema
     
1
2
3
4
5
6
7
8
9
     
{
"type" : "object",
"properties" : {
"myEnum" : {
"type" : "string",
"enum" : ["one", "secondOne", "3rd one"]
}
}
}
java
     
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

可以给属性指定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

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 {
....
}

$ref

Supported protocols
  • http://, https://
  • file://
  • classpath:, resource:, java: (all synonyms used to resolve schemas from the classpath)
$ref同样支持内部类型的引用
     
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)

javaType


 
      
1
2
3
4
      
{
"javaType" : "com.other.package.CustomTypeName",
"type" : "object"
}

javaType允许指定属性类型或类名称为java类(已存在或不存在的),如此生成会创建一个CustomTypeName类,并将属性类型指定为该类 如果不加”type” : “object”,则不会生成对应类,但是属性类型依然为该类名,报错而已 当然,你也可以直接指定已有的封装类

javaEnumNames

schema
     
1
2
3
4
5
6
7
8
9
10
     
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string",
"enum" : ["H","L"],
"javaEnumNames" : ["HIGH","LOW"]
}
}
}
java
     
1
2
3
4
5
     
public enum Foo {
HIGH("H"),
LOW("L")
...
}

javaEnumNames是对于enum的扩展,可以指定java中的enum列表具体名称

javaInterfaces

schema
     
1
2
3
4
     
{
"javaInterfaces" : ["java.io.Serializable", "Cloneable"],
"type" : "object"
}
java
     
1
2
3
4
     
public class FooBar implements Serializable, Cloneable
{
...
}

这个好理解,声明接口

javaName

该属性用于指定类或属性的生成名称

schema
     
1
2
3
4
5
6
7
8
9
     
{
"type": "object",
"properties": {
"a": {
"javaName": "b",
"type": "string"
}
}
}
java
     
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/

作者:拉手研发技术部

您可能感兴趣的与本文相关的镜像

LobeChat

LobeChat

AI应用

LobeChat 是一个开源、高性能的聊天机器人框架。支持语音合成、多模态和可扩展插件系统。支持一键式免费部署私人ChatGPT/LLM 网络应用程序。

你提出的问题: > `"date"` 并不是 `$jsonSchema` 中合法的 `bsonType` 名称,验证时报错。 这个说法**在某些情况下是正确的**,但需要澄清一个关键点:是否真的不支持?还是使用方式或环境有问题? 我们来 **彻底分析原因、验证事实,并提供解决方案**。 --- ### ✅ 事实澄清:`"date"` 是合法的 `bsonType`(从 MongoDB 3.6+ 开始) MongoDB 的 `$jsonSchema` 支持 `"date"` 作为 `bsonType` 的取值之一,**官方文档明确列出它为有效类型**。 #### 官方文档依据(MongoDB 4.0+): > [MongoDB $jsonSchema 文档](https://www.mongodb.com/docs/manual/reference/operator/query/jsonSchema/#bson-types) > > 支持的 `bsonType` 包括: > - `"double"` > - `"string"` > - ... > - `"date"` ✅ > - `"timestamp"` > - ... 所以结论是: > ✅ **`"date"` 是合法且推荐用于表示 BSON Date 类型的 `bsonType` 值** 但如果你遇到“`'date' is not a valid bsonType`”这类错误,说明你的 **MongoDB 版本太低 或 驱动/工具链有兼容性问题**。 --- ## 🔍 常见导致 `"date"` 不被识别的原因及解决方案 --- ### ❌ 原因 1:MongoDB 版本低于 3.6 - `$jsonSchema` 查询操作符是在 **MongoDB 3.6** 引入的; - 在此之前版本中,即使写 `"date"`,也会报错; - 更早版本(如 3.4 或 3.2)根本不支持 `$jsonSchema`; 🔧 检查你的 MongoDB 版本: ```javascript db.version() ``` 📌 要求: - 必须 ≥ **3.6** 才能使用 `$jsonSchema` - 推荐使用 **4.0+** 以获得完整功能支持 ✅ 解决方案: > 升级 MongoDB 到 4.0 或更高版本 --- ### ❌ 原因 2:拼写错误或大小写问题 确保你写的确实是小写的 `"date"`,而不是: - `"Date"` ❌(首字母大写) - `"datetime"` ❌(不存在) - `"time"` ❌(非法) - `"timestamp"` ❌(这是另一个类型) ✅ 正确写法: ```cpp << "bsonType" << "date" ``` ❌ 错误写法示例: ```cpp << "bsonType" << "Date" << "bsonType" << "datetime" << "bsonType" << "Time" ``` --- ### ❌ 原因 3:使用了旧版驱动或 schema 构造方式不当 某些 C++ 驱动封装层可能对字段名做了校验,或者你在用 JSON 字符串解析时未正确转义。 #### 示例:正确构造 schema 的 C++ 写法(使用 mongocxx) ```cpp #include <mongocxx/client.hpp> #include <mongocxx/instance.hpp> #include <bsoncxx/builder/stream/document.hpp> using namespace bsoncxx::builder::stream; auto validator = make_document( open_document << "$jsonSchema" << open_document << "bsonType" << "object" << "required" << open_array << "createdAt" << close_array << "properties" << open_document << "createdAt" << open_document << "bsonType" << "date" // ✅ 合法 << close_document << close_document << close_document << close_document ); // 应用到集合 mongocxx::options::create_collection opts; opts.validator(validator.view()); db.create_collection("messages", opts); ``` 如果这里报错,说明驱动或服务端不支持。 --- ### ❌ 原因 4:通过某些 GUI 工具(如 Compass、Studio 3T)输入 schema 时限制 部分可视化工具为了“安全”或“简化”,可能会过滤掉 `"date"`,提示它不在列表中。 📌 实际上服务端接受它,但前端 UI 屏蔽了。 ✅ 解决方法: > 使用 `mongo` shell 或程序方式直接设置 validator,绕过 GUI 限制。 例如在 `mongosh` 中运行: ```js db.createCollection("test", { validator: { $jsonSchema: { bsonType: "object", properties: { createdAt: { bsonType: "date" } } } } }) ``` ✔️ 这样是可以成功创建的(MongoDB 3.6+) --- ### ✅ 替代方案(仅限无法升级的老系统) 如果你**确实不能升级 MongoDB 到 3.6+**,而必须使用老版本(如 3.4),那么你可以这样变通: #### 方案:放弃 `bsonType: "date"`,改用 `type: "string"` + `format: "date-time"` 这是 **JSON Schema 标准中的做法**,虽然不是 BSON 原生类型检查,但可以配合正则实现类似效果。 ```cpp << "createdAt" << open_document << "bsonType" << "string" << "pattern" << "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})?$" << close_document ``` ⚠️ 缺点: - 存的是字符串,不能排序、不能索引优化; - 可能插入无效时间(如 `2025-02-30T...`); - 性能差; ✅ 优点: - 兼容老版本 MongoDB; - 至少格式看起来像时间; 📌 最终建议:尽早升级到现代 MongoDB 版本。 --- ### ✅ 如何确认 `"date"` 是否被支持? 运行以下命令测试: ```js db.runCommand({ collMod: "your_collection", validator: { $jsonSchema: { properties: { testField: { bsonType: "date" } } } } }) ``` ✅ 如果返回 `{ ok: 1 }` → 支持 ❌ 如果返回 `"ErrorMessage: 'date' is not a valid bsonType"` → 版本太低 --- ### 📌 总结:如何解决 `"date" is not a valid bsonType` 问题? | 问题原因 | 解决方案 | |--------|---------| | MongoDB 版本 < 3.6 | ✅ 升级到 3.6+ 或 4.0+ | | 拼写错误(如 `"Date"`) | ✅ 改为小写 `"date"` | | 使用了不支持的工具/UI | ✅ 改用 `mongosh` 或程序设置 | | 企业版/社区版差异? | ❌ 无区别,都支持 `"date"`(≥3.6) | | 驱动版本太老 | ✅ 更新 `mongocxx` 驱动到最新版 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值