Jakarta JSON Processing (JSON-P) en Quarkus: Manipulación Programática de JSON
Introducción
Jakarta JSON Processing (JSON-P) proporciona APIs para crear, parsear, transformar y consultar JSON de forma programática. A diferencia de JSON-Binding, JSON-P te da control total sobre la estructura JSON.
¿Qué es JSON-Processing?
JSON-P ofrece dos APIs principales:
Object Model API: Para manipular JSON como objetos (JsonObject, JsonArray)
Streaming API: Para procesar JSON grande de forma eficiente (JsonParser, JsonGenerator)
Object Model API
Crear JsonObject
JsonObjectBuilder builder = Json.createObjectBuilder();
builder.add("name", "Superman")
.add("powerLevel", 95)
.add("isActive", true);
// Objeto anidado
JsonObjectBuilder locationBuilder = Json.createObjectBuilder();
locationBuilder.add("city", "Metropolis");
builder.add("location", locationBuilder);
// Array
JsonArrayBuilder abilitiesBuilder = Json.createArrayBuilder();
abilitiesBuilder.add("Super strength").add("Flight");
builder.add("abilities", abilitiesBuilder);
JsonObject hero = builder.build();
Crear JsonArray
JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
JsonObjectBuilder hero1 = Json.createObjectBuilder();
hero1.add("name", "Superman").add("powerLevel", 95);
arrayBuilder.add(hero1);
JsonObjectBuilder hero2 = Json.createObjectBuilder();
hero2.add("name", "Batman").add("powerLevel", 85);
arrayBuilder.add(hero2);
JsonArray heroes = arrayBuilder.build();
Parsear JSON
String jsonString = "{\"name\":\"Superman\",\"powerLevel\":95}";
JsonReader reader = Json.createReader(new StringReader(jsonString));
JsonObject jsonObject = reader.readObject();
reader.close();
Escribir con Formato
Map<String, Object> config = Map.of(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory factory = Json.createWriterFactory(config);
StringWriter writer = new StringWriter();
JsonWriter jsonWriter = factory.createWriter(writer);
jsonWriter.writeObject(jsonObject);
jsonWriter.close();
String formattedJson = writer.toString();
JsonPointer (RFC 6901) - Querying JSON
JsonPointer permite consultar valores específicos en JSON:
// Consultar un valor
JsonPointer pointer = Json.createPointer("/name");
JsonValue value = pointer.getValue(jsonObject);
// Agregar un valor
JsonPointer pointer = Json.createPointer("/newField");
JsonObject modified = pointer.add(jsonObject, Json.createValue("newValue"));
// Eliminar un valor
JsonPointer pointer = Json.createPointer("/fieldToRemove");
JsonObject modified = pointer.remove(jsonObject);
JsonPatch (RFC 6902) - Transformar JSON
JsonPatch permite transformar JSON usando operaciones estándar:
// Crear operaciones de patch
JsonArrayBuilder patchBuilder = Json.createArrayBuilder();
// Operación: reemplazar
JsonObjectBuilder replaceOp = Json.createObjectBuilder();
replaceOp.add("op", "replace")
.add("path", "/powerLevel")
.add("value", 98);
patchBuilder.add(replaceOp);
// Operación: agregar
JsonObjectBuilder addOp = Json.createObjectBuilder();
addOp.add("op", "add")
.add("path", "/newField")
.add("value", "newValue");
patchBuilder.add(addOp);
JsonArray patchOperations = patchBuilder.build();
// Aplicar patch
JsonPatch patch = Json.createPatch(patchOperations);
JsonObject transformed = patch.apply(original);
Streaming API
JsonParser - Parsear JSON Grande
JsonParser parser = Json.createParser(new StringReader(jsonString));
while (parser.hasNext()) {
JsonParser.Event event = parser.next();
switch (event) {
case KEY_NAME:
String key = parser.getString();
break;
case VALUE_STRING:
String value = parser.getString();
break;
case VALUE_NUMBER:
if (parser.isIntegralNumber()) {
long number = parser.getLong();
} else {
BigDecimal decimal = parser.getBigDecimal();
}
break;
// ... más eventos
}
}
parser.close();
JsonGenerator - Generar JSON Grande
Map<String, Object> config = Map.of(JsonGenerator.PRETTY_PRINTING, true);
JsonGenerator generator = Json.createGeneratorFactory(config)
.createGenerator(writer);
generator.writeStartObject()
.write("name", "Superman")
.write("powerLevel", 95)
.writeStartObject("location")
.write("city", "Metropolis")
.writeEnd()
.writeStartArray("abilities")
.write("Super strength")
.write("Flight")
.writeEnd()
.writeEnd();
generator.close();
Filtrar y Transformar
Filtrar JsonArray
JsonArrayBuilder filteredBuilder = Json.createArrayBuilder();
for (JsonValue heroValue : heroesArray) {
if (heroValue.getValueType() == JsonValue.ValueType.OBJECT) {
JsonObject hero = heroValue.asJsonObject();
int powerLevel = hero.getInt("powerLevel", 0);
if (powerLevel >= minPowerLevel) {
filteredBuilder.add(hero);
}
}
}
JsonArray filtered = filteredBuilder.build();
Comparación: JSON-Processing vs JSON-Binding
| Característica | JSON-Processing | JSON-Binding |
| Propósito | Manipulación programática | Serialización automática |
| API | JsonObject, JsonArray | Anotaciones en clases Java |
| Uso | Cuando necesitas control total | Cuando trabajas con objetos Java |
| Streaming | Sí (JsonParser/Generator) | No |
| Querying | Sí (JsonPointer) | No |
| Transformations | Sí (JsonPatch) | No |
Ejemplo Completo
Nuestro demo muestra:
Creación de JsonObject y JsonArray programáticamente
Parsing de JSON strings
Escritura con formato
JsonPointer para consultar JSON
JsonPatch para transformar JSON
Streaming API para JSON grande
Filtrado y transformación
Ventajas en Quarkus
Control Total: Manipulación completa de JSON
Streaming: Eficiente para JSON grande
Estándares: JsonPointer y JsonPatch son RFCs estándar
Flexibilidad: Útil cuando JSON-Binding no es suficiente
Conclusión
JSON-Processing es perfecto cuando necesitas manipular JSON directamente o cuando JSON-Binding no cubre tus necesidades. Las APIs de streaming son especialmente útiles para procesar JSON grande.




