Snack JSONPath 项目架构分析

Snack JSONPath 项目架构分析 ack JSONPath是一个高性能 Java JSONPath 处理框架支持JSON DOM 文档模型JSONPath 查询兼容 jayway.jsonpath 和 IETF JSONPath RFC 9535JSONSchema 生成与校验支持 Draft-07 / Draft-2019-09 / Draft-2020-12语言: Java (JDK 8)构建: Maven 多模块项目模块结构snackjson/ ├── snack4/ # 核心 JSON 库 ├── snack4-jsonpath/ # JSONPath 实现模块 ├── snack4-jsonschema/ # JSONSchema 模块 ├── snack4-test/ # 测试模块 └── snack4-test17/ # Java 17 专用测试核心模块详解1. snack4核心库主要类类职责ONode统一节点类型作为所有 JSON 值的入口类DataType数据类型枚举Feature配置特性开关枚举Options序列化/反序列化配置JsonReaderJSON 解析器JsonWriterJSON 序列化器CodecLib编解码器注册表目录结构snack4/src/main/java/org/noear/snack4/ ├── ONode.java # 入口类 ├── DataType.java # 数据类型 ├── Feature.java # 配置特性 ├── Options.java # 配置选项 ├── annotation/ # 注解自定义序列化 ├── codec/ # 编解码系统 │ ├── CodecLib.java # 编解码注册表 │ ├── BeanEncoder.java # Bean 编码器 │ ├── BeanDecoder.java # Bean 解码器 │ ├── decode/ # 解码器实现 │ ├── encode/ # 编码器实现 │ └── create/ # 对象创建实现 ├── json/ # JSON 解析/写入 └── jsonpath/ # JSONPath 集成2. snack4-jsonpathJSONPath 实现目录结构snack4-jsonpath/ ├── JsonPath.java # 主查询引擎 ├── JsonPathParser.java # 路径表达式解析器 ├── JsonPathProviderImpl.java # SPI 实现 ├── JsonPathException.java # 异常类 ├── QueryResult.java # 查询结果 ├── QueryContext.java # 查询上下文接口 ├── QueryContextImpl.java # 查询上下文实现 ├── QueryMode.java # 查询模式枚举 ├── FunctionLib.java # 函数库可扩展 ├── Function.java # 函数接口 ├── FunctionHolder.java # 函数持有器 ├── OperatorLib.java # 操作符库可扩展 ├── Operator.java # 操作符接口 ├── selector/ # 节点选择器 │ ├── Selector.java # 选择器接口 │ ├── NameSelector.java # 按名称 │ ├── IndexSelector.java # 按索引 │ ├── WildcardSelector.java # 通配符 │ ├── SliceSelector.java # 切片 [0:3] │ ├── FilterSelector.java # 过滤器 │ └── QuerySelector.java # 查询选择 ├── segment/ # 路径段 │ ├── Segment.java # 段接口 │ ├── AbstractSegment.java # 抽象基类 │ ├── SelectSegment.java # 基本选择 │ ├── DescendantSegment.java # 递归后代 .. │ └── FuncSegment.java # 函数段 ├── filter/ # 过滤器表达式 │ ├── Expression.java # 表达式RPN 算法 │ ├── Term.java # 词项 │ ├── Operand.java # 操作数 │ └── Token.java # 词法标记 ├── operator/ # 比较操作符 │ ├── Operator.java # 操作符接口 │ ├── CompareOperator.java # 比较运算 │ ├── MatchesOperator.java # 正则匹配 │ ├── InOperator.java # in │ ├── NinOperator.java # nin │ ├── ContainsOperator.java # 包含 │ ├── StartsWithOperator.java # 开头匹配 │ ├── EndsWithOperator.java # 结尾匹配 │ ├── EmptyOperator.java # 空检查 │ ├── SizeOperator.java # 大小检查 │ └── ... ├── function/ # 内置函数 │ ├── LengthFunction.java # length / size │ ├── CountFunction.java # count │ ├── MinFunction.java # min │ ├── MaxFunction.java # max │ ├── AvgFunction.java # avg │ ├── SumFunction.java # sum │ ├── StddevFunction.java # stddev │ ├── FirstFunction.java # first │ ├── LastFunction.java # last │ ├── KeysFunction.java # keys │ ├── MatchFunction.java # match (RFC) │ ├── SearchFunction.java # search (RFC) │ └── ... └── util/ # 工具类 ├── TokenizeUtil.java # 词法分析 ├── IndexUtil.java # 索引计算 ├── RangeUtil.java # 范围计算 ├── RegexUtil.java # 正则匹配 └── ...路径段 (Segment)类型说明SelectSegment基本选择.key或[0]DescendantSegment递归后代..FuncSegment函数调用段.length()选择器 (Selector)类型语法示例说明NameSelector$.store.book按属性名选择IndexSelector$[0]按索引选择数组元素WildcardSelector$.*或[*]通配符选择SliceSelector$[1:3]切片选择FilterSelector[?(.price10)]过滤器表达式QuerySelector[?(..price10)]嵌套查询内置函数函数说明支持模式length()/size()集合长度IETF RFC / Jaywaycount()计数IETF RFCmin()/max()最小/最大值Jaywayavg()/sum()/stddev()统计函数Jaywaykeys()获取所有键Jaywayfirst()/last()首/末元素Jaywayindex()当前索引Jaywaymatch(regex)正则匹配IETF RFCsearch(regex)正则搜索IETF RFCvalue()获取值IETF RFC内置操作符分类操作符说明比较//!////基本比较正则~正则匹配集合in/nin包含/不包含子集subsetof子集判断逻辑anyof/noneof任意/无匹配大小size集合大小比较空值empty空值检查字符串contains/startsWith/endsWith字符串操作查询模式模式说明SELECT查询匹配节点默认CREATE创建路径不存在时创建DELETE删除匹配节点3. snack4-jsonschemaJSONSchemasnack4-jsonschema/ ├── JsonSchema.java # 主类 ├── JsonSchemaException.java # 异常类 ├── SchemaVersion.java # 版本枚举DRAFT_7/2019-09/2020-12 ├── SchemaKeyword.java # 关键字常量接口 ├── SchemaType.java # 类型枚举 ├── SchemaFormat.java # 格式常量 ├── generate/ # Schema 生成 │ ├── JsonSchemaGenerator.java # 生成器 │ ├── MapperLib.java # 映射注册表 │ ├── SchemaMapper.java # 架构映射接口 │ ├── SchemaPatternMapper.java # 模式映射接口 │ ├── TypeMapper.java # 类型映射接口 │ └── TypePatternMapper.java # 类型模式映射接口 └── validate/ # Schema 校验 ├── JsonSchemaValidator.java # 校验器 ├── PathTracker.java # 路径跟踪器 ├── CompiledRule.java # 编译后规则 └── impl/ # 校验规则实现 ├── TypeRule.java # 类型规则 ├── RequiredRule.java # 必填规则 ├── EnumRule.java # 枚举规则 ├── StringConstraintRule.java # 字符串约束 ├── NumericConstraintRule.java # 数值约束 ├── ArrayConstraintRule.java # 数组约束 ├── AdditionalPropertiesRule.java └── PropertyNamesRule.java校验规则实现规则类校验内容TypeRule类型匹配RequiredRule必填字段EnumRule枚举值StringConstraintRuleminLength, maxLength, patternNumericConstraintRuleminimum, maximum, exclusiveMin/MaxArrayConstraintRuleminItems, maxItemsAdditionalPropertiesRule额外属性控制PropertyNamesRule属性名约束架构图┌─────────────────────────────────────────────────────────────┐ │ ONode │ │ (统一入口类) │ └────────────────────────┬────────────────────────────────────┘ │ ┌────────────────────┼────────────────────┐ │ │ │ ▼ ▼ ▼ ┌────────────┐ ┌──────────────┐ ┌─────────────────┐ │ JsonReader │ │ JsonWriter │ │ JsonPathProvider │ │ (解析) │ │ (序列化) │ │ (SPI) │ └────────────┘ └──────────────┘ └────────┬─────────┘ │ ┌─────────────────────────┼─────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ JsonPathParser │ │ JsonPath │ │ FunctionLib │ │ (词法解析) │ │ (查询引擎) │ │ (内置函数) │ │ │ │ │ │ │ │ TokenizeUtil │ │ QueryContext │ │ min/max/avg │ │ ↓ │ │ QueryResult │ │ length/count │ │ ListToken │ │ QueryMode │ │ match/search │ │ ↓ │ │ │ │ ... │ │ RPN 转换 │ │ select() │ └────────────────┘ └───────┬────────┘ │ create() │ │ │ delete() │ ▼ └────────┬─────────┘ ┌────────────────┐ │ │ Expression │ │ │ (过滤器表达式) │ │ │ │ │ │ RPN 算法求值 │◀────────────────┤ │ ↑ │ │ │ OperatorLib │ │ └───────┬────────┘ │ │ │ ▼ ▼ ┌─────────────────────────────┬──────────────────────────────┐ │ Segment │ Selector │ │ (路径段) │ (节点选择器) │ │ │ │ │ SelectSegment ──────────► │ NameSelector ──── 属性名 │ │ DescendantSegment ──────► │ IndexSelector ─── 数组索引 │ │ FuncSegment ────────────► │ WildcardSelector ── 通配符 │ │ │ SliceSelector ───── 切片 │ │ │ FilterSelector ──── 过滤 │ │ │ QuerySelector ───── 查询 │ └─────────────────────────────┴──────────────────────────────┘核心数据结构DataType 枚举enum DataType { Undefined, // 未初始化 Null, // null 值 Boolean, // true/false Number, // Integer, Long, Double, BigDecimal String, // 字符串 Date, // java.util.Date Array, // ListONode Object // MapString, ONode }JSONPath 查询执行流程1. 解析阶段: JsonPath.parse(path) ├── 词法分析: TokenizeUtil.tokenize() │ └── 字符串 → ListToken │ ├── 语法解析: JsonPathParser.parse() │ └── ListToken → ListSegment │ └── 缓存: ConcurrentHashMap 存储已解析路径 2. 执行阶段: JsonPath.select(root) │ ├── QueryContextImpl 初始化 │ └── 设置 QueryMode.SELECT │ ├── 遍历 Segments: │ └── for each Segment: │ ├── SelectSegment.resolve(ctx, currentNodes) │ │ └── 调用 Selector 选择节点 │ ├── DescendantSegment.resolve() │ │ └── 递归遍历所有后代 │ └── FuncSegment.resolve() │ └── 调用 FunctionLib 执行函数 │ └── Selector 选择: ├── NameSelector → 按属性名匹配 ├── IndexSelector → 按数组索引 ├── WildcardSelector → [*] 通配 ├── SliceSelector → [1:3] 切片 ├── FilterSelector → [?()] 过滤 │ └── Expression.test() 使用 RPN 求值 │ └── OperatorLib 调用操作符 └── QuerySelector → 嵌套查询 3. 结果阶段 └── QueryResult 包装节点列表 ├── getNodeList() → ListONode ├── asNode() → 第一个节点 └── asString/asInt/asDouble → 类型转换关键算法算法实现说明词法分析TokenizeUtil路径表达式 → Token 序列RPN 求值Expression过滤器表达式逆波兰求值递归遍历DescendantSegment..递归后代节点路径缓存ConcurrentHashMap解析结果缓存复用操作符分发OperatorLib根据符号查找操作符执行JSONSchema 校验执行流程1. 编译阶段: JsonSchemaValidator 初始化 └── Schema 解析 → MapPath, CompiledRule └── 规则预编译类型、约束、条件allOf 合并 2. 校验阶段: validator.validate(data) └── PathTracker 跟踪当前路径 └── 按路径匹配 CompiledRule 执行校验 └── 递归处理 properties / items └── 处理条件 anyOf / oneOf 3. 异常阶段 └── 校验失败 → 抛出 JsonSchemaException └── 包含路径和错误信息Schema 生成流程1. 入口: schema.generate(Type) └── JsonSchemaGenerator 构造 2. 生成阶段: doGenerate() └── 循环引用检测visited 缓存 └── 根据类型分发处理 ├── Bean → 生成 properties/required ├── Array → 生成 items ├── Collection → 生成 items支持泛型 └── Map → 生成 additionalProperties 3. 定义处理可选 └── enableDefinitionstrue 时生成 $defs/definitions └── 支持循环引用 $ref公开 APIONode 主入口// 创建 ONode.ofJson(String json) // 解析 JSON 字符串 ONode.ofBean(Object bean) // 转换 Java Bean ONode.ofJson(Reader reader) // 从流解析 // DOM 操作 oNode.set(key, value) // 设置属性 oNode.add(value) // 添加数组元素 oNode.get(key) // 获取子节点 oNode.get(0) // 获取数组元素 // JSONPath 查询 oNode.select($.store.book[0]) // 查询节点 oNode.exists($.store.book) // 检查存在 oNode.create($.new.path) // 创建路径 oNode.delete($.old.path) // 删除节点 // 序列化 oNode.toJson() // 转 JSON 字符串 oNode.toBean(ClassT) // 转 Java Bean oNode.toBean(TypeRefT) // 带泛型转换JsonPath 直接访问// 解析路径支持缓存 JsonPath path JsonPath.parse($.store.book[*].author); // 查询 ONode result path.select(rootNode); // 在 ONode 上查询 ONode result JsonPath.select(json, $.path); // 静态查询 ONode result JsonPath.select(rootNode, $.path); // 检查存在 boolean exists JsonPath.exists(rootNode, $.store); // 创建路径不存在时创建 ONode created JsonPath.create(rootNode, $.new.path); // 删除节点 boolean deleted JsonPath.delete(rootNode, $.old.path); // 查询结果处理 QueryResult qr path.select(rootNode); qr.getNodeList(); // 获取所有匹配节点 qr.asNode(); // 获取第一个匹配节点 qr.asString(); // 作为字符串 qr.asInt(); // 作为整数 qr.asDouble(); // 作为浮点数路径语法示例语法说明$根节点当前节点过滤器内.name子属性[name]子属性带引号[0]数组索引[*]数组通配符[1:3]数组切片[?(.price10)]过滤器表达式..name递归后代.length()函数调用过滤器表达式// 基本比较 [?(.age 18)] [?(.name ! test)] [?(.price 100)] // 正则匹配 [?(.email ~ /^.*.*\.com$/)] // 集合操作 [?(.status in [active,pending])] [?(.role nin [admin])] // 字符串操作 [?(.name contains john)] [?(.url startsWith https)] [?(.ext endsWith .json)] // 逻辑组合 [?(.age 18 .active true)] [?(.vip true || .balance 1000)] // 嵌套路径 [?(.address.city Beijing)] [?(..price 100)] // 递归搜索JSONSchema// 创建 Schema 实例支持 Builder 模式 JsonSchema schema JsonSchema.builder() .version(SchemaVersion.DRAFT_7) // 草案版本 .enableDefinitions(true) // 启用定义规范 .printVersion(true) // 打印 $schema .build(); // 添加自定义映射 schema.addSchemaMapper(User.class, new CustomSchemaMapper()); schema.addTypeMapper(new CustomTypePatternMapper()); // 生成 Schema ONode schemaNode schema.generate(User.class); String schemaJson schemaNode.toJson(); // 校验数据 JsonSchemaValidator validator schema.createValidator(User.class); validator.validate(dataNode); // 抛出 JsonSchemaException 则校验失败 // 也可直接用 JSON 字符串创建校验器 JsonSchemaValidator validator2 JsonSchema.builder() .createValidator({\type\:\object\});核心功能功能说明Schema 生成从 Java Type 生成 JSON SchemaSchema 校验校验 ONode 数据是否符合 Schema版本支持DRAFT_7, DRAFT_2019_09, DRAFT_2020_12条件校验支持 allOf, anyOf, oneOf$ref 引用支持内部定义引用循环引用自动检测并处理自定义映射支持 SchemaMapper/TypeMapper 扩展SchemaKeyword 关键字分类关键字元数据$schema,title,description,default,examples类型type,enum,format,readOnly,writeOnly对象properties,required,additionalProperties,patternProperties,propertyNames字符串minLength,maxLength,pattern数值minimum,maximum,exclusiveMinimum,exclusiveMaximum数组items,minItems,maxItems引用$ref,$defs,definitions,$anchor,$comment条件allOf,anyOf,oneOf配置Options 配置选项// 创建配置实例 Options opts Options.of( Feature.Write_PrettyFormat, // 漂亮格式输出 Feature.Write_UseSmlSnakeStyle // 字段名下划线风格 ); // 或者链式配置 Options opts new Options(false) .dateFormat(yyyy-MM-dd) // 日期格式 .writeIndent( ) // 缩进 .addFeatures(Feature.Write_PrettyFormat) .addEncoder(MyClass.class, new MyEncoder()) .mapFactory(LinkedHashMap::new) .listFactory(ArrayList::new);常用特性 (Feature)特性说明Read_AutoType读取时支持 type 自动类型Read_UseBigDecimalMode大数字模式避免精度丢失Write_PrettyFormat漂亮格式带缩进Write_UseSmlSnakeStyle字段名下划线风格Write_UseSmlCamelStyle字段名驼峰风格Write_EnumUsingName枚举使用名称Write_DateFormat日期格式化输出JsonPath_IETF_RFC_9535IETF RFC 9535 兼容模式依赖关系snack4-parent (父 POM) ├── snack4 (核心) │ └── 依赖: eggg, slf4j-api ├── snack4-jsonpath │ └── 依赖: snack4 ├── snack4-jsonschema │ └── 依赖: snack4, slf4j-api