Saltar al contenido
AldeaCode Logo
Formateador JSON / Java Formato 100% local

Formatear JSON en Java: Jackson, Gson y el indent por defecto de 1 espacio

Java te da tres opciones mainstream para formatear JSON: Jackson, Gson y org.json. Jackson es el estándar de facto pero su pretty printer por defecto indenta con un espacio, lo que sorprende a cualquiera la primera vez.

Jackson es el default en Java moderno

com.fasterxml.jackson.databind.ObjectMapper es la capa JSON por defecto en Spring Boot, Micronaut y Quarkus. La vía pretty es writerWithDefaultPrettyPrinter():

ObjectMapper mapper = new ObjectMapper();
String pretty = mapper.writerWithDefaultPrettyPrinter()
    .writeValueAsString(obj);

La salida es JSON válido e indentado. La primera vez que lo lees, notas que el indent es de un espacio, no dos ni cuatro. Es intencionado, está documentado, y origina un hilo de issue abierto desde hace una década. El printer por defecto trae un solo espacio porque el autor de la librería prefería una forma pretty compacta.

La mayoría de equipos quieren el indent convencional de 2 espacios. Para obtenerlo, instancia DefaultPrettyPrinter y sobreescribe el indenter:

DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(DefaultIndenter.SYSTEM_LINEFEED_INSTANCE);
DefaultIndenter indenter = new DefaultIndenter("  ", DefaultIndenter.SYS_LF);
printer.indentObjectsWith(indenter);
printer.indentArraysWith(indenter);

Dos espacios, line endings del sistema, aplicado a objetos y arrays.

Ordenar claves para salida determinista

Los diffs y los snapshot tests necesitan orden de clave estable. Jackson soporta dos sabores: a nivel de ObjectMapper vía SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, y a nivel de tipo vía @JsonPropertyOrder(alphabetic = true). El flag de feature afecta a cada Map que serialices a través de ese mapper. La anotación solo afecta a la clase anotada.

ObjectMapper mapper = new ObjectMapper()
    .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

Ojo: esto solo ordena instancias de Map. El orden de campos en POJOs sigue el orden de declaración de la clase o la anotación explícita. Si tu salida tiene los dos, te quedan los campos de la clase en orden de declaración seguidos de las entradas de mapa en orden alfabético. Fuentes mezcladas en el mismo objeto JSON pasan poco en la práctica; cuando pasa, fija el orden con @JsonPropertyOrder en la clase.

Gson es más liviana e igual de común

Gson de Google es la segunda librería más usada, más pequeña, y el default en muchos proyectos Android. La vía pretty pasa por GsonBuilder:

Gson gson = new GsonBuilder()
    .setPrettyPrinting()
    .serializeNulls()
    .create();
String json = gson.toJson(obj);

setPrettyPrinting() indenta con dos espacios por defecto, que es lo que la mayoría espera. Gson no tiene un toggle equivalente al de Jackson para ordenar claves alfabéticamente. Si lo necesitas, ordena el Map de entrada antes de serializar o usa TreeMap de extremo a extremo.

org.json para dependencias mínimas

org.json viene con el JDK en Android y es una dependencia por debajo del megabyte en JDK de servidor. Sin anotaciones, sin databinding, solo JSONObject y JSONArray. La forma pretty es una sobrecarga única:

JSONObject obj = new JSONObject(rawString);
String pretty = obj.toString(2); // indent de 2 espacios

Úsala cuando parseas un payload, transformas unos pocos campos y emites. No la uses para mapeo de objetos: no hay processor de anotaciones, no hay esquema, y la API te empuja a código stringly-typed.

Ejemplo completo

java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;

public class FormatJson {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper()
            .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);

        // Forzar indent de 2 espacios en objetos y arrays
        DefaultIndenter indenter =
            new DefaultIndenter("  ", DefaultIndenter.SYS_LF);
        DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
        printer.indentObjectsWith(indenter);
        printer.indentArraysWith(indenter);

        var data = java.util.Map.of(
            "user", java.util.Map.of("id", 42, "name", "Ada"),
            "tags", java.util.List.of("admin", "beta"),
            "active", true
        );

        String pretty = mapper.writer(printer).writeValueAsString(data);
        System.out.println(pretty);
    }
}

¿Solo necesitas el resultado?

Cuando necesitas leer un payload de una respuesta de curl o de una línea de log y no quieres montar un proyecto Java solo para formatearlo, pega el JSON en el formateador de aldeacode.com. La salida usa 2 espacios de indent, valida mientras escribes, y corre entera en tu navegador.

Abrir Formateador y Validador JSON →

Preguntas frecuentes

¿Por qué el indent por defecto de Jackson es de un espacio?

DefaultPrettyPrinter trae un indenter de un solo espacio porque el autor de la librería prefería una forma pretty compacta. No hay flag para cambiarlo global. Instancia un DefaultPrettyPrinter, mete un DefaultIndenter con dos espacios, y pásalo a writer(printer).

¿Jackson maneja Unicode sin escapar por defecto?

Sí. Jackson saca caracteres UTF-8 literales por defecto. Si necesitas salida solo ASCII para un transporte limitado, activa JsonGenerator.Feature.ESCAPE_NON_ASCII en el writer. El default es la opción correcta en la mayoría de sistemas modernos.

¿Jackson o Gson para código nuevo?

Jackson en JVM de servidor, sobre todo con Spring o Quarkus. Gson en Android, en scripts, y donde el tiempo de arranque pesa más que el surface de features. Ambas producen JSON válido y bonito.