Entrada (esquema .proto)

Salida (Java)

Qué hace esta herramienta

Tienes un esquema de Protocol Buffers y un servicio Java que consume esos mensajes — quizá por gRPC, quizá vía JSON sobre HTTP. Ejecutar el protoc oficial con el plugin Java te da clases generadas con patrón Builder, geniales para producción pero pesadas para esbozar, prototipar o mapear JSON a mano sobre un POJO. Este conversor emite clases Java sencillas — campos públicos, valores por defecto razonables, una clase por mensaje, tipos separados para los enums.

El mapeo de tipos sigue lo que parece Java escrito a mano en la práctica: stringString, boolboolean, int32/sint32/sfixed32int, int64/sint64/sfixed64long, doubledouble, floatfloat, bytesbyte[]. Java no tiene tipos numéricos sin signo, así que uint32/fixed32 caen a int y uint64/fixed64 caen a long — bien para la mayoría de los casos; si realmente necesitas el bit alto, usa Integer.toUnsignedLong en la frontera. repeated T se vuelve List<T>, map<K, V> se vuelve Map<K, V>, ambos de java.util.

Los nombres de campo se convierten de snake_case (convención Protobuf) a camelCase (convención Java) — coincidiendo con lo que haría protoc, y con lo que usa el mapeo JSON de proto3. Los enums se convierten en tipos public enum de nivel superior con el valor entero del cable conservado como un campo final, así puedes hacer round-trip por código generado por protoc si algún día migras. Los mensajes anidados se aplanan a clases de nivel superior para que cada uno pueda moverse a su propio archivo cuando dividas la salida. Todo se ejecuta en tu navegador — tu esquema no sale de la página.

Cómo usarla

Tres pasos. La salida está lista para soltar en un proyecto Java.

1

Pega tu esquema .proto

Suelta el esquema en el editor de la izquierda. syntax = "proto3"; arriba está bien pero es opcional. El parser maneja bloques anidados de message, declaraciones enum, oneof, map<K, V> y opciones de campo. Las directivas import se reconocen pero se saltan — pega los tipos importados inline si los necesitas.

La conversión de nombres de campo es automática: order_id en .proto se vuelve orderId en Java. Los nombres de mensajes y enums se mantienen tal cual (ya están en PascalCase).

2

Lee la salida

A la derecha: un único bloque .java con todos los enums primero, luego todas las clases en orden de declaración. Cada clase tiene campos públicos con valores por defecto para los primitivos (0, 0.0, false, ""), y los tipos referencia (List, Map, refs a mensajes) quedan en null hasta que los rellenes. Los imports java.util.List y java.util.Map se añaden solo cuando el esquema los necesita.

3

Suéltalo en tu proyecto

Copia cada clase a su propio archivo .java (Java exige una clase pública por archivo). Añade una declaración de package, luego conecta las clases a tu deserializador JSON preferido — Jackson coge campos públicos por defecto, y el mapeo JSON de proto3 usa camelCase, así que los nombres de campo ya cuadran. Si prefieres getters/setters, el refactor "Encapsulate Fields" de IntelliJ lo hace en una pulsación.

Cuándo te ahorra tiempo de verdad

Esbozar un cliente Java contra un servicio gRPC

Estás haciendo un spike de un cliente Java contra un backend gRPC existente — quizá un servicio Spring Boot, quizá uno de Quarkus — y todavía no quieres montar el plugin completo de protoc en Maven o Gradle. Pega el esquema, suelta las clases en src/main/java/dto, deserializa la respuesta JSON con Jackson, lanza el prototipo.

Crear DTOs a mano que coincidan con un proto

Tu equipo usa Protobuf como fuente de verdad en el cable, pero el servicio Java consumidor solo necesita tres o cuatro campos y no quieres una dependencia de Message/Builder. Pega el esquema, borra los campos que no necesites, tienes un DTO sencillo que compila por sí solo.

Revisar un cambio de API Protobuf

Un compañero del backend añadió campos a un mensaje. Quieres ver cómo afecta eso al POJO de Java sin lanzar el build. Pega el nuevo .proto, haz diff de la salida Java contra tus clases actuales, deja un comentario de revisión enfocado.

Contrastar la salida generada por protoc

Tu build usa el plugin Java oficial de protoc, que produce clases con patrón Builder. Pega el esquema aquí para tener una referencia limpia de cómo se ve Java sencillo, útil para documentación, onboarding o para compañeros de Kotlin que prefieren data classes.

Preguntas frecuentes

¿Se envía mi esquema a algún sitio?

No. El parser y el emisor de Java se ejecutan enteramente en tu navegador como JavaScript. Abre DevTools y mira la pestaña Network mientras pegas — cero peticiones. Útil cuando tu esquema incluye rutas de paquetes internos, nombres de tipos o cualquier cosa que no querrías mandar a un servicio de terceros.

¿Por qué campos públicos y no getters/setters?

Dos razones. Primera, la salida está pensada como un punto de partida que adaptas — los campos públicos son la cosa más pequeña que compila, y siempre puedes ejecutar "Encapsulate Fields" en tu IDE. Segunda, el consumidor más común es la deserialización con Jackson, que funciona de serie con campos públicos. Si necesitas un record, un tipo inmutable o una clase Lombok @Data, pega la salida y refactoriza.

¿Cómo se manejan uint32 y uint64?

Java no tiene tipos enteros sin signo, así que uint32/fixed32 mapean a int y uint64/fixed64 mapean a long. Para valores que entran en el rango con signo esto funciona bien; para valores por encima de Integer.MAX_VALUE o Long.MAX_VALUE verás números negativos. La solución estándar es Integer.toUnsignedLong(x) en la frontera, o usar los helpers aritméticos de java.lang.Long — mira la documentación de la API de Java 21 para los helpers sin signo.

¿Por qué los campos int64 son simplemente long y no String?

TypeScript y JSON tienen un techo de precisión de 53 bits, así que la spec de JSON de proto3 codifica los enteros de 64 bits como cadenas para preservar la precisión. El long de Java es un entero con signo de 64 bits real sin pérdida de precisión, así que mantenemos el tipo Java como long. Si estás deserializando JSON donde el servidor ya codificó el int64 como cadena, configura Jackson con @JsonFormat o un deserializador a medida; el tipo subyacente no necesita cambiar.

¿Cómo maneja los mensajes anidados?

Cada mensaje anidado se aplana a una clase de nivel superior. La convención de Java es una clase pública por archivo, así que los tipos planos de nivel superior son más fáciles de dividir cuando copias cada clase a su propio archivo .java. Si prefieres tener static inner classes (el estilo que emite protoc), pega la salida y mueve las clases anidadas dentro de su padre — las referencias a campos ya usan el nombre hoja y resolverán en cuanto estén en el mismo ámbito.

¿Los campos están marcados como opcionales?

No — los campos de proto3 siempre tienen un default en el formato del cable, así que los campos primitivos se inicializan a su cero Java (0, 0.0, false, ""). Los tipos referencia (List, Map, mensajes anidados, byte[]) empiezan como null; recuerda inicializarlos antes de añadir elementos. Si quieres wrappers explícitos Optional<T>, eso es un paso manual.

¿Maneja oneof?

Cada campo de oneof se emite como un campo de clase normal. La salida no fuerza la restricción de "exactamente uno" que implica oneof — para eso necesitarías una jerarquía de tipos sellada o una comprobación en tiempo de ejecución, ninguna de las cuales encaja en un POJO sencillo. Si necesitas un modelado más estricto, coge la salida y convierte los campos del oneof en una sealed interface con un record por caso.

¿Puedo usar estas clases con el runtime oficial protobuf-java?

No directamente — el runtime oficial espera clases generadas por protoc con Builder, parseFrom y el resto del contrato com.google.protobuf.MessageOrBuilder. Las clases de esta herramienta son POJOs sencillos, pensadas para serialización JSON (Jackson, Gson, Moshi). Para el formato binario del cable sigues queriendo el codegen oficial — mira el tutorial de Java para la configuración.

Herramientas relacionadas

Si trabajas con Protobuf, JSON y Java, estas casan bien: