1. 程式人生 > 其它 >maven protobuf 編譯外掛使用 (2)

maven protobuf 編譯外掛使用 (2)

問題

maven protobuf 編譯外掛使用 (1)之後,使用maven外掛編譯.proto檔案時,遇到如下問題

xxx.proto:12:9: "XXX" is already defined in file "xxx.proto".

外掛如下

<plugin>
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.5.1</version>
</plugin>

原因

出現這個問題,就是因為外掛指定的protoSourceRoot目錄中,多個.proto檔案含有相同名稱message體定義。
例如,目錄中存在如下student.proto後teacher.proto兩個檔案,都有相同的message Address。

syntax = "proto3";

option java_package = "me.fengfshao.pb";
option java_outer_classname = "TeacherProto";

message Teacher{
  string name=1;
  Address address=2;
  uint32 age=3;
}

message Address{
  string province=1;
  string street=2;
  string neighborName=3;
}
syntax = "proto3";

option java_package = "me.fengfshao.pb";
option java_outer_classname = "StudentProto";

message Student{
  string name=1;
  string address=2;
  uint32 age=3;
}

message Address{
  string province=1;
  string street=2;
}

此時使用上述外掛進行proto編譯時,就會出現上面的問題。

分析

為了解決這個問題,最簡單的方式是可以選擇使用巢狀結構,如將上述定義改為如下:

syntax = "proto3";

option java_package = "me.fengfshao.pb";
option java_outer_classname = "StudentProto";

message Student{
  string name=1;
  string address=2;
  uint32 age=3;

  message Address{
    string province=1;
    string street=2;
  }
}

對於我的場景到,如果改成巢狀結構,大量的歷史pb程式碼需要改動,就沒有這樣做。
在google後,發現了這個issue,從這段話可以看出來,這個人遷到gradle之前用的maven外掛不會產生這個問題

於是嘗試了外掛的老版本,發現依然產生這個問題,後來在這個外掛github倉庫中發現它fork自另一個專案
這個maven外掛經驗證,支援proto原始檔目錄中有不同的protobuf檔案存在同樣的message定義體

解決

maven外掛替換為下面這個,由於內部實現不同,該外掛即使protobuf目錄中有多個protobuf檔案存在同樣的message定義體,也不會有問題。
具體的配置如下:

<plugin>
    <groupId>com.github.igor-petruk.protobuf</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.6.5</version>
    <configuration>
        <!--預設是protoc,即/usr/bin/local/protoc-->
        <protocCommand>${project.basedir}/protoc</protocCommand>
        <!--inputDirectories,預設src/main/protobuf-->
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <cleanOutputFolder>false</cleanOutputFolder>
    </configuration>
    <executions>
        <execution>
            <phase>process-sources</phase>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin>