probuf
v0.1.3
Published
</a>
Downloads
425
Readme
Probuf
Core Probuf library. Probufs are a way of encoding structured data in an efficient yet extensible format.
🌐 Online reference
Examples
These headers allow to access protobuf-java APIs from a GraalJS execution
environment to serialise and deserialise objects.
Since statically-generated bindings are produced as Java code by
protoc, only DynamicMessage capabilities (aka, reflection) are supported.
Preparation
Firstly, we will need a proto file:
syntax = "proto3";
package example;
option java_package = "com.example.protos";
option java_outer_classname = "PersonProto";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}Then we generate the binary descriptor that will be read into runtime:
protoc --descriptor_set_out=person.desc --include_imports person.protoThis is different from fully-optimised Java-code generated by protoc which is
not supported.
Reading Descriptor
Now the descriptor can be loaded:
// doc/example/person.js
import FileDescriptorSet from 'probuf/DescriptorProtos/FileDescriptorSet'
import FileDescriptor from 'probuf/Descriptors/FileDescriptor'
import { readAllBytes } from '@javish/nio/file/Files'
import Paths from '@javish/nio/file/Paths'
var bytes = readAllBytes(
Paths.get('doc/example/person.desc')
)
var fds = FileDescriptorSet.parseFrom(bytes)
var fileDesc = FileDescriptor.buildFrom(fds.getFile(0), [])
export var Person = fileDesc.findMessageTypeByName('Person')
Serialisation
As we have the descriptor, we can load it and create the Person object dynamically:
// doc/example/build-alice.js
import DynamicMessage from 'probuf/DynamicMessage'
import TextFormat from 'probuf/TextFormat'
import { write } from '@javish/nio/file/Files'
import Paths from '@javish/nio/file/Paths'
import { Person } from './person'
var person = DynamicMessage.newBuilder(Person)
person.setField(
Person.findFieldByName('name'),
'Alice'
)
person.setField(
Person.findFieldByName('id'),
123
)
person.setField(
Person.findFieldByName('email'),
'[email protected]'
)
var phonesField = Person.findFieldByName('phones')
var Phone = phonesField.getMessageType()
var typeField = Phone.findFieldByName('type')
var phoneTypeEnum = typeField.getEnumType()
// Phone 1: WORK
var phone1 = DynamicMessage.newBuilder(Phone)
phone1.setField(Phone.findFieldByName('number'), '555-1234')
phone1.setField(typeField, phoneTypeEnum.findValueByName('WORK'))
person.addRepeatedField(phonesField, phone1.build())
// Phone 2: HOME
var phone2 = DynamicMessage.newBuilder(Phone)
phone2.setField(Phone.findFieldByName('number'), '555-5678')
phone2.setField(typeField, phoneTypeEnum.findValueByName('HOME'))
person.addRepeatedField(phonesField, phone2.build())
var msg = person.build()
print(TextFormat.printer().printToString(msg))
// write TextFormat output to file
write(Paths.get('doc/example/alice.text'), msg.toString())
// write binary protobuf to file
write(Paths.get('doc/example/alice.bin'), msg.toByteArray())This produces a text form:
name: "Alice"
id: 123
email: "[email protected]"
phones {
number: "555-1234"
type: WORK
}
phones {
number: "555-5678"
type: HOME
}
And a binary form:
Alice{[email protected]"
555-1234"
555-5678Deserialisation
Having Alice's data, we can also read it and convert back into the Person object dynamically from binary:
// doc/example/read-alice-bin.js
import DynamicMessage from 'probuf/DynamicMessage'
import { readAllBytes } from '@javish/nio/file/Files'
import Paths from '@javish/nio/file/Paths'
import { Person } from "./person"
import { toObject } from './to-object'
/**
* @param {string} filePath
* @return {DynamicMessage}
*/
function parsePersonBin(filePath) {
var bytes = readAllBytes(Paths.get(filePath))
var builder = DynamicMessage.newBuilder(Person)
builder.mergeFrom(bytes)
return builder.build()
}
var personFromBin = parsePersonBin('doc/example/alice.bin')
print(JSON.stringify(toObject(personFromBin), null, 1))And from text:
// doc/example/read-alice-text.js
import DynamicMessage from 'probuf/DynamicMessage'
import TextFormat from 'probuf/TextFormat'
import { readAllBytes } from '@javish/nio/file/Files'
import Paths from '@javish/nio/file/Paths'
import { Person } from "./person"
import { toObject } from './to-object'
/**
* @param {string} filePath
* @return {DynamicMessage}
*/
function parsePersonText(filePath) {
var bytes = readAllBytes(Paths.get(filePath))
var builder = DynamicMessage.newBuilder(Person)
var text = `${bytes}`
TextFormat.merge(text, builder)
return builder.build()
}
var personFromText = parsePersonText('doc/example/alice.text', true)
print(JSON.stringify(toObject(personFromText), null, 1))// doc/example/to-object.js
import 'probuf/DynamicMessage'
/**
* @param {com.google.protobuf.DynamicMessage} msg
* @returns
*/
export function toObject(msg) {
var obj = {}
var fields = msg.getAllFields().entrySet().iterator()
while (fields.hasNext()) {
var entry = fields.next()
var fd = entry.getKey()
var val = entry.getValue()
if (fd.isRepeated()) {
var arr = []
var it = val.iterator()
while (it.hasNext()) {
var v = it.next()
if (fd.getJavaType().toString() == "MESSAGE") arr.push(toObject(v))
else if (fd.getJavaType().toString() == "ENUM") arr.push(v.getName())
else arr.push(v)
}
obj[fd.getName()] = arr
} else {
if (fd.getJavaType().toString() == "MESSAGE") obj[fd.getName()] = toObject(val)
else if (fd.getJavaType().toString() == "ENUM") obj[fd.getName()] = val.getName()
else obj[fd.getName()] = val
}
}
return obj
}
License
While most of the documentation is received from the protocol buffers, the examples were adjusted to the target language (JavaScript) and are subject to copyright license.
Protocol Buffers - Google's data interchange format
Copyright 2008 Google Inc. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd❔ This package contains JavaScript header files which were automatically generated for a public Maven artifact. The project admins do not aclaim ownership of the original work, and/or any affiliation with, or endorsement by, the original software authors, trademark holders or the Maven registry itself.
