Roger Johansson
Roger Johansson

Reputation: 23214

proto.MessageName returns empty string

I'm completely stuck on a problem with Protobuf in Go

Given the following bit of code:

if proto.MessageName(&messages.AddedItemEvent{}) == "" {
    log.Fatal("empty")
}

This will evaluate to true and exit the application. What can possibly make protobuf return empty string on MessageName? I can see that the types and their names are registered as they should in the generated protobuf message code:

func init() {
    proto.RegisterType((*AddItemCommand)(nil), "messages.AddItemCommand")
    proto.RegisterType((*AddedItemEvent)(nil), "messages.AddedItemEvent")
    proto.RegisterType((*RenameCommand)(nil), "messages.RenameCommand")
    proto.RegisterType((*RenamedEvent)(nil), "messages.RenamedEvent")
    proto.RegisterType((*DumpCommand)(nil), "messages.DumpCommand")
}

I have also verified that the above init actually runs, and it does.

I have other generated proto messages, which returns their names as expected. So what is going wrong here?

Edit The protofile looks like this

syntax = "proto3";
package messages;

//user messages
message AddItemCommand {
  string item = 1;
}
message AddedItemEvent {
  string item = 1;
}
message RenameCommand {
  string name = 1;
}
message RenamedEvent {
  string name = 1;
}
message DumpCommand {}

Edit again. Manually calling proto.RegisterType((*messages.AddedItemEvent)(nil), "messages.AddedItemEvent")

From the main func, makes it work. So somehow the type registry is cleared somewhere between the messages.init and main

Anyone?

Upvotes: 3

Views: 2005

Answers (1)

Mark Novikov
Mark Novikov

Reputation: 11

No, type registry isn't cleared.

Most probably you are using different implementations of proto package in your generated code, where proto package implementation choice is addressed by your proto code generator of choice. In your code you are actually trying to get MessageName.

Each imported package in Go is initialized exactly one time during the go binary process lifetime. Each initialized package has it's own table of names (both exported and unexported) and their corresponding values. proto package in particular maintains so called "registry" of known proto message names and types. A bit simplified, registry is a package-scoped map associating message types with their corresponding names. This map is initialized and populated on package initialization. Then, to retrieve MessageName you access it indirectly through some helper function. The key point is, if you use different proto package implementations imported in your code, your generated code, or in your dependencies, then chances are, on app start you populate one registry, and then later on, you are trying to retrieve MessageName from some other registry that know nothing about it. The rule of thumb is to always use protoc code generator plugin, pregenerated proto type libraries, and proto package implementation from a single vendor through out your app.

Most popular proto packages (I've never used or encountered any other) are https://github.com/golang/protobuf and https://github.com/gogo/protobuf. Double check your protoc generator plugin and package imports and I hope it'll be all fine.

Upvotes: 1

Related Questions