use of custom field-options during code-generation

1,073 views
Skip to first unread message

Leo Hilbert

unread,
Nov 25, 2019, 3:28:35 PM11/25/19
to Protocol Buffers
Hi guys,

Background:
I'm currently building/prototyping a modified version of the protoc java-compiler. I need to change some things from the standard-implementation for my usecase, but want to keep most of it.
To avoid starting from scratch I copied the java-generation-code to my own project and started to modify it. I'm a java-dev, so C++ proves to be quite the challenge, but I'm learning a lot and am nearly finished with what I wanted to do. However now I'm stuck and need your help.

Here is a quick overview of the relevant folders in my project ( https://github.com/leohilbert/protoc-gen-java-leo ):
  • include-folder: "h-files" that I copied over (otherwise no classes from the protoc-libraries were found)
  • java-folder: for my java-library. Also contains my test-proto-files for now (java/src/test/proto).
  • src/google/protobuf/compiler/java_leo: copied and modifed java-generation code from the official repo
  • src/javaleo/proto: the generated c++ code for my custom FieldOption (java/src/test/proto/options.proto)
btw: if you have any feedback on my setup, it's greatly appreciated! I'm a C++ noob and trying to understand everything as I go. :) 

Now to my actual problem:
If you navigate to src/google/protobuf/compiler/java_leo/java_field.cc in line 64 you can see that I'm trying to read the value from my custom-field option by calling 
string test = field->options().GetExtension(javaleo::proto::javatype);

This is always empty. Although I imported and used this exact custom FieldOption in my addressbook.proto.
The C++-Class for the option.proto is also generated and add in the CMakeList (src/javaleo/proto).
"javaleo::proto::javatype" does compile, so at least it seems to be in the executable somewhere.

What makes me suspicious is that I did not register this custom-extension anywhere in my code. I'm thinking of something like "ExtensionRegistry.registerExtension(javaleo::proto::javatype);" to add to the beginning of my plugin (main.cpp). Otherwise how should protoc know how this field should be interpreted. Am I on the right track here, or did I understand this whole system wrong.

I debugged this a lot already and am running out of ideas. Searching for a solution online is also really tricky, because not a lot of people have compiled there own protoc-compiler.. But maybe I'm looking in the wrong direction.

I hope my issue is somewhat clear, it's hard describing it when knowing so little about c++ and how protoc works internally.. ^^

TLDR: I need to get the value of my custom-option during code-generation, but my field-option is always ignored. Help :c

Adam Cozzette

unread,
Nov 25, 2019, 4:40:41 PM11/25/19
to Leo Hilbert, Protocol Buffers
Your code looks right as far as I can tell. In C++ there's no need to manually register extensions because they register themselves before main() begins. Could you try calling DebugString() on the FieldDescriptor that you expect to have the extension? Seeing a human-readable summary of that descriptor might offer some insight.

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/protobuf/8135f496-9ec3-4e0d-bff2-dd37d85792bc%40googlegroups.com.

Leo Hilbert

unread,
Nov 26, 2019, 4:58:42 AM11/26/19
to Protocol Buffers
Hi, sure! 
It returns:
"string id = 1[json_name = \"id\", (.javaleo.proto.javatype) = \"uuid\"];\n"

I also attached a screenshot of the field where you can see that options->_extensions_ is empty.

Bildschirmfoto 2019-11-26 um 10.54.35.png

The line in the proto-file looks like this:

string id = 1 [(javaleo.proto.javatype) = "uuid"];



To unsubscribe from this group and stop receiving emails from it, send an email to prot...@googlegroups.com.

Adam Cozzette

unread,
Nov 26, 2019, 12:18:04 PM11/26/19
to Leo Hilbert, Protocol Buffers
I wonder if the parser put it in the uninterpreted_option field within FieldOptions. Could you try also printing out field->options().DebugString()?

To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/protobuf/0fe72ed2-c773-4233-9572-0ba2c1ccc657%40googlegroups.com.

Leo Hilbert

unread,
Nov 27, 2019, 7:02:42 AM11/27/19
to Protocol Buffers
field->options().DebugString()
returns
"51234: \"uuid\"\n"

So he even got the ID right that is defined here:
syntax = "proto3";
import "google/protobuf/descriptor.proto";

package javaleo.proto;

extend google
.protobuf.FieldOptions {
   
string javatype = 51234;
}


Leo Hilbert

unread,
Dec 19, 2019, 6:43:00 AM12/19/19
to Protocol Buffers
Hi all, I was able to solve it with the awesome tip I found in https://github.com/protocolbuffers/protobuf/issues/4925
It turns out I had set the "protobuf-lite"-library as a target_link_library although I didn't even use it anywhere.
After removing it the field-option is now displayed correctly. :)

One more thing: Does somebody have an idea on how to shorten my option-declaration.
My field now looks like this
string id = 1 [(javaleo.proto.javatype) = "java.util.UUID"];

For example I can shorten my package from "javaleo.proto" to "leo". Or better, is there a way to "statically import" an option, so that I only need to write "(javatype) = ..."?
Also can I generify the "java.util.UUID"-string into a constant that I can reuse? I'm thinking about something like a enum with a value.


Optimally it should something look like this
string id = 1 [javatype = UUID];

with a enum
enum Types {
    UUID
= 0 [name="java.util.UUID"];
}

If this is not possible, I will simply copy paste the same string everywhere, just wondering if there's a better fay :)
Reply all
Reply to author
Forward
0 new messages