Serializa tus datos con Protocol Buffers (1/2)

0
4309

Google nos ofrece este sencillo método para tratar estructuras de datos serializadas y olvidarnos del lenguaje utilizado y de la plataforma en la que se vaya a ejecutar.

Índice de contenidos


1. Introducción

Protocol Buffers es un mecanismo de Google para serializar estructuras de datos independientes a la plataforma y al lenguaje, que luego podremos compilar al lenguaje que utilicemos en nuestra aplicación, obteniendo a la vez métodos de lectura y escritura de los mismos. En este tutorial, veremos cómo crear nuestras estructuras utilizando proto3, la última versión del protocolo.


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (2,2 Ghz Intel Core i7, 16GB DDR3).
  • Sistema Operativo: Mac OS High Sierra 10.13
  • Compilador de Protocol Buffers: protoc 3.5.1 (versión precompilada para MacOS)


3. Estructura de un .proto

La extensión de archivo que se utiliza es .proto, y dentro de ellos, la unidad principal para los registros de datos es el message, que contiene pares nombre-valor con los atributos que queremos incluir. Por ejemplo, podríamos tener el siguiente archivo Car.proto:

syntax = "proto3";

message Car {
  required int plate_number = 1;
  optional string brand = 2;
  optional string color = 3;
}

Lo que más llama la atención es el “=1”, “=2”, etc que aparece con cada campo: son los tags o etiquetas, que servirán para identificarlos cuando se utilice formato binario. Es de vital importancia que, una vez que el tipo ha sido compilado y esté utilizándose, no se modifiquen las etiquetas de los campos, ya que provocaríamos errores de parseo entre las distintas versiones del tipo.

Aparte de eso, vemos que cada entrada del mensaje consta de:

  • un modificador, que puede ser required (obligatorio), optional (opcional) o repeated (puede aparecer cualquier número de veces, incluido el cero; se asemejan a los arrays dinámicos). Los campos opcionales incluyen un resultado por defecto para los casos en que no especifiquemos un valor, aunque podemos modificarlo a nuestro gusto:
  • optional string cad = 1 [default = “blah”];
  • el tipo del campo, que puede ser simple (bool, int32, double, string…) o definido por el usuario como enumerado o como mensaje. Estos dos casos los veremos en secciones siguientes.
  • el nombre del campo.

Por último, nos fijamos en que la primera línea del archivo es syntax = «proto3». Si no utilizamos la opción syntax, el compilador dará por hecho que estamos utilizando proto2, por lo que es bastante importante especificarlo. Además, debe ser la primera línea no vacía del archivo que no sea un comentario.


4. Enumerados

Definir enumerados en un .proto es muy sencillo; solo hay que especificar el nombre de los valores que puede tomar:

enum Position {
    CENTER = 0;
    UP = 1;
    DOWN = 2;
}

Solamente debemos tener en cuenta que la etiqueta de la primera entrada del enumerado debe ser 0, que además será la que se utilice como valor por defecto.


5. Mensajes como tipo

Podemos utilizar otros mensajes como tipo para entradas en otro mensaje. Puede estar definido en el mismo archivo, dentro del mensaje en el que lo vamos a utilizar o incluso en otro archivo. Estudiamos los tres casos:

  • mensajes “hermanos”:
  • message A {
        …
    }
    
    message B {
        required A field = 1;
    }
    
  • mensajes «hijos»:
  • message A {
        message B {
            …
        }
    }
    
        repeated B field = 1;
    }
    
  • mensajes «sobrinos»:
  • message A {
        message B {
            …
        }
        required B field = 1;
    }
    
    message C {
        optional A.B val = 1;
    }
    
  • mensajes no relacionados: necesitamos importar el .proto en el que está definido. Una vez hecho eso, se utiliza igual que en el primer caso. Por ejemplo, para utilizar el tipo A definido en el archivo file1.proto dentro de un mensaje B del archivo file2.proto, hay que incluir la siguiente línea al principio (pero después de decir que estamos usando proto3) de file2.proto:
  • import "file1.proto";


6. Compilando

Una vez que ya tenemos preparado nuestro archivo example.proto, procedemos a compilarlo vía protoc:

protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/example.proto

Con la opción I, indicamos el directorio fuente (si no lo indicamos, tomará el directorio actual); con java_out estamos diciendo que queremos que se compile en Java, además de especificar el directorio destino en el que queremos que se creen los .java. Por último, se añade la ruta al archivo .proto que queremos compilar.

Como resultado, obtendremos un archivo .java con una clase por cada mensaje que hayamos definido, así como una clase Builder para crear instancias de estos mensajes.


7. Conclusiones

Esta ha sido una pequeña introducción al formato de los archivos .protoc, suficiente para empezar a probar el potencial que tiene la herramienta. En la segunda y última parte de este tutorial, ampliaremos las opciones que nos ofrece y profundizaremos un poco más en su funcionamiento.


8. Referencias

Documentación oficial de Protocol Buffers

Consultor tecnológico de desarrollo de proyectos informáticos.
Doble graduado en Ingeniería Informática y Matemáticas (UCM).
Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.
Somos expertos en Java/Java EE

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad