Los desarrolladores de Java a menudo han envidiado a JavaScript por su facilidad para analizar JSON. Aunque Java ofrece más solidez, tiende a implicar más trabajo y código repetitivo. Gracias al proyecto Manifold, Java ahora tiene el potencial de eclipsar a JavaScript en el análisis y procesamiento de archivos JSON.
Manifold es un conjunto revolucionario de extensiones de lenguaje para Java que cambia por completo la forma en que manejamos JSON (y mucho más...).
El código de este tutorial se puede encontrar en mi página de GitHub . Manifold es relativamente joven pero ya tiene muchas capacidades. Puede obtener más información sobre el proyecto en su sitio web y en el canal de Slack.
Para comenzar, deberá instalar el complemento Manifold, que actualmente solo está disponible para los IDE de JetBrains. El proyecto es compatible con las versiones LTS de Java, incluido el último JDK 19.
Podemos instalar el complemento desde la interfaz de usuario de configuración de IntelliJ/IDEA navegando al mercado y buscando Manifold. El complemento se asegura de que el IDE no colisione con el trabajo realizado por el complemento Maven/Gradle.
Manifold consta de varios proyectos más pequeños, cada uno de los cuales ofrece una extensión de idioma personalizada. Hoy hablaremos de una de esas extensiones, pero hay mucho más por explorar.
Para demostrar Manifold, usaremos un proyecto Maven simple (también funciona con Gradle). Primero debemos pegar la versión actual de Manifold desde su sitio web y agregar las dependencias necesarias. La dependencia principal para JSON es la dependencia manifold-json-rt
.
Se pueden agregar otras dependencias para la compatibilidad con YAML, XML y CSV. Necesitamos agregar esto al archivo pom.xml
en el proyecto.
Soy consciente de la ironía en la que la reducción repetitiva para JSON comienza con una gran cantidad de configuración en el script de compilación de Maven. Pero esto es configuración, no "código real"; es principalmente copiar y pegar.
Tenga en cuenta que si desea reducir este código, el código equivalente de Gradle es breve en comparación.
Esta línea debe ir a la sección de propiedades:
<manifold.version>2023.1.5</manifold.version>
Las dependencias que utilizamos son estas:
<dependencies> <dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-json-rt</artifactId> <version>${manifold.version}</version> </dependency>
El complemento de compilación es el modelo que teje Manifold en el código de bytes y lo hace perfecto para nosotros. Es la última parte de la configuración del 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>
Con la configuración completa, profundicemos en el código.
Colocamos un archivo JSON de muestra en el directorio del proyecto bajo la jerarquía de recursos. Coloqué este archivo en src/main/resources/com/debugagent/json/Test.json
:
{ "firstName": "Shai", "surname": "Almog", "website": "https://debugagent.com/", "active": true, "details":[ {"key": "value"} ] }
En la clase principal, actualizamos el proyecto Maven y notará que aparece una nueva clase de prueba. Manifold crea dinámicamente esta clase en función del archivo JSON. Si cambia el JSON y actualiza Maven, todo se actualiza sin problemas.
Es importante comprender que Manifold no es un generador de código. Compila el JSON que acabamos de escribir en bytecode.
La clase Test viene con varias capacidades integradas, como una API de compilación con seguridad de tipos que le permite construir objetos JSON mediante métodos de compilación. También puede generar objetos anidados y convertir el JSON en una cadena mediante los métodos write()
y toJson()
.
Significa que ahora podemos escribir:
Test test = Test.builder().withFirstName("Someone") .withSurname("Surname") .withActive(true) .withDetails(List.of( Test.details.detailsItem.builder(). withKey("Value 1").build() )) .build();
Que imprimirá el siguiente JSON:
{ "firstName": "Someone", "surname": "Surname", "active": true, "details": [ { "key": "Value 1" } ] }
De manera similar, podemos leer un archivo JSON usando un código como este:
Test readObject = Test.load().fromJson(""" { "firstName": "Someone", "surname": "Surname", "active": true, "details": [ { "key": "Value 1" } ] } """);
Tenga en cuenta el uso de la sintaxis de Java 15 TextBlock
para escribir una cadena larga. El método load()
devuelve un objeto que incluye varias API para leer el JSON. En este caso se lee desde un String
pero existen APIs para leerlo desde una URL, archivo, etc.
Manifold admite varios formatos, incluidos CSV, XML y YAML, lo que le permite generar y analizar cualquiera de estos formatos sin escribir ningún código repetitivo ni sacrificar la seguridad de los tipos. Para agregar ese soporte, necesitaremos agregar dependencias adicionales al archivo 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>
Con estas dependencias adicionales, este código imprimirá los mismos datos que el archivo JSON... Con test.write().toCsv()
el resultado sería:
"firstName","surname","active","details" "Someone","Surname","true","[manifold.json.rt.api.DataBindings@71070b9c]"
Tenga en cuenta que la salida de valores separados por comas (CSV) no incluye información de jerarquía. Esa es una limitación del formato CSV y no es culpa de Manifold.
Con test.write().toXml()
el resultado es familiar y sorprendentemente conciso:
<root_object firstName="Someone" surname="Surname" active="true"> <details key="Value 1"/> </root_object>
Con test.write().toYaml()
nuevamente obtenemos una impresión familiar:
firstName: Someone surname: Surname active: true details: - key: Value 1
Manifold también funciona a la perfección con el esquema JSON, lo que le permite aplicar reglas y restricciones estrictas. Esto es particularmente útil cuando se trabaja con fechas y enumeraciones.
Manifold crea/actualiza sin problemas el código de bytes que se adhiere al esquema, lo que facilita mucho el trabajo con datos JSON complejos.
Este esquema se copia y pega desde el proyecto 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"] }
Es un esquema relativamente simple, pero me gustaría llamar su atención sobre varias cosas aquí. Define nombre y correo electrónico según sea necesario. Es por eso que cuando intentamos crear un objeto User
usando un constructor en Manifold, el método build()
requiere ambos parámetros:
User.builder("Name", "[email protected]")
Eso es solo el comienzo... El esquema incluye una fecha. Las fechas son una perspectiva dolorosa en JSON, la estandarización es deficiente y está llena de problemas. El esquema también incluye un campo de género que es efectivamente una enumeración.
Todo esto se convierte en semántica de seguridad de tipos utilizando clases comunes de Java como LocalDate:
User u = User.builder("Name", "[email protected]") .withDate_of_birth(LocalDate.of(1999, 10, 11)) .withGender(User.Gender.male) .build();
Eso se puede acortar aún más con importaciones estáticas, pero la esencia de la idea es clara. JSON es efectivamente nativo de Java en Manifold.
Manifold es un proyecto poderoso y emocionante. Revoluciona el análisis de JSON en Java, ¡pero eso es solo una pequeña parte de lo que puede hacer!
Solo hemos arañado la superficie de sus capacidades en esta publicación. En el próximo artículo, profundizaremos en Manifold y exploraremos algunas características inesperadas adicionales.
Comparta su experiencia y pensamientos sobre Manifold en la sección de comentarios. Si tiene alguna pregunta, no dude en preguntar.