Search code examples
javaprotocol-buffersprotocolsprotoc

Java : Proto parser library


I want to parse a proto file. Wanted to check is there any java library available which can parse proto files. Based on my requirement I cannot use descriptor parseFrom method or protoc command. Please suggest thanks in advance.

$ protoc --include_imports --descriptor_set_out temp *.proto // I don't want to do this manual step 
or 
DescriptorProtos.FileDescriptorProto descriptorProto = DescriptorProtos.FileDescriptorProto.parseFrom(proto.getBytes());

Appreciate suggestion thanks


Solution

  • Possible solution: io.protostuff:protostuff-parser library

    Let's consider the 3.1.38 version of the io.protostuff:protostuff-parser library as the current version.

    Example program

    Please, consider the below example program as a draft to get started with the library.

    Input file

    Let's assume the /some/directory/data/test.proto file exist with the following content:

    message SearchRequest {
      string query = 1;
      int32 page_number = 2;
      int32 result_per_page = 3;
      enum ContentType {
        WEB = 1;
        IMAGES = 2;
        VIDEO = 3;
      }
      ContentType content_type = 4;
    }
    

    pom.xml: Dependencies

    <project>
        <dependencies>
            <dependency>
                <groupId>io.protostuff</groupId>
                <artifactId>protostuff-parser</artifactId>
                <version>3.1.38</version>
            </dependency>
            <dependency>
                <groupId>com.google.inject</groupId>
                <artifactId>guice</artifactId>
                <version>5.1.0</version>
            </dependency>
        </dependencies>
    </project>
    

    Program

    import com.google.inject.Guice;
    import com.google.inject.Injector;
    import io.protostuff.compiler.ParserModule;
    import io.protostuff.compiler.model.Message;
    import io.protostuff.compiler.model.Proto;
    import io.protostuff.compiler.parser.Importer;
    import io.protostuff.compiler.parser.LocalFileReader;
    import io.protostuff.compiler.parser.ProtoContext;
    import java.nio.file.Path;
    import java.util.List;
    
    public final class Program {
        public static void main(final String[] args) {
            final Injector injector = Guice.createInjector(new ParserModule());
            final Importer importer = injector.getInstance(Importer.class);
            final ProtoContext protoContext = importer.importFile(
                new LocalFileReader(Path.of("/some/directory/data")),
                "test.proto"
            );
    
            final Proto proto = protoContext.getProto();
    
            final List<Message> messages = proto.getMessages();
            System.out.println(String.format("Messages: %s", messages));
    
            final Message searchRequestMessage = proto.getMessage("SearchRequest");
            System.out.println(String.format("SearchRequest message: %s", searchRequestMessage));
    
            final List<Enum> searchRequestMessageEnums = searchRequestMessage.getEnums();
            System.out.println(String.format("SearchRequest message enums: %s", searchRequestMessageEnums));
        }
    }
    

    The program output:

    Messages: [Message{name=SearchRequest, fullyQualifiedName=..SearchRequest, fields=[Field{name=query, typeName=string, tag=1, options=DynamicMessage{fields={}}}, Field{name=page_number, typeName=int32, tag=2, options=DynamicMessage{fields={}}}, Field{name=result_per_page, typeName=int32, tag=3, options=DynamicMessage{fields={}}}, Field{name=content_type, typeName=ContentType, tag=4, options=DynamicMessage{fields={}}}], enums=[Enum{name=ContentType, fullyQualifiedName=..SearchRequest.ContentType, constants=[EnumConstant{name=WEB, value=1, options=DynamicMessage{fields={}}}, EnumConstant{name=IMAGES, value=2, options=DynamicMessage{fields={}}}, EnumConstant{name=VIDEO, value=3, options=DynamicMessage{fields={}}}], options=DynamicMessage{fields={}}}], options=DynamicMessage{fields={}}}]
    SearchRequest message: Message{name=SearchRequest, fullyQualifiedName=..SearchRequest, fields=[Field{name=query, typeName=string, tag=1, options=DynamicMessage{fields={}}}, Field{name=page_number, typeName=int32, tag=2, options=DynamicMessage{fields={}}}, Field{name=result_per_page, typeName=int32, tag=3, options=DynamicMessage{fields={}}}, Field{name=content_type, typeName=ContentType, tag=4, options=DynamicMessage{fields={}}}], enums=[Enum{name=ContentType, fullyQualifiedName=..SearchRequest.ContentType, constants=[EnumConstant{name=WEB, value=1, options=DynamicMessage{fields={}}}, EnumConstant{name=IMAGES, value=2, options=DynamicMessage{fields={}}}, EnumConstant{name=VIDEO, value=3, options=DynamicMessage{fields={}}}], options=DynamicMessage{fields={}}}], options=DynamicMessage{fields={}}}
    SearchRequest message enums: [Enum{name=ContentType, fullyQualifiedName=..SearchRequest.ContentType, constants=[EnumConstant{name=WEB, value=1, options=DynamicMessage{fields={}}}, EnumConstant{name=IMAGES, value=2, options=DynamicMessage{fields={}}}, EnumConstant{name=VIDEO, value=3, options=DynamicMessage{fields={}}}], options=DynamicMessage{fields={}}}]