记一次 Gradle Build 问题分析
问题出现
一次项目更新后,发现项目无法正常 build 了,出现如下报错:
1 | error: cannot access DoNotMock |
问题定位
Review 代码更新,寻找可疑点
这一步 review 没有发现什么特殊的改动,只是更改了几个 proto 文件的定义。但是回退代码后却又能正常 build,所以说明构建失败的确是此次更新引入的问题。
根据报错信息寻找问题根源
寻找错误包
看错误是类找不到的问题,那么首先确定这个类是哪个包的;Google 了下,该类出现在 error-prone , 并且发现
DoNotMock
从 2.3.0 开始就被移除掉了,相关讨论见 GITHUB1
2
3
4
5<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
<version>2.2.0</version>
</dependency>分析包依赖
从上面其实就可以看出这应该是一个依赖包不对带来的问题。那么此时就需要分析项目的依赖。重点查看 error_prone_annotations 的相关依赖。分析如下(本来在 console 中 error_prone_annotations 有高亮的,贴上来就没有了):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82$ ./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
引入。至此找到问题所在。就是包依赖的问题
问题解决
在上一步中已已经确定问题点,就是包依赖导致的问题。那么我们便可以着手解决问题,该问题可以有三个解决方案:
- 编译时强制使用含
DoNotMock
的error_prone_annotations
1
2
3implementation('com.google.errorprone:error_prone_annotations:2.2.0') {
force = true
} - 在依赖中移除
error_prone_annotations:2.3.2
1
2
3compile ("io.dropwizard.modules:dropwizard-protobuf:${dropwizardProtobufVersion}") {
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
} - 升级所有依赖
error_prone_annotations
的包,升级到新版不使用DoNotMock
;该方案影响较大。需要先全局查找使用了DoNotMock
的包。然后分析其使用依赖,再判断是否能升级。
问题回顾
问题是解决了,但是有个疑问。此次更新中,我们并没有更新相关的包依赖,为何以前 build 的时候没有出错,而这次却出错了呢?
这边再次 Review 了下更新的代码,再结合此前对包依赖的分析,发现了问题所在。此次更新中,我们在 proto 文件中定义了 grpc 接口服务,而此服务的编译依赖包 io.grpc
;即编译 grpc 接口服务的包需要使用到相关的类,而这些类中有些使用了 DoNotMock
。而不幸的是,我们引用的其他包中使用了更新的 error_prone_annotations
,然该包中又不含 DoNotMock
,从而导致了编译错误。
1 | error: cannot access DoNotMock |