Introduzione a Google Protocol Buffer

1. Panoramica

In questo articolo, esamineremo il Google Protocol Buffer (protobuf), un noto formato di dati binari indipendente dalla lingua. Possiamo definire un file con un protocollo e successivamente, usando quel protocollo, possiamo generare codice in linguaggi come Java, C ++, C #, Go o Python.

Questo è un articolo introduttivo al formato stesso; se vuoi vedere come utilizzare il formato con un'applicazione web Spring, dai un'occhiata a questo articolo.

2. Definizione delle dipendenze Maven

Per utilizzare i buffer di protocollo è Java, dobbiamo aggiungere una dipendenza Maven a un protobuf-java:

 com.google.protobuf protobuf-java ${protobuf.version}   3.2.0 

3. Definizione di un protocollo

Cominciamo con un esempio. Possiamo definire un protocollo molto semplice in un formato protobuf:

message Person { required string name = 1; }

Questo è un protocollo di un semplice messaggio di tipo Persona che ha un solo campo obbligatorio - nome che ha un tipo stringa .

Diamo un'occhiata all'esempio più complesso di definizione di un protocollo. Supponiamo di dover memorizzare i dettagli della persona in un formato protobuf:

pacchetto protobuf;

package protobuf; option java_package = "com.baeldung.protobuf"; option java_outer_classname = "AddressBookProtos"; message Person { required string name = 1; required int32 id = 2; optional string email = 3; repeated string numbers = 4; } message AddressBook { repeated Person people = 1; }

Il nostro protocollo è costituito da due tipi di dati: una persona e una rubrica. Dopo aver generato il codice (maggiori informazioni su questo nella sezione successiva), quelle classi saranno le classi interne all'interno della classe AddressBookProtos .

Quando vogliamo definire un campo che è richiesto, il che significa che la creazione di un oggetto senza tale campo causerà un'eccezione , dobbiamo usare una parola chiave obbligatoria .

La creazione di un campo con la parola chiave opzionale significa che non è necessario impostare questo campo. La parola chiave ripetuta è un tipo di matrice di dimensione variabile.

Tutti i campi sono indicizzati: il campo indicato con il numero 1 verrà salvato come primo campo in un file binario. Il campo contrassegnato con 2 verrà salvato successivamente e così via. Questo ci dà un controllo migliore su come i campi sono disposti nella memoria.

4. Generazione di codice Java da un file Protobuf

Una volta definito un file, possiamo generare codice da esso.

Innanzitutto, dobbiamo installare protobuf sulla nostra macchina. Una volta fatto ciò, possiamo generare codice eseguendo un comando protoc :

protoc -I=. --java_out=. addressbook.proto

Il comando protoc genererà il file di output Java dal nostro file addressbook.proto . L' opzione -I specifica una directory in cui risiede un file proto . Il java-out specifica una directory in cui verrà creata la classe generata.

La classe generata avrà setter, getter, costruttori e builder per i nostri messaggi definiti. Avrà anche alcuni metodi di utilità per salvare i file protobuf e deserializzarli dal formato binario alla classe Java.

5. Creazione di un'istanza di messaggi definiti da Protobuf

Possiamo facilmente utilizzare un codice generato per creare un'istanza Java di una classe Person :

String email = "[email protected]"; int id = new Random().nextInt(); String name = "Michael Program"; String number = "01234567890"; AddressBookProtos.Person person = AddressBookProtos.Person.newBuilder() .setId(id) .setName(name) .setEmail(email) .addNumbers(number) .build(); assertEquals(person.getEmail(), email); assertEquals(person.getId(), id); assertEquals(person.getName(), name); assertEquals(person.getNumbers(0), number);

Possiamo creare un builder fluente utilizzando un metodo newBuilder () sul tipo di messaggio desiderato. Dopo aver impostato tutti i campi obbligatori, possiamo chiamare un metodo build () per creare un'istanza di una classe Person .

6. Serializzazione e deserializzazione di Protobuf

Una volta creata un'istanza della nostra classe Person , vogliamo salvarla su disco in un formato binario compatibile con un protocollo creato. Diciamo che vogliamo creare un'istanza della classe AddressBook e aggiungere una persona a quell'oggetto.

Successivamente, vogliamo salvare quel file su disco: c'è un metodo util writeTo () nel codice generato automaticamente che possiamo usare:

AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder().addPeople(person).build(); FileOutputStream fos = new FileOutputStream(filePath); addressBook.writeTo(fos);

Dopo aver eseguito quel metodo, il nostro oggetto verrà serializzato in formato binario e salvato su disco. Per caricare quei dati da un disco e deserializzarli di nuovo nell'oggetto AddressBook possiamo usare un metodo mergeFrom () :

AddressBookProtos.AddressBook deserialized = AddressBookProtos.AddressBook.newBuilder() .mergeFrom(new FileInputStream(filePath)).build(); assertEquals(deserialized.getPeople(0).getEmail(), email); assertEquals(deserialized.getPeople(0).getId(), id); assertEquals(deserialized.getPeople(0).getName(), name); assertEquals(deserialized.getPeople(0).getNumbers(0), number);

7. Conclusione

In questo rapido articolo, abbiamo introdotto uno standard per la descrizione e l'archiviazione dei dati in un formato binario: Google Protocol Buffer.

Abbiamo creato un protocollo semplice, creato un'istanza Java conforme al protocollo definito. Successivamente, abbiamo visto come serializzare e deserializzare gli oggetti usando protobuf.

L'implementazione di tutti questi esempi e frammenti di codice può essere trovata nel progetto GitHub: questo è un progetto Maven, quindi dovrebbe essere facile da importare ed eseguire così com'è.