Protobuf-naar-Java-converter
Plak een .proto-schema. Krijg eenvoudige Java-klassen die je zo in een project kunt droppen — public velden, geen getters, makkelijk aan te passen.
Invoer (.proto-schema)
Uitvoer (Java)
Wat deze tool doet
Je hebt een Protocol Buffers-schema en een Java-service die die berichten consumeert — misschien via gRPC, misschien via JSON over HTTP. Het officiële protoc draaien met de Java-plugin levert je klassen op in Builder-pattern, prima voor productie maar zwaar voor schetsen, prototyping of het met de hand mappen van JSON op een POJO. Deze converter geeft simpele Java-klassen — public velden, zinnige defaults, één klasse per bericht, aparte types voor enums.
De type-mapping volgt hoe handgeschreven Java er in de praktijk uitziet: string → String, bool → boolean, int32/sint32/sfixed32 → int, int64/sint64/sfixed64 → long, double → double, float → float, bytes → byte[]. Java heeft geen unsigned numerieke types, dus uint32/fixed32 vallen op int en uint64/fixed64 vallen op long — voor de meeste gevallen prima; als je echt het hoogste bit nodig hebt, gebruik Integer.toUnsignedLong aan de grens. repeated T wordt List<T>, map<K, V> wordt Map<K, V>, beide uit java.util.
Veldnamen worden geconverteerd van snake_case (Protobuf-conventie) naar camelCase (Java-conventie) — overeenkomend met wat protoc zou doen, en met wat de proto3 JSON-mapping gebruikt. Enums worden top-level public enum-types, met de integer-wirewaarde bewaard als final-veld, dus je kunt round-trippen via protoc-gegenereerde code als je ooit overstapt. Geneste berichten worden afgeplat tot top-level klassen, zodat elke klasse naar zijn eigen bestand kan wanneer je de uitvoer splitst. Alles draait in je browser — je schema verlaat de pagina niet.
Hoe gebruik je het
Drie stappen. De uitvoer is klaar om in een Java-project te droppen.
Plak je .proto-schema
Drop het schema in de linker editor. syntax = "proto3"; bovenaan is prima, maar optioneel. De parser kan om met geneste message-blokken, enum-declaraties, oneof, map<K, V> en veldopties. import-directives worden herkend maar overgeslagen — plak geïmporteerde types inline als je ze nodig hebt.
Veldnaam-conversie gaat automatisch: order_id in .proto wordt orderId in Java. Bericht- en enum-namen blijven zoals ze zijn (al PascalCase).
Lees de uitvoer
Aan de rechterkant: één .java-blok met eerst alle enums, dan alle klassen in declaratievolgorde. Elke klasse heeft public velden met defaultwaarden voor primitieven (0, 0.0, false, ""), en referentietypes (List, Map, berichtreferenties) blijven null tot je ze vult. De java.util.List- en java.util.Map-imports worden alleen toegevoegd als het schema ze nodig heeft.
Drop in je project
Kopieer elke klasse naar zijn eigen .java-bestand (Java vereist één public klasse per bestand). Voeg een package-declaratie toe, koppel de klassen vervolgens aan je JSON-deserializer naar keuze — Jackson pakt public velden standaard op, en de proto3 JSON-mapping gebruikt camelCase, dus de veldnamen kloppen al. Als je liever getters/setters wilt, regelt IntelliJ's "Encapsulate Fields"-refactor dat met één toetsaanslag.
Wanneer dit echt tijd bespaart
Een Java-client schetsen voor een gRPC-service
Je doet een spike voor een Java-client tegen een bestaande gRPC-backend — misschien een Spring Boot-service, misschien Quarkus — en je wilt nog niet de volledige protoc Maven- of Gradle-plugin opzetten. Plak het schema, drop de klassen in src/main/java/dto, deserialiseer de JSON-respons met Jackson, lever het prototype.
Met de hand DTO's schrijven die matchen met een proto
Je team gebruikt Protobuf als bron van waarheid op de wire, maar de consumerende Java-service heeft maar drie of vier velden nodig en je wilt geen Message/Builder-afhankelijkheid. Plak het schema, verwijder de velden die je niet nodig hebt, je hebt een eenvoudige DTO die standalone compileert.
Een Protobuf-API-wijziging reviewen
Een backend-collega heeft velden aan een bericht toegevoegd. Je wilt zien hoe dat de Java-POJO beïnvloedt zonder de build te draaien. Plak de nieuwe .proto, diff de Java-uitvoer tegen je huidige klassen, laat een gerichte review-comment achter.
De protoc-gegenereerde uitvoer dubbelchecken
Je build gebruikt de officiële protoc Java-plugin, die klassen in Builder-pattern produceert. Plak het schema hier voor een schone referentie van hoe simpel Java eruitziet, handig voor documentatie, onboarding of voor Kotlin-collega's die data classes prefereren.
Veelgestelde vragen
Wordt mijn schema ergens naartoe gestuurd?
Nee. De parser en Java-emitter draaien volledig in je browser als JavaScript. Open DevTools en bekijk het Network-tabblad terwijl je plakt — nul requests. Handig wanneer je schema interne package-paden, typenamen of iets anders bevat dat je niet naar een externe service wilt sturen.
Waarom public velden en geen getters/setters?
Twee redenen. Ten eerste, de uitvoer is bedoeld als startpunt dat je aanpast — public velden zijn het kleinste dat compileert, en je kunt altijd "Encapsulate Fields" in je IDE draaien. Ten tweede, de meest voorkomende consument is Jackson-deserialisatie, die out of the box werkt op public velden. Als je een record, immutable type of Lombok @Data-klasse nodig hebt, plak de uitvoer en refactor.
Hoe worden uint32 en uint64 behandeld?
Java heeft geen unsigned integer-types, dus uint32/fixed32 mappen naar int en uint64/fixed64 mappen naar long. Voor waarden die in het signed bereik passen werkt dit prima; voor waarden boven Integer.MAX_VALUE of Long.MAX_VALUE zie je negatieve getallen. De standaardoplossing is Integer.toUnsignedLong(x) aan de grens, of de aritmetische helpers van java.lang.Long gebruiken — zie de Java 21 API-docs voor de unsigned helpers.
Waarom zijn int64-velden gewoon long en geen String?
TypeScript en JSON hebben een precisieplafond van 53 bits, dus de proto3 JSON-spec codeert 64-bit ints als strings om precisie te behouden. Java's long is een echte 64-bit signed integer zonder precisieverlies, dus we houden het Java-type op long. Als je JSON deserialiseert waarin de server de int64 al als string heeft gecodeerd, configureer Jackson met @JsonFormat of een custom deserializer; het onderliggende type hoeft niet te veranderen.
Hoe gaat het om met geneste berichten?
Elk genest bericht wordt afgeplat tot een top-level klasse. Java's conventie is één public klasse per bestand, dus platte top-level types zijn makkelijker te splitsen wanneer je elke klasse naar zijn eigen .java-bestand kopieert. Als je liever static inner classes wilt (de stijl die protoc uitspuwt), plak de uitvoer en verplaats de geneste klassen in hun parent — de veldreferenties gebruiken al de leaf-naam en zullen oplossen zodra ze in dezelfde scope staan.
Worden velden als optional gemarkeerd?
Nee — proto3-velden hebben altijd een default in het wire-formaat, dus primitieve velden worden geïnitialiseerd op hun Java-nulwaarde (0, 0.0, false, ""). Referentietypes (List, Map, geneste berichten, byte[]) starten als null; vergeet niet ze te initialiseren voordat je elementen toevoegt. Als je expliciete Optional<T>-wrappers wilt, is dat een handmatige stap.
Werkt het met oneof?
Elk oneof-veld wordt uitgespuugd als een gewoon klasseveld. De uitvoer dwingt de "precies één"-beperking die oneof impliceert niet af — daarvoor zou je een sealed type-hiërarchie of een runtime-check nodig hebben, wat geen van beide bij een eenvoudige POJO past. Als je strakkere modellering wilt, neem de uitvoer en converteer de oneof-velden naar een sealed interface met één record per case.
Kan ik deze klassen met de officiële protobuf-java-runtime gebruiken?
Niet direct — de officiële runtime verwacht klassen gegenereerd door protoc met Builder, parseFrom en de rest van het com.google.protobuf.MessageOrBuilder-contract. De klassen uit deze tool zijn eenvoudige POJO's, bedoeld voor JSON-serialisatie (Jackson, Gson, Moshi). Voor het binaire wire-formaat wil je nog steeds de officiële codegen — zie de Java-tutorial voor de setup.
Gerelateerde tools
Als je met Protobuf, JSON en Java werkt, passen deze goed samen: