Java 开发人员经常羡慕 JavaScript 解析 JSON 的简便性。尽管 Java 提供了更多的健壮性,但它往往涉及更多的工作和样板代码。多亏了 Manifold 项目,Java 现在有可能在解析和处理 JSON 文件方面超越 JavaScript。
Manifold 是一组革命性的 Java 语言扩展,它完全改变了我们处理 JSON(以及更多……)的方式。
本教程的代码可以在我的GitHub 页面上找到。 Manifold 相对年轻,但其功能已经非常强大。您可以在他们的网站和 Slack 频道上了解有关该项目的更多信息。
首先,您需要安装 Manifold 插件,该插件目前仅适用于 JetBrains IDE。该项目支持 Java 的 LTS 版本,包括最新的 JDK 19。
我们可以通过导航到市场并搜索 Manifold 从 IntelliJ/IDEAs 设置 UI 安装插件。该插件确保 IDE 不会与 Maven/Gradle 插件完成的工作发生冲突。
Manifold 由多个较小的项目组成,每个项目都提供自定义语言扩展。今天,我们将讨论一个这样的扩展,但还有更多内容需要探索。
为了演示 Manifold,我们将使用一个简单的 Maven 项目(它也适用于 Gradle)。我们首先需要从他们的网站粘贴当前的 Manifold 版本并添加必要的依赖项。 JSON 的主要依赖项是manifold-json-rt
依赖项。
可以添加其他依赖项以支持 YAML、XML 和 CSV。我们需要将它添加到项目中的pom.xml
文件中。
我知道具有讽刺意味的是,JSON 的样板文件减少始于 Maven 构建脚本中的大量配置。但这是配置,而不是“实际代码”;它主要是复制和粘贴。
请注意,如果您想减少此代码,Gradle 等效代码相比之下更简洁。
此行需要进入属性部分:
<manifold.version>2023.1.5</manifold.version>
我们使用的依赖项是:
<dependencies> <dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-json-rt</artifactId> <version>${manifold.version}</version> </dependency>
编译插件是将 Manifold 编织到字节码中并使我们无缝衔接的样板。这是 pom 设置的最后一部分:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>19</source> <target>19</target> <encoding>UTF-8</encoding> <compilerArgs> <!-- Configure manifold plugin--> <arg>-Xplugin:Manifold</arg> </compilerArgs> <!-- Add the processor path for the plugin --> <annotationProcessorPaths> <path> <groupId>systems.manifold</groupId> <artifactId>manifold-json</artifactId> <version>${manifold.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
设置完成后,让我们深入研究代码。
我们将示例 JSON 文件放在资源层次结构下的项目目录中。我把这个文件放在src/main/resources/com/debugagent/json/Test.json
下:
{ "firstName": "Shai", "surname": "Almog", "website": "https://debugagent.com/", "active": true, "details":[ {"key": "value"} ] }
在主类中,我们刷新 Maven 项目,您会注意到出现了一个新的 Test 类。这个类是Manifold根据JSON文件动态创建的。如果您更改 JSON 并刷新 Maven,一切都会无缝更新。
重要的是要了解 Manifold 不是代码生成器。它将我们刚刚写入的 JSON 编译成字节码。
Test 类带有几个内置功能,例如类型安全的构建器 API,它允许您使用构建器方法构建 JSON 对象。您还可以使用write()
和toJson()
方法生成嵌套对象并将 JSON 转换为字符串。
这意味着我们现在可以写:
Test test = Test.builder().withFirstName("Someone") .withSurname("Surname") .withActive(true) .withDetails(List.of( Test.details.detailsItem.builder(). withKey("Value 1").build() )) .build();
这将打印出以下 JSON:
{ "firstName": "Someone", "surname": "Surname", "active": true, "details": [ { "key": "Value 1" } ] }
我们可以类似地使用如下代码读取 JSON 文件:
Test readObject = Test.load().fromJson(""" { "firstName": "Someone", "surname": "Surname", "active": true, "details": [ { "key": "Value 1" } ] } """);
请注意使用 Java 15 TextBlock
语法编写长字符串。 load()
方法返回一个对象,其中包含用于读取 JSON 的各种 API。在这种情况下,它是从一个String
中读取的,但是有一些 API 可以从 URL、文件等中读取它。
Manifold 支持各种格式,包括 CSV、XML 和 YAML,允许您生成和解析这些格式中的任何一种,而无需编写任何样板代码或牺牲类型安全性。为了添加该支持,我们需要向 pom.xml 文件添加额外的依赖项:
<dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-csv-rt</artifactId> <version>${manifold.version}</version> </dependency> <dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-xml-rt</artifactId> <version>${manifold.version}</version> </dependency> <dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-yaml-rt</artifactId> <version>${manifold.version}</version> </dependency> </dependencies>
使用这些额外的依赖项,此代码将打印出与 JSON 文件相同的数据......使用test.write().toCsv()
输出将是:
"firstName","surname","active","details" "Someone","Surname","true","[manifold.json.rt.api.DataBindings@71070b9c]"
请注意,逗号分隔值 (CSV) 输出不包含层次结构信息。这是 CSV 格式的限制,而不是 Manifold 的错误。
使用test.write().toXml()
时,输出很熟悉而且非常简洁:
<root_object firstName="Someone" surname="Surname" active="true"> <details key="Value 1"/> </root_object>
使用test.write().toYaml()
我们再次得到熟悉的打印输出:
firstName: Someone surname: Surname active: true details: - key: Value 1
Manifold 还可以与 JSON 模式无缝协作,允许您执行严格的规则和约束。这在处理日期和枚举时特别有用。
Manifold 无缝地创建/更新符合模式的字节码,使得处理复杂的 JSON 数据变得更加容易。
此架构是从Manifold GitHub 项目复制并粘贴的:
{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "http://example.com/schemas/User.json", "type": "object", "definitions": { "Gender": { "type": "string", "enum": ["male", "female"] } }, "properties": { "name": { "type": "string", "description": "User's full name.", "maxLength": 80 }, "email": { "description": "User's email.", "type": "string", "format": "email" }, "date_of_birth": { "type": "string", "description": "Date of uses birth in the one and only date standard: ISO 8601.", "format": "date" }, "gender": { "$ref" : "#/definitions/Gender" } }, "required": ["name", "email"] }
这是一个相对简单的架构,但我想在这里将您的注意力转移到几件事上。它根据需要定义名称和电子邮件。这就是为什么当我们尝试在 Manifold 中使用构建器创建User
对象时, build()
方法需要两个参数:
User.builder("Name", "[email protected]")
那只是开始……该架构包括一个日期。日期在 JSON 中是一个痛苦的前景,标准化很差并且充满了问题。该模式还包括一个实际上是枚举的性别字段。
使用 LocalDate 等常见的 Java 类,这一切都被转换为类型安全的语义:
User u = User.builder("Name", "[email protected]") .withDate_of_birth(LocalDate.of(1999, 10, 11)) .withGender(User.Gender.male) .build();
这可以通过静态导入变得更短,但这个想法的要点很清楚。 JSON 在 Manifold 中是 Java 的有效原生。
Manifold 是一个强大而令人兴奋的项目。它彻底改变了 Java 中的 JSON 解析,但这只是它能做的一小部分!
在这篇文章中,我们只触及了其功能的表面。在下一篇文章中,我们将更深入地研究 Manifold 并探索一些额外的意想不到的功能。
请在评论部分分享您对 Manifold 的体验和想法。如果您有任何问题,请随时提出。