protobuf.js
protobuf.js copied to clipboard
Error using extend with fromJSON
protobuf.js version: 6.8.7 (master e8449c4)
When calling protobuf.Root.fromJSON on a JSON descriptor of a proto that contains an extend, an error is thrown saying the extended field is a duplicate.
For example a proto like:
syntax = "proto3";
package mypackage.options;
import "google/protobuf/descriptor.proto";
enum Scope {
ALL = 0;
HINT = 1;
}
extend google.protobuf.FieldOptions {
repeated Scope scope = 12345;
}
And the following in TypeScript:
import * as protobuf from 'protobufjs/light';
import * as Long from 'long';
protobuf.util.Long = Long;
protobuf.configure();
import * as protoDescriptor from './proto-reflection';
import {INamespace} from 'protobufjs';
export const protoRoot = protobuf.Root.fromJSON(protoDescriptor as INamespace);
Results in the error:
type.js:331 Uncaught Error: duplicate name '.mypackage.options.scope' in Type .google.protobuf.FieldOptions
at Type.add (type.js:331)
at tryHandleExtension (root.js:266)
at Root._handleAdd (root.js:294)
at Root._handleAdd (root.js:299)
at Root._handleAdd (root.js:299)
at Namespace.onAdd (object.js:120)
at Root.add (namespace.js:243)
at Root.addJSON (namespace.js:172)
at Function.fromJSON (root.js:51)
at Object../src/app/protos-helper.ts (protos-helper.ts:13)
One way to work around this is to modify tryHandleExtension in protobufjs/src/root.js to replace:
extendedType.add(sisterField);
with:
if (!extendedType.get(sisterField.name)) {
extendedType.add(sisterField);
}
I looked a bit more into what's causing this. Apparently in my example Namespace.addJSON is getting called on the full namespace twice:
- When the JSON module is initially imported(or required).
- When calling Root.fromJSON on the imported namespace. So this means it tries to loop over everything twice, including these extending fields.
Okay, so clearly I'm not supposed to be calling Root.fromJSON on my protoDescriptor namespace imported from the JSON module. However, TypeScript doesn't like protoDescriptor being treated as a Root directly, so I can't just use reflection methods on that...
Is there some other way I'm supposed to be getting a Root object when using JSON modules?
EDIT:
Looking again at the code of the generated JSON module, it looks like the correct way to get the Root object was staring me in the face, instead of calling: protobuf.Root.fromJSON(protoDescriptor as INamespace), simply grab protobuf.roots['default'].
This could probably be documented more explicitly, but I suppose it should have been obvious enough, so feel free to close.
I have exactly same issue. But in my case I'm importing an existing proto which contains exactly same construction. @cusher which exact solution would you propose - if such a file is imported from a root .proto file? Thanks!
I've tried your change - but for me it didn't work ( there were errors later ). So i've came with a similar change:
https://github.com/protobufjs/protobuf.js/pull/1784/files
What do you think of this?