Skip to content

Use Custom Type Registry with UnmarshalAny #1085

Closed
@Rossiar

Description

@Rossiar

Is your feature request related to a problem? Please describe.

The protoregistry is a very powerful tool that allows users to register their own types at runtime. I have made use of this feature along with protojson.UnmarshalOptions to supply my own Resolver that is backed by a protoregistry.Types that I fill dynamically with my own types.

Unfortunately I am also using any.Any within my message to specify a generic "payload" and when I come to unmarshal that payload I receive err == protoregistry.NotFound.

var x ptypes.DynamicAny
if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
fmt.Printf("unmarshaled message: %v", x.Message)

This is due to the use of the protoregistry.GlobalTypes inside ptypes.Empty (which in turn is used by ptypes.UnmarshalAny to generate an empty proto.Message for the type inside the TypeURL of the Any message).

As described below, I want to be able to inject my own registry and not rely on the global one for resolution.

Describe the solution you'd like

I have one way forward and two places it can be added, the solution is to add an UnmarshalAnyOptions/MarshalAnyOptions with a Resolver interface that can be supplied by the user, exactly the same as the implementation in protojson.

  1. Refactor the api inside ptypes/any.go (I assume you do not want to do this)
  2. Add this new functionality to the v2 API types package

Describe alternatives you've considered

I briefly considered using protoregistry.GlobalTypes throughout my application, but it does not support the following use case:

I have a new version of an existing MessageType (maybe with a field added) that needs to be registered that I want to replace the existing type.

The protoregistry.GlobalTypes does not support this because I cannot remove the old entry and if I register the new type it will be ignored with a type already registered error.

An alternative solution would be to extend the protoregistry.GlobalTypes to support removal/replacement of types, but this is a much larger change than the one I have proposed here. (although maybe necessary in future).

For now I have simply copied the UnmarshalAny / AnyMessage / Empty methods from the source into my application, where I can use my own registry instead of protoregistry.GlobalTypes.

Additional context
I am attempting to build a dynamic registry similar to the one mentioned in this tech blog by Deliveroo.

I am using this parser to read the protos from a GCS bucket when they are uploaded, and then using them to validate that the structure of incoming events is correct.

I am happy to provide a sample repository if the explanation given here is not sufficient to debug this issue.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions