Protobuf'tan Java'ya Dönüştürücü
Bir .proto şemasını yapıştır. Projeye doğrudan atabileceğin sade Java sınıfları al — public alanlar, getter yok, uyarlaması kolay.
Giriş (.proto şeması)
Çıkış (Java)
Bu araç ne yapar
Elinde bir Protocol Buffers şeması var ve bu mesajları tüketen bir Java servisi var — belki gRPC üzerinden, belki HTTP üzerinden JSON ile. Resmi protoc'u Java eklentisiyle çalıştırınca Builder desenli üretilmiş sınıflar elde edersin; üretim için harika ama eskiz, prototip ya da JSON'u elle bir POJO'ya eşlemek için ağır kalır. Bu dönüştürücü sade Java sınıfları çıkarır — public alanlar, makul varsayılanlar, mesaj başına bir sınıf, enum'lar için ayrı tipler.
Tip eşlemesi sahada elle yazılan Java'ya benzer şekilde işler: string → String, bool → boolean, int32/sint32/sfixed32 → int, int64/sint64/sfixed64 → long, double → double, float → float, bytes → byte[]. Java'nın işaretsiz sayısal tipi yok, bu yüzden uint32/fixed32 int'e, uint64/fixed64 ise long'a düşer — çoğu durumda yeterli; gerçekten en yüksek bite ihtiyacın varsa sınırda Integer.toUnsignedLong kullan. repeated T List<T>'ye, map<K, V> ise Map<K, V>'ye dönüşür; her ikisi de java.util'den.
Alan adları snake_case'den (Protobuf geleneği) camelCase'e (Java geleneği) çevrilir — protoc'un yapacağı şeyle ve proto3 JSON eşlemesinin kullandığı şeyle uyumlu. Enum'lar üst düzey public enum tipleri olur ve hat üstündeki tamsayı değer final bir alanda korunur, böylece bir gün geçersen protoc'un ürettiği kodla round-trip yapabilirsin. İç içe mesajlar üst düzey sınıflara düzleştirilir, böylece çıktıyı böldüğünde her biri kendi dosyasına taşınabilir. Her şey tarayıcında çalışır — şeman sayfayı terk etmez.
Nasıl kullanılır
Üç adım. Çıktı bir Java projesine doğrudan atılmaya hazır.
.proto şemanı yapıştır
Şemayı sol editöre bırak. Üstte syntax = "proto3"; bulunması iyi ama opsiyonel. Parser iç içe message bloklarını, enum bildirimlerini, oneof, map<K, V> ve alan seçeneklerini idare eder. import direktifleri tanınır ama atlanır — gerekiyorsa içe aktarılan tipleri inline yapıştır.
Alan adı dönüşümü otomatik: .proto'daki order_id, Java'da orderId olur. Mesaj ve enum adları olduğu gibi kalır (zaten PascalCase).
Çıktıyı oku
Sağ tarafta: önce tüm enum'lar, sonra bildirim sırasına göre tüm sınıfların yer aldığı tek bir .java bloğu. Her sınıfın primitifler için varsayılan değerli (0, 0.0, false, "") public alanları var; referans tipler (List, Map, mesaj refleri) ise sen doldurana kadar null kalır. java.util.List ve java.util.Map import'ları yalnızca şema gerektirdiğinde eklenir.
Projene at
Her sınıfı kendi .java dosyasına kopyala (Java dosya başına bir public sınıf ister). Bir package bildirimi ekle, ardından sınıfları tercih ettiğin JSON deserializer'a bağla — Jackson public alanları varsayılan olarak yakalar ve proto3 JSON eşlemesi camelCase kullanır, bu yüzden alan adları zaten uyuşur. Getter/setter'ları tercih edersen IntelliJ'in "Encapsulate Fields" refactor'u tek tuşla halleder.
Gerçekten zaman kazandırdığı yerler
Bir gRPC servisine yönelik Java istemcisi taslamak
Mevcut bir gRPC arka ucuna karşı bir Java istemcisi spike'lıyorsun — belki Spring Boot, belki Quarkus servisi — ve henüz tüm protoc Maven veya Gradle eklentisini kurmak istemiyorsun. Şemayı yapıştır, sınıfları src/main/java/dto'ya bırak, JSON yanıtını Jackson ile deserialize et, prototipi gönder.
Bir proto'yla eşleşen DTO'ları elle yazmak
Ekibin hat üzerinde tek doğru kaynak olarak Protobuf'u kullanıyor ama tüketici Java servisi yalnızca üç dört alana ihtiyaç duyuyor ve Message/Builder bağımlılığı istemiyorsun. Şemayı yapıştır, gereksiz alanları sil, başına buyruk derlenen sade bir DTO'n hazır.
Bir Protobuf API değişikliğini gözden geçirmek
Arka uçtaki bir takım arkadaşın bir mesaja alanlar ekledi. Build'i çalıştırmadan bunun Java POJO'sunu nasıl etkilediğini görmek istiyorsun. Yeni .proto'yu yapıştır, Java çıktısını mevcut sınıflarınla diff'le, odaklı bir review yorumu bırak.
protoc'un ürettiği çıktıyı çapraz kontrol etmek
Build'in resmi protoc Java eklentisini kullanıyor ve Builder desenli sınıflar üretiyor. Sade Java'nın nasıl göründüğüne dair temiz bir referans için şemayı buraya yapıştır; dokümantasyon, onboarding veya data class tercih eden Kotlin takım arkadaşları için kullanışlı.
Sık sorulan sorular
Şemam herhangi bir yere gönderiliyor mu?
Hayır. Parser ve Java üretici tamamen tarayıcında JavaScript olarak çalışır. Yapıştırırken DevTools'u aç ve Network sekmesini izle — sıfır istek. Şemanda dahili paket yolları, tip adları veya üçüncü taraf bir servise göndermek istemeyeceğin herhangi bir şey varsa kullanışlıdır.
Neden getter/setter değil de public alanlar?
İki sebep. Birincisi, çıktı uyarladığın bir başlangıç noktası olarak tasarlandı — public alanlar derlemenin en küçük hâli ve istediğinde IDE'nde "Encapsulate Fields"'i çalıştırabilirsin. İkincisi, en yaygın tüketici Jackson deserialize'ı ve public alanlarda kutudan çıktığı gibi çalışır. Bir record, immutable tip ya da Lombok @Data sınıfına ihtiyacın varsa çıktıyı yapıştır ve refactor'la.
uint32 ve uint64 nasıl ele alınıyor?
Java'nın işaretsiz tamsayı tipi yok, bu yüzden uint32/fixed32 int'e, uint64/fixed64 ise long'a eşlenir. İşaretli aralığa sığan değerler için bu sorunsuz çalışır; Integer.MAX_VALUE veya Long.MAX_VALUE'nin üstündeki değerlerde negatif sayılar görürsün. Standart çözüm sınırda Integer.toUnsignedLong(x) kullanmak ya da java.lang.Long aritmetik yardımcılarını kullanmak — işaretsiz yardımcılar için Java 21 API dokümanlarına bak.
int64 alanları neden String değil de düz long?
TypeScript ve JSON'un 53 bitlik bir hassasiyet tavanı var, bu yüzden proto3 JSON spec'i hassasiyeti korumak için 64-bit tamsayıları string olarak kodlar. Java'nın long'u gerçek 64-bit işaretli bir tamsayı ve hassasiyet kaybı yaşamaz, bu yüzden Java tipini long olarak tutuyoruz. Sunucunun int64'ü string olarak kodladığı bir JSON'u deserialize ediyorsan Jackson'ı @JsonFormat veya özel bir deserializer ile yapılandır; alttaki tipin değişmesi gerekmez.
İç içe mesajlar nasıl ele alınıyor?
Her iç içe mesaj üst düzey bir sınıfa düzleştirilir. Java'nın geleneği dosya başına bir public sınıf, bu yüzden düz üst düzey tipler her sınıfı kendi .java dosyasına kopyalarken bölmek için daha kolaydır. Bunun yerine static inner class'lar (protoc'un ürettiği stil) tercih edersen, çıktıyı yapıştır ve iç içe sınıfları ebeveynlerinin içine taşı — alan referansları zaten leaf adı kullanıyor ve aynı kapsama girdiklerinde çözülecektir.
Alanlar optional olarak işaretleniyor mu?
Hayır — proto3 alanlarının hat formatında her zaman bir varsayılanı vardır, bu yüzden primitif alanlar Java sıfır değerine (0, 0.0, false, "") ilklendirilir. Referans tipler (List, Map, iç içe mesajlar, byte[]) null olarak başlar; eleman eklemeden önce ilklemeyi unutma. Açık Optional<T> sarmalayıcıları istiyorsan, bu manuel bir adımdır.
oneof'u idare ediyor mu?
Her oneof alanı normal bir sınıf alanı olarak çıkarılır. Çıktı oneof'un ima ettiği "tam olarak bir tane" kısıtlamasını zorlamaz — bunun için sealed bir tip hiyerarşisi ya da çalışma zamanı kontrolü gerekir, ikisi de sade bir POJO'ya uymaz. Daha sıkı bir modelleme istiyorsan çıktıyı al ve oneof alanlarını her durum için bir record olan sealed bir interface'e dönüştür.
Bu sınıfları resmi protobuf-java çalışma zamanıyla kullanabilir miyim?
Doğrudan değil — resmi çalışma zamanı protoc'un ürettiği, Builder, parseFrom ve com.google.protobuf.MessageOrBuilder sözleşmesinin geri kalanını taşıyan sınıfları bekler. Bu aracın çıkardığı sınıflar JSON serileştirme (Jackson, Gson, Moshi) için tasarlanmış sade POJO'lardır. İkili hat formatı için yine resmi codegen'i istersin — kurulum için Java rehberine bak.
İlgili araçlar
Protobuf, JSON ve Java ile çalışıyorsan bunlar iyi gider: