Cómo generar clases Java a partir de un JSON de ejemplo

Pega un JSON de ejemplo —una respuesta de API, un archivo de configuración o el cuerpo de un webhook— y esta página escribe las clases Java correspondientes: una clase por archivo, con campos privados y sus métodos get y set. Define el nombre de la clase raíz y el paquete, pulsa Generar JavaBean y descarga todos los archivos en un ZIP o copia el código desde la página. La conversión se ejecuta en el navegador, el contenido no se sube a ningún servidor y la página sigue funcionando sin conexión una vez cargada.

Dos detalles de la salida son intencionados. Cada nombre de campo es un identificador válido de Java, y toda propiedad que haya tenido que renombrarse conserva su nombre JSON original en una anotación Jackson @JsonProperty, de modo que la clase generada sigue mapeando el payload del que salió. El resto —tipos, nombres de clase y anidamiento— se deduce de la muestra que pegaste, así que el resultado es un borrador para revisar y no un modelo terminado.

  1. Pega el JSON en el campo superior. Las clases se regeneran con cada pulsación, así que verás cambiar el modelo mientras editas la muestra.
  2. Ajusta Clase y Paquete si los valores por defecto no encajan: Clase es el nombre de la clase raíz (RootBean) y Paquete es la línea package de cada archivo (com.example.model). Ambos se corrigen automáticamente cuando no son Java válido.
  3. Pulsa Generar JavaBean. Cada clase aparece en su propio bloque con la etiqueta Nombre de clase; el primer bloque es la clase raíz y los siguientes son las clases a las que hace referencia.
  4. Pulsa Descargar código Java para obtener un ZIP llamado kivtools-java-models.zip que reproduce las carpetas del paquete y contiene un archivo .java por clase, o Limpiar entrada para vaciar el campo y el resultado.

Cómo se convierten valores, nombres y arrays a Java

Qué tipo Java recibe cada valor JSON

El texto se convierte en String y true o false en boolean. Los enteros que caben en 32 bits pasan a int; los enteros mayores pasan a long, y los que quedan fuera del rango que JavaScript representa con exactitud pasan a BigDecimal para que nada se redondee en silencio. Los números con decimales pasan a double y null pasa a String, porque un null aislado no aporta información de tipo.

Una cadena con aspecto de fecha pasa a java.util.Date: 2024-05-06, 2024/05/06, 12/31/2024, May 6, 2024 y las marcas de tiempo ISO 8601 con zona horaria opcional entran en esta categoría. Los dígitos solos no: 20240506, 2024 y "1-2" siguen siendo String, de modo que un id, un año o un número de versión no se convierten en fecha por error.

De nombre JSON a nombre Java

Un nombre de propiedad que ya es un identificador válido se conserva tal cual, incluidas sus mayúsculas. El resto se convierte a camelCase separando por los caracteres que Java no admite: user_name pasa a userName, a.b a aB y user name a userName. Si el nombre es una palabra reservada de Java o empieza por dígito, se le antepone un guion bajo, así que {"class": 1} produce el campo _class.

Los nombres de clase siguen las mismas reglas y empiezan en mayúscula. Hay dos protecciones adicionales. Una clase no puede llamarse como un tipo que el propio archivo usa, por lo que una propiedad llamada list genera ListModel en lugar de ocultar java.util.List; y dos objetos no pueden reclamar el mismo nombre de clase —el segundo se cualifica con su padre, de modo que wrap.data pasa a WrapData mientras el data exterior sigue siendo Data—. Dentro de un mismo objeto, user_name y userName chocan y el segundo campo pasa a llamarse userName2. La anotación se importa desde com.fasterxml.jackson.annotation.JsonProperty, el paquete de Jackson 2.

Objetos, arrays y modelos anidados

Un objeto anidado se convierte en una clase propia, con el nombre de la propiedad que lo contiene, y el campo apunta a esa clase. Los arrays pasan a List<...>: un array de cadenas es List<String>, un array de objetos es List<Users> más la clase Users, y un array anidado conserva su profundidad, así que [[1,2]] es List<List<Integer>>. Los argumentos de tipo siempre van con envoltorio —List<Integer> y nunca List<int>— porque Java no admite primitivos ahí.

En un array de objetos se leen todos los elementos, no solo el primero: un campo que aparezca en algunos elementos también se añade, los arrays de esos objetos se combinan y una propiedad con tipos distintos en elementos distintos pasa a Object. Un array vacío no aporta ningún tipo de elemento, así que su elemento se tipa como String a modo de marcador. Un array en el nivel superior recibe el mismo tratamiento: la clase raíz se construye con las propiedades de todos sus elementos.

Qué son los archivos generados y qué no son

Cada archivo contiene la línea package, los imports que realmente usa, una cabecera Javadoc breve con la hora de generación y la dirección de esta página, una clase pública y campos privados con su get y su set. No hay Lombok, ni builder, ni equals ni hashCode: la salida es un JavaBean sencillo que solo necesita el JDK y, cuando algún campo se renombró, las anotaciones de Jackson en el classpath.

Aquí no se compila nada ni se contrasta con tu proyecto, y los tipos proceden de una única muestra. Los campos opcionales, los null anidados o un valor que cambia de tipo entre llamadas no pueden aparecer en esa muestra, y un número que hoy es int se convierte en un campo primitivo que quizá tengas que envolver después. Unos cientos de kilobytes se convierten en el navegador en bastante menos de un segundo, así que una respuesta grande no es problema, pero la muestra es una instantánea, no un esquema.

Herramientas recientes: