Conversor Protobuf para Java
Cole um esquema .proto. Receba classes Java simples para colocar num projeto — campos públicos, sem getters, fáceis de adaptar.
Entrada (esquema .proto)
Saída (Java)
O que esta ferramenta faz
Você tem um esquema Protocol Buffers e um serviço Java que consome essas mensagens — talvez via gRPC, talvez via JSON sobre HTTP. Rodar o protoc oficial com o plugin Java dá classes geradas no padrão Builder, ótimas para produção mas pesadas para esboçar, prototipar ou mapear JSON na mão para um POJO. Este conversor emite classes Java simples — campos públicos, defaults sensatos, uma classe por mensagem, tipos separados para enums.
O mapeamento de tipos segue como o Java escrito à mão aparece na prática: string → String, bool → boolean, int32/sint32/sfixed32 → int, int64/sint64/sfixed64 → long, double → double, float → float, bytes → byte[]. Java não tem tipos numéricos sem sinal, então uint32/fixed32 caem para int e uint64/fixed64 caem para long — tudo bem para a maior parte dos casos; se você realmente precisa do bit alto, use Integer.toUnsignedLong na fronteira. repeated T vira List<T>, map<K, V> vira Map<K, V>, ambos de java.util.
Os nomes de campos são convertidos de snake_case (convenção Protobuf) para camelCase (convenção Java) — combinando com o que o protoc faria, e com o que o mapeamento JSON do proto3 usa. Enums viram tipos public enum de nível superior com o valor inteiro do fio preservado num campo final, então você consegue round-trip via código gerado pelo protoc se um dia migrar. Mensagens aninhadas são achatadas em classes de nível superior para que cada uma possa ir para seu próprio arquivo quando você dividir a saída. Tudo roda no seu navegador — seu esquema não sai da página.
Como usar
Três passos. A saída está pronta para colocar num projeto Java.
Cole o seu esquema .proto
Solte o esquema no editor da esquerda. syntax = "proto3"; no topo está OK mas é opcional. O parser lida com blocos message aninhados, declarações enum, oneof, map<K, V> e opções de campo. Diretivas import são reconhecidas mas puladas — cole os tipos importados inline se precisar deles.
A conversão de nomes de campos é automática: order_id no .proto vira orderId em Java. Nomes de mensagens e enums ficam como estão (já em PascalCase).
Leia a saída
À direita: um único bloco .java com todos os enums primeiro, depois todas as classes na ordem de declaração. Cada classe tem campos públicos com valores default para primitivos (0, 0.0, false, ""), e tipos referência (List, Map, refs de mensagens) ficam como null até você populá-los. Os imports java.util.List e java.util.Map só são adicionados quando o esquema precisa deles.
Coloque no seu projeto
Copie cada classe para seu próprio arquivo .java (Java exige uma classe pública por arquivo). Adicione uma declaração package, depois conecte as classes ao seu desserializador JSON preferido — Jackson pega campos públicos por padrão, e o mapeamento JSON do proto3 usa camelCase, então os nomes de campos já batem. Se você prefere getters/setters, o refactor "Encapsulate Fields" do IntelliJ resolve isso com uma tecla.
Quando isso realmente economiza tempo
Esboçar um cliente Java para um serviço gRPC
Você está fazendo um spike de cliente Java contra um backend gRPC existente — talvez um serviço Spring Boot, talvez um Quarkus — e ainda não quer montar o plugin protoc Maven ou Gradle completo. Cole o esquema, jogue as classes em src/main/java/dto, desserialize a resposta JSON com Jackson, lance o protótipo.
Escrever DTOs à mão que combinam com um proto
Sua equipe usa Protobuf como fonte da verdade no fio, mas o serviço Java consumidor só precisa de três ou quatro campos e você não quer uma dependência Message/Builder. Cole o esquema, apague os campos que não precisa, e você tem um DTO simples que compila standalone.
Revisar uma mudança de API Protobuf
Um colega do backend adicionou campos a uma mensagem. Você quer ver como isso afeta o POJO Java sem rodar o build. Cole o novo .proto, faça diff da saída Java contra suas classes atuais, deixe um comentário de revisão objetivo.
Cruzar com a saída gerada pelo protoc
Seu build usa o plugin Java oficial do protoc, que produz classes no padrão Builder. Cole o esquema aqui para ter uma referência limpa de como Java simples se parece, útil para documentação, onboarding ou para colegas de Kotlin que preferem data classes.
Perguntas frequentes
Meu esquema é enviado para algum lugar?
Não. O parser e o emissor Java rodam inteiramente no seu navegador como JavaScript. Abra o DevTools e olhe a aba Network enquanto cola — zero requests. Útil quando seu esquema inclui caminhos de package internos, nomes de tipos ou qualquer coisa que você não queira mandar para um serviço de terceiros.
Por que campos públicos e não getters/setters?
Duas razões. Primeira, a saída é pensada como ponto de partida que você adapta — campos públicos são a menor coisa que compila, e você sempre pode rodar "Encapsulate Fields" na sua IDE. Segunda, o consumidor mais comum é a desserialização Jackson, que funciona de cara em campos públicos. Se você precisa de um record, tipo imutável ou classe Lombok @Data, cole a saída e refatore.
Como uint32 e uint64 são tratados?
Java não tem tipos inteiros sem sinal, então uint32/fixed32 mapeiam para int e uint64/fixed64 mapeiam para long. Para valores que cabem no intervalo com sinal isso funciona; para valores acima de Integer.MAX_VALUE ou Long.MAX_VALUE você verá números negativos. A solução padrão é Integer.toUnsignedLong(x) na fronteira, ou usar os helpers aritméticos de java.lang.Long — veja a documentação da API Java 21 para os helpers sem sinal.
Por que campos int64 são apenas long, não String?
TypeScript e JSON têm um teto de precisão de 53 bits, então a spec JSON do proto3 codifica inteiros de 64 bits como strings para preservar precisão. O long de Java é um inteiro com sinal de 64 bits real sem perda de precisão, então mantemos o tipo Java como long. Se você está desserializando JSON onde o servidor já codificou o int64 como string, configure o Jackson com @JsonFormat ou um desserializador custom; o tipo subjacente não precisa mudar.
Como ele lida com mensagens aninhadas?
Cada mensagem aninhada é achatada em uma classe de nível superior. A convenção Java é uma classe pública por arquivo, então tipos planos de nível superior são mais fáceis de dividir quando você copia cada classe para seu próprio arquivo .java. Se você prefere ter static inner classes (o estilo que o protoc emite), cole a saída e mova as classes aninhadas para dentro do pai — as referências aos campos já usam o nome da folha e vão resolver assim que estiverem no mesmo escopo.
Os campos são marcados como opcionais?
Não — campos proto3 sempre têm um default no formato do fio, então campos primitivos são inicializados com seu valor zero Java (0, 0.0, false, ""). Tipos referência (List, Map, mensagens aninhadas, byte[]) começam como null; lembre-se de inicializá-los antes de adicionar elementos. Se quiser wrappers explícitos Optional<T>, isso é um passo manual.
Ele lida com oneof?
Cada campo de oneof é emitido como um campo de classe normal. A saída não impõe a restrição "exatamente um" que oneof implica — para isso você precisaria de uma hierarquia de tipos sealed ou uma checagem em runtime, nada disso encaixa num POJO simples. Se quiser modelagem mais estrita, pegue a saída e converta os campos do oneof em uma sealed interface com um record por caso.
Posso usar essas classes com o runtime oficial protobuf-java?
Não diretamente — o runtime oficial espera classes geradas pelo protoc com Builder, parseFrom e o resto do contrato com.google.protobuf.MessageOrBuilder. As classes desta ferramenta são POJOs simples, voltadas para serialização JSON (Jackson, Gson, Moshi). Para o formato binário do fio você ainda quer o codegen oficial — veja o tutorial Java para o setup.
Ferramentas relacionadas
Se você está mexendo com Protobuf, JSON e Java, esses combinam bem: