Input (.proto-skema)

Output (Java)

Hvad det her værktøj gør

Du har et Protocol Buffers-skema og en Java-tjeneste, der forbruger de meddelelser — måske over gRPC, måske via JSON over HTTP. At køre den officielle protoc med Java-pluginet giver dig genererede klasser i Builder-stil, der er fine til produktion men tunge, når du skitserer, prototyper eller hånd-mapper JSON ned i en POJO. Denne konverter spytter almindelige Java-klasser ud — public-felter, fornuftige defaults, én klasse per meddelelse, separate typer til enums.

Type-mappingen følger det, som håndskrevet Java ser ud i praksis: stringString, boolboolean, int32/sint32/sfixed32int, int64/sint64/sfixed64long, doubledouble, floatfloat, bytesbyte[]. Java har ingen unsigned numeriske typer, så uint32/fixed32 falder til int og uint64/fixed64 falder til long — fint i de fleste tilfælde; har du faktisk brug for den øverste bit, så brug Integer.toUnsignedLong ved grænsen. repeated T bliver List<T>, map<K, V> bliver Map<K, V>, begge fra java.util.

Feltnavne konverteres fra snake_case (Protobuf-konvention) til camelCase (Java-konvention) — i tråd med, hvad protoc ville gøre, og hvad proto3 JSON-mappingen bruger. Enums bliver til top-level public enum-typer med heltalsværdien fra ledningen bevaret som et final-felt, så du kan round-trippe gennem protoc-genereret kode, hvis du nogensinde skifter over. Nestede meddelelser flades ud til top-level klasser, så hver kan flytte ind i sin egen fil, når du splitter outputtet. Alt kører i din browser — dit skema forlader ikke siden.

Sådan bruger du det

Tre skridt. Outputtet er klar til at smide ind i et Java-projekt.

1

Indsæt dit .proto-skema

Smid skemaet i editoren til venstre. syntax = "proto3"; i toppen er fint men valgfrit. Parseren håndterer nestede message-blokke, enum-deklarationer, oneof, map<K, V> og feltoptions. import-direktiver genkendes men springes over — indsæt importerede typer inline, hvis du har brug for dem.

Feltnavnskonvertering sker automatisk: order_id i .proto bliver til orderId i Java. Meddelelses- og enumnavne lades stå som de er (allerede PascalCase).

2

Læs outputtet

Til højre: én enkelt .java-blok med alle enums først, derefter alle klasser i deklarationsrækkefølge. Hver klasse har public-felter med default-værdier til primitiver (0, 0.0, false, ""), og referencetyper (List, Map, meddelelses-referencer) står som null, indtil du fylder dem. Importerne java.util.List og java.util.Map tilføjes kun, når skemaet kræver det.

3

Smid det ind i dit projekt

Kopiér hver klasse over i sin egen .java-fil (Java kræver én public-klasse per fil). Tilføj en package-deklaration, og kobl så klasserne på din JSON-deserializer efter eget valg — Jackson tager public-felter som standard, og proto3 JSON-mappingen bruger camelCase, så feltnavnene matcher allerede. Foretrækker du gettere/settere, klarer IntelliJs "Encapsulate Fields"-refaktor det med ét tastetryk.

Hvornår det reelt sparer tid

Skitsere en Java-klient til en gRPC-tjeneste

Du laver en spike med en Java-klient mod en eksisterende gRPC-backend — måske en Spring Boot-tjeneste, måske en Quarkus — og du vil ikke sætte den fulde protoc Maven- eller Gradle-plugin op endnu. Indsæt skemaet, smid klasserne i src/main/java/dto, deserialisér JSON-svaret med Jackson, lever prototypen.

Håndlave DTO'er der matcher en proto

Dit team bruger Protobuf som sandhedskilde på ledningen, men den forbrugende Java-tjeneste behøver kun tre eller fire felter, og du vil ikke have et Message/Builder-afhængighed. Indsæt skemaet, slet de felter du ikke skal bruge, og du har en almindelig DTO, der kompilerer fritstående.

Reviewe en Protobuf-API-ændring

En backend-kollega tilføjede felter til en meddelelse. Du vil se, hvordan det påvirker Java-POJO'en uden at køre buildet. Indsæt det nye .proto, diff Java-outputtet mod dine nuværende klasser, efterlad en fokuseret review-kommentar.

Krydscheck af protoc-genereret output

Dit build bruger den officielle protoc Java-plugin, som producerer klasser i Builder-stil. Indsæt skemaet her for en ren reference på, hvordan almindelig Java ser ud — nyttigt til dokumentation, onboarding eller for Kotlin-kolleger, der foretrækker data classes.

Almindelige spørgsmål

Bliver mit skema sendt nogen steder hen?

Nej. Parseren og Java-emitteren kører fuldt ud i din browser som JavaScript. Åbn DevTools og hold øje med Network-fanen, mens du indsætter — nul requests. Nyttigt når dit skema indeholder interne package-stier, typenavne eller noget, du helst ikke vil sende til en tredjepartstjeneste.

Hvorfor public-felter og ikke gettere/settere?

To grunde. For det første er outputtet tænkt som et udgangspunkt, du tilpasser — public-felter er det mindste, der kompilerer, og du kan altid køre "Encapsulate Fields" i din IDE. For det andet er den mest almindelige forbruger Jackson-deserialisering, som virker direkte på public-felter. Har du brug for en record, en immutable type eller en Lombok @Data-klasse, så indsæt outputtet og refaktorér.

Hvordan håndteres uint32 og uint64?

Java har ingen unsigned heltalstyper, så uint32/fixed32 mappes til int og uint64/fixed64 til long. For værdier der ligger inden for det signede interval, virker det fint; for værdier over Integer.MAX_VALUE eller Long.MAX_VALUE ser du negative tal. Standardløsningen er Integer.toUnsignedLong(x) ved grænsen, eller brug aritmetiske helpers fra java.lang.Long — se Java 21 API-dokumentationen for unsigned-helpers.

Hvorfor er int64-felter bare long og ikke String?

TypeScript og JSON har et præcisionsloft på 53 bit, så proto3 JSON-spec'en koder 64-bits heltal som strings for at bevare præcisionen. Javas long er et ægte 64-bits signed heltal uden præcisionstab, så vi beholder Java-typen som long. Hvis du deserialiserer JSON, hvor serveren allerede har kodet int64 som streng, så konfigurér Jackson med @JsonFormat eller en custom deserializer; den underliggende type behøver ikke at ændres.

Hvordan håndteres nestede meddelelser?

Hver nestet meddelelse flades ud til en top-level klasse. Java-konventionen er én public-klasse per fil, så flade top-level typer er nemmere at splitte op, når du kopierer hver klasse til sin egen .java-fil. Vil du hellere have statiske inner-klasser (stilen protoc spytter ud), så indsæt outputtet og flyt de nestede klasser ind i deres forælder — feltreferencerne bruger allerede leaf-navnet og resolver, så snart de havner i samme scope.

Er felter markeret som optional?

Nej — proto3-felter har altid en default i wire-formatet, så primitive felter initialiseres til deres Java-nulværdi (0, 0.0, false, ""). Referencetyper (List, Map, nestede meddelelser, byte[]) starter som null; husk at initialisere dem, før du tilføjer elementer. Vil du have eksplicitte Optional<T>-wrappers, er det et manuelt skridt.

Håndterer den oneof?

Hvert oneof-felt udsendes som et almindeligt klasse-felt. Outputtet håndhæver ikke "præcis én"-betingelsen, som oneof indebærer — det ville kræve en sealed type-hierarki eller et runtime-tjek, og ingen af delene passer til en almindelig POJO. Vil du have strammere modellering, så tag outputtet og konvertér oneof-felterne til et sealed interface med én record per case.

Kan jeg bruge disse klasser med den officielle protobuf-java-runtime?

Ikke direkte — den officielle runtime forventer klasser genereret af protoc med Builder, parseFrom og resten af com.google.protobuf.MessageOrBuilder-kontrakten. Klasserne fra det her værktøj er almindelige POJO'er, tænkt til JSON-serialisering (Jackson, Gson, Moshi). Til binær wire-format vil du stadig have den officielle codegen — se Java-tutorialen for opsætningen.

Relaterede værktøjer

Hvis du arbejder med Protobuf, JSON og Java, passer disse godt sammen: