天天看點

記一次 Gradle Build 問題分析

問題出現

一次項目更新後,發現項目無法正常 build 了,出現如下報錯:

error: cannot access DoNotMock
  class file for com.google.errorprone.annotations.DoNotMock not found
           

定位問題

  1. Review 代碼更新,尋找可疑點

    這一步 review 沒有發現什麼特殊的改動,隻是更改了幾個 proto 檔案的定義。但是回退代碼後卻又能正常 build,是以說明建構失敗的确是此次更新引入的問題。

  2. 根據報錯資訊尋找問題根源
    1. 尋找錯誤包

      看錯誤是類找不到的問題,那麼首先确定這個類是哪個包的;Google 了下,該類出現在 error-prone , 并且發現

      DoNotMock

      從 2.3.0 開始就被移除掉了,相關讨論見 GITHUB
      <dependency>
            <groupId>com.google.errorprone</groupId>
            <artifactId>error_prone_annotations</artifactId>
            <version>2.2.0</version>
       </dependency>    
                 
    2. 分析包依賴

      從上面其實就可以看出這應該是一個依賴包不對帶來的問題。那麼此時就需要分析項目的依賴。重點檢視 error_prone_annotations 的相關依賴。分析如下(本來在 console 中 error_prone_annotations 有高亮的,貼上來就沒有了):

      $ ./gradlew dependencies -q --configuration compile | grep error_prone_annotations --color -C 10
      compile - Dependencies for source set 'main' (deprecated, use 'implementation' instead).
      +--- net.xxxx.mshell:mshell-java-dropwizard-core:10.0.0
      |    +--- io.dropwizard:dropwizard-core:1.3.13
      |    |    +--- io.dropwizard:dropwizard-util:1.3.13
      |    |    |    +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 -> 2.9.9
      |    |    |    +--- com.google.guava:guava:24.1.1-jre -> 27.1-jre
      |    |    |    |    +--- com.google.guava:failureaccess:1.0.1
      |    |    |    |    +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
      |    |    |    |    +--- com.google.code.findbugs:jsr305:3.0.2
      |    |    |    |    +--- org.checkerframework:checker-qual:2.5.2
      |    |    |    |    +--- com.google.errorprone:error_prone_annotations:2.2.0 -> 2.3.2 # here use error_prone_annotations 2.3.2
      |    |    |    |    +--- com.google.j2objc:j2objc-annotations:1.1
      |    |    |    |    \--- org.codehaus.mojo:animal-sniffer-annotations:1.17
      |    |    |    +--- com.google.code.findbugs:jsr305:3.0.2
      |    |    |    \--- joda-time:joda-time:2.10.1
      |    |    +--- io.dropwizard:dropwizard-jackson:1.3.13
      |    |    |    +--- com.google.guava:guava:24.1.1-jre -> 27.1-jre (*)
      |    |    |    +--- io.dropwizard:dropwizard-util:1.3.13 (*)
      |    |    |    +--- com.fasterxml.jackson.core:jackson-core:2.9.9
      |    |    |    +--- com.fasterxml.jackson.core:jackson-annotations:2.9.0 -> 2.9.9
      |    |    |    +--- com.fasterxml.jackson.core:jackson-databind:2.9.9.1
      --
      --
      |    |    |    |    +--- io.dropwizard:dropwizard-configuration:1.3.5 -> 1.3.13 (*)
      |    |    |    |    \--- org.apache.commons:commons-lang3:3.4 -> 3.8.1
      |    |    |    +--- com.google.protobuf:protobuf-java:3.6.0 -> 3.8.0
      |    |    |    \--- net.jodah:failsafe:2.0.1
      |    |    +--- net.xxxx.experimentation:java-mr-hyde-client:0.5.1 (*)
      |    |    +--- io.dropwizard:dropwizard-logging:1.3.13 (*)
      |    |    +--- io.dropwizard:dropwizard-configuration:1.3.13 (*)
      |    |    +--- io.dropwizard:dropwizard-metrics:1.3.13 (*)
      |    |    +--- io.dropwizard.metrics:metrics-healthchecks:4.0.2 -> 4.0.5 (*)
      |    |    +--- org.slf4j:jcl-over-slf4j:1.7.25 -> 1.7.26 (*)
      |    |    \--- com.google.errorprone:error_prone_annotations:2.0.12 -> 2.3.2  # here use error_prone_annotations 2.3.2
      |    +--- net.xxxx.mshell:mshell-java-secrets:10.0.0 (*)
      |    +--- net.xxxx.mshell:mshell-java-metrics:10.0.0 (*)
      |    +--- net.xxxx.mshell:mshell-java-async-client:10.0.0
      |    |    +--- org.asynchttpclient:async-http-client:2.4.9
      |    |    |    +--- org.asynchttpclient:async-http-client-netty-utils:2.4.9
      |    |    |    |    +--- io.netty:netty-buffer:4.1.25.Final
      |    |    |    |    |    \--- io.netty:netty-common:4.1.25.Final
      |    |    |    |    +--- org.slf4j:slf4j-api:1.7.25 -> 1.7.26
      |    |    |    |    \--- com.sun.activation:javax.activation:1.2.0
      |    |    |    +--- io.netty:netty-codec-http:4.1.25.Final
      --
      --
      |    |    |    +--- com.lightstep.tracer:java-common:0.15.8
      |    |    |    |    +--- io.opentracing:opentracing-api:0.31.0
      |    |    |    |    +--- io.opentracing:opentracing-util:0.31.0 (*)
      |    |    |    |    +--- com.google.protobuf:protobuf-java:3.5.1 -> 3.8.0
      |    |    |    |    \--- com.google.api.grpc:grpc-google-common-protos:1.12.0
      |    |    |    |         +--- io.grpc:grpc-stub:1.10.1 -> 1.13.2
      |    |    |    |         |    \--- io.grpc:grpc-core:1.13.2
      |    |    |    |         |         +--- io.grpc:grpc-context:1.13.2
      |    |    |    |         |         +--- com.google.code.gson:gson:2.7
      |    |    |    |         |         +--- com.google.guava:guava:20.0 -> 27.1-jre (*)
      |    |    |    |         |         +--- com.google.errorprone:error_prone_annotations:2.1.2 -> 2.3.2 # here use error_prone_annotations 2.3
      |    |    |    |         |         +--- com.google.code.findbugs:jsr305:3.0.0 -> 3.0.2
      |    |    |    |         |         +--- io.opencensus:opencensus-api:0.12.3
      |    |    |    |         |         \--- io.opencensus:opencensus-contrib-grpc-metrics:0.12.3
      |    |    |    |         |              \--- io.opencensus:opencensus-api:0.12.3
      |    |    |    |         +--- io.grpc:grpc-protobuf:1.10.1 -> 1.13.2
      |    |    |    |         |    +--- io.grpc:grpc-core:1.13.2 (*)
      |    |    |    |         |    +--- com.google.protobuf:protobuf-java:3.5.1 -> 3.8.0
      |    |    |    |         |    +--- com.google.guava:guava:20.0 -> 27.1-jre (*)
      |    |    |    |         |    +--- com.google.api.grpc:proto-google-common-protos:1.0.0 -> 1.12.0
      |    |    |    |         |    |    \--- com.google.protobuf:protobuf-java:3.5.1 -> 3.8.0
      --
      --
      |    |    +--- io.prometheus:simpleclient:0.6.0
      |    |    \--- io.dropwizard.metrics:metrics-core:3.1.2 -> 4.0.5 (*)
      |    \--- javax.xml.bind:jaxb-api:2.3.1
      |         \--- javax.activation:javax.activation-api:1.2.0
      \--- io.dropwizard.modules:dropwizard-protobuf:1.3.12-1
           +--- io.dropwizard:dropwizard-core:1.3.12 -> 1.3.13 (*)
           +--- com.google.protobuf:protobuf-java:3.8.0
           \--- com.google.protobuf:protobuf-java-util:3.8.0
                +--- com.google.protobuf:protobuf-java:3.8.0
                +--- com.google.guava:guava:26.0-android -> 27.1-jre (*)
                +--- com.google.errorprone:error_prone_annotations:2.3.2    # here use error_prone_annotations 2.3
                \--- com.google.code.gson:gson:2.7
                 
      從上面可以看出,最終用的是 2.3.2 的

      error_prone_annotations

      ,該版本中是沒有

      DoNotMock

      注解的。而 2.3.2 版本的

      error_prone_annotations

      是由

      protobuf-java-util:3.8.0

      引入。至此找到問題所在。就是包依賴的問題

解決問題

在上一步中已已經确定問題點,就是包依賴導緻的問題。那麼我們便可以着手解決問題,該問題可以有三個解決方案:

  1. 編譯時強制使用含

    DoNotMock

    error_prone_annotations

    implementation('com.google.errorprone:error_prone_annotations:2.2.0') {
        force = true
    }
               
  2. 在依賴中移除

    error_prone_annotations:2.3.2

    compile ("io.dropwizard.modules:dropwizard-protobuf:${dropwizardProtobufVersion}") {
        exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
    }
               
  3. 更新所有依賴

    error_prone_annotations

    的包,更新到新版不使用

    DoNotMock

    ;該方案影響較大。需要先全局查找使用了

    DoNotMock

    的包。然後分析其使用依賴,再判斷是否能更新。

回顧問題

問題是解決了,但是有個疑問。此次更新中,我們并沒有更新相關的包依賴,為何以前 build 的時候沒有出錯,而這次卻出錯了呢?

這邊再次 Review 了下更新的代碼,再結合此前對包依賴的分析,發現了問題所在。此次更新中,我們在 proto 檔案中定義了 grpc 接口服務,而此服務的編譯依賴包

io.grpc

;即編譯 grpc 接口服務的包需要使用到相關的類,而這些類中有些使用了

DoNotMock

。而不幸的是,我們引用的其他包中使用了更新的

error_prone_annotations

,然該包中又不含

DoNotMock

,進而導緻了編譯錯誤。

error: cannot access DoNotMock
  class file for com.google.errorprone.annotations.DoNotMock not found
           

繼續閱讀