javaprotocol-buffersjava-11protoprotoc

proto3: Why setting java_multiple_files = true not creating separate java classes for each proto message?


I have a proto definition with nested classes

syntax = "proto3";

option java_package = "com.spot.proto.v1.config";

package v1config;

// ClusterConfig proto is used to maintain the params required by all the services at a central place.
message ClusterConfig {
  enum LogLevel {
    UNKNOWN_TYPE = 0;
    DEBUG = 1;
    INFO = 2;
    WARN = 3;
    ERROR = 4;
    FATAL = 5;
  }

  message Network {
    string ip = 1;
    int32 port = 2;
  }

  message Constants {
    message SlackNotifier {
      message Channel {
        string name = 1;
      }
      string auth_token = 1;
      map<string, Channel> channels = 2;
      bool is_enabled = 3;
    }

    message Kafka {
      string broker_list = 1;
    }

    Kafka kafka = 2;
   }
   message Support {
      Network network = 1;
   }
   Support support = 1;
    ...  
  }

When I generate the java classes with option java_multiple_files = false; it creates a single java class, ClusterConfigOuterClass.java with all the Java classes/enums/etc generated for the top-level messages, services, and enumerations nested inside it. This is expected.

But if I use option java_multiple_files = true; then I am seeing it is generating two additional classes ClusterConfig.java, ClusterConfigOrBuilder.java along with ClusterConfigOuterClass.java. ClusteConfig.java now contains the nested classes.

The documentation states like below:-

java_multiple_files (file option): If false, only a single .java file will be generated for this .proto file, and all the Java classes/enums/etc. generated for the top-level messages, services, and enumerations will be nested inside of an outer class (see java_outer_classname). If true, separate .java files will be generated for each of the Java classes/enums/etc. generated for the top-level messages, services, and enumerations, and the wrapper Java class generated for this .proto file won't contain any nested classes/enums/etc. This is a Boolean option that defaults to false. If not generating Java code, this option has no effect.

So should not each nested message like Kafka, Network, etc go into a separate java file?


Solution

  • With only Nested classes, the java_multiple_files will not do anything, and this is on purpose. You are explicitly giving a context for Kafka, Network, etc... They are relevant only in their parent object.

    Now, if you really wanted to generate multiple files, you would have to do something like:

    enum LogLevel {
      UNKNOWN_TYPE = 0;
      DEBUG = 1;
      INFO = 2;
      WARN = 3;
      ERROR = 4;
      FATAL = 5;
    }
    
    message Channel {
      string name = 1;
    }
    
    message SlackNotifier {
      string auth_token = 1;
      map<string, Channel> channels = 2;
      bool is_enabled = 3;
    }
    
    message Kafka {
      string broker_list = 1;
    }
    
    message Constants {
      Kafka kafka = 2;
    }
    
    message Network {
      string ip = 1;
      int32 port = 2;
    }
    
    message Support {
      Network network = 1;
    }
    
    message ClusterConfig {
      Support support = 1;
      //...
    }
    

    Then, to go further, if you wanted to give them a Context in which these objects should be used (maybe because you have team, and you don't want other developers to misuse these objects), you could put them in a package like:

    package mycompany.service.cluster
    

    and then to use your Kafka object for example, they will need to give the fully qualified type (except if they are in the same package):

    mycompany.service.cluster.Kafka