Gradle で io.spring.dependency-management を導入したら Dependency Tree が変わってしまったけどそもそもそっちが正しかった話。

はー。。。マジカ。。。。勘弁してくれだった。

TL;DR
===
* `io.spring.dependency-management` を入れたときの挙動が正しい。
* `io.spring.dependency-management` を入れると、自分が DependencyManagement を使うだけでなく、依存関係の途中に DependencyManagement がる場合に Gradle がそれを正しく扱う。

発生したこと
===

`io.spring.dependency-management` なし
---
```
compileClasspath - Compile classpath for source set 'main'.
\--- org.glassfish.jersey.core:jersey-common:2.13
     +--- javax.ws.rs:javax.ws.rs-api:2.0.1
     +--- javax.annotation:javax.annotation-api:1.2
     +--- org.glassfish.jersey.bundles.repackaged:jersey-guava:2.13
     +--- org.glassfish.hk2:hk2-api:2.3.0-b10
     |    +--- javax.inject:javax.inject:1
     |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10
     |    |    \--- javax.inject:javax.inject:1
     |    \--- org.glassfish.hk2.external:aopalliance-repackaged:2.3.0-b10
     +--- org.glassfish.hk2.external:javax.inject:2.3.0-b10
     +--- org.glassfish.hk2:hk2-locator:2.3.0-b10
     |    +--- org.glassfish.hk2.external:javax.inject:2.3.0-b10
     |    +--- org.glassfish.hk2.external:aopalliance-repackaged:2.3.0-b10
     |    +--- org.glassfish.hk2:hk2-api:2.3.0-b10 (*)
     |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10 (*)
     |    \--- org.javassist:javassist:3.18.1-GA
     \--- org.glassfish.hk2:osgi-resource-locator:1.0.1
```

`io.spring.dependency-management` あり
---
```
compileClasspath - Compile classpath for source set 'main'.
\--- org.glassfish.jersey.core:jersey-common:2.13
     +--- javax.ws.rs:javax.ws.rs-api:2.0.1
     +--- javax.annotation:javax.annotation-api:1.2
     +--- org.glassfish.jersey.bundles.repackaged:jersey-guava:2.13
     +--- org.glassfish.hk2:hk2-api:2.3.0-b10
     |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10
     |    \--- org.glassfish.hk2.external:aopalliance-repackaged:2.3.0-b10
     +--- org.glassfish.hk2.external:javax.inject:2.3.0-b10
     +--- org.glassfish.hk2:hk2-locator:2.3.0-b10
     |    +--- org.glassfish.hk2.external:javax.inject:2.3.0-b10
     |    +--- org.glassfish.hk2.external:aopalliance-repackaged:2.3.0-b10
     |    +--- org.glassfish.hk2:hk2-api:2.3.0-b10 (*)
     |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10
     |    \--- org.javassist:javassist:3.18.1-GA
     \--- org.glassfish.hk2:osgi-resource-locator:1.0.1
```

`diff -U 5 plugin_without/dependencies.txt  plugin_with/dependencies.txt`
---
```diff
 compileOnly - Compile only dependencies for source set 'main'.
 No dependencies
@@ -41,20 +39,18 @@
 \--- org.glassfish.jersey.core:jersey-common:2.13
      +--- javax.ws.rs:javax.ws.rs-api:2.0.1
      +--- javax.annotation:javax.annotation-api:1.2
      +--- org.glassfish.jersey.bundles.repackaged:jersey-guava:2.13
      +--- org.glassfish.hk2:hk2-api:2.3.0-b10
-     |    +--- javax.inject:javax.inject:1
      |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10
-     |    |    \--- javax.inject:javax.inject:1
      |    \--- org.glassfish.hk2.external:aopalliance-repackaged:2.3.0-b10
      +--- org.glassfish.hk2.external:javax.inject:2.3.0-b10
      +--- org.glassfish.hk2:hk2-locator:2.3.0-b10
      |    +--- org.glassfish.hk2.external:javax.inject:2.3.0-b10
      |    +--- org.glassfish.hk2.external:aopalliance-repackaged:2.3.0-b10
      |    +--- org.glassfish.hk2:hk2-api:2.3.0-b10 (*)
-     |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10 (*)
+     |    +--- org.glassfish.hk2:hk2-utils:2.3.0-b10
      |    \--- org.javassist:javassist:3.18.1-GA
      \--- org.glassfish.hk2:osgi-resource-locator:1.0.1
```

はぁ、なんで、、、ニンジャナンデ。。。



Debug
====
右クリックから Debug できるって聞いたが。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/0570b38d-9f82-ccbb-86d2-6b8447982d2d.png)

なんか上手くいかない

改めて見ると
====

依存関係にも気になるところが無いわけでは無い

`org.glassfish.hk2:hk2-api:2.3.0-b10` -> Beta?

まぁいいけど。

pom.xml of `org.glassfish.hk2:hk2-api:2.3.0-b10`
====
* https://repo1.maven.org/maven2/org/glassfish/hk2/hk2-api/2.3.0-b10/hk2-api-2.3.0-b10.pom

```xml://repo1.maven.org/maven2/org/glassfish/hk2/hk2-api/2.3.0-b10/hk2-api-2.3.0-b10.pom
	<dependencies>
		<dependency>
			<groupId>org.glassfish.hk2</groupId>
			<artifactId>osgi-resource-locator</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
		</dependency>
		<dependency>
			<groupId>org.glassfish.hk2</groupId>
			<artifactId>hk2-utils</artifactId>
		</dependency>
		<dependency>
			<groupId>org.glassfish.hk2.external</groupId>
			<artifactId>aopalliance-repackaged</artifactId>
		</dependency>
	</dependencies>
```

普通に依存してるって書いてあるが。。。Exclude も無いし。

--debug 実行してみる
=====
```
% ./gradlew dependencies --debug

11:34:46.517 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder] javax.inject:javax.inject is excluded from org.glassfish.hk2:hk2-api:2.3.0-b10(compile) by {"exclude module id" : "javax.inject:javax.inject"}.
```

確かに意図通りに exclude してるっぽい。

[gradle/DependencyGraphBuilder\.java at v5\.6\.3 · gradle/gradle](https://github.com/gradle/gradle/blob/v5.6.3/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/builder/DependencyGraphBuilder.java) でもこのファイルに `is excluded` の文字が無いから手詰まり感。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/44d42f3a-4392-1006-ed9e-b73800712d06.png)

ここかー [gradle/NodeState\.java at v5\.6\.3 · gradle/gradle](https://github.com/gradle/gradle/blob/v5.6.3/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/builder/NodeState.java#L560)

いやだから LOGGER を手書きするのは駄目だって。。。 [gradle/NodeState\.java at v5\.6\.3 · gradle/gradle](https://github.com/gradle/gradle/blob/v5.6.3/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/ivyservice/resolveengine/graph/builder/NodeState.java#L66-L67)


Debug してみる
=====
うまくソースがあたらないんで、以下二つはローカルビルドした

* https://github.com/gradle/gradle
* https://github.com/spring-gradle-plugins/dependency-management-plugin

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/4ff7bd5a-2eab-ca00-274a-1437d09fa0f2.png)


がっつり exclude してる。

## visitOutgoingDependencies:253
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/4d1a7ee2-0051-a129-48ee-159f70a02f7a.png)

```
visitOutgoingDependencies:253, NodeState (org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder)
traverseGraph:180, DependencyGraphBuilder (org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder)
resolve:142, DependencyGraphBuilder (org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder)
resolve:123, DefaultArtifactDependencyResolver (org.gradle.api.internal.artifacts.ivyservice.resolveengine)
resolveGraph:175, DefaultConfigurationResolver (org.gradle.api.internal.artifacts.ivyservice)
resolveGraph:86, ShortCircuitEmptyConfigurationResolver (org.gradle.api.internal.artifacts.ivyservice)
resolveGraph:74, ErrorHandlingConfigurationResolver (org.gradle.api.internal.artifacts.ivyservice)
run:612, DefaultConfiguration$7 (org.gradle.api.internal.artifacts.configurations)
execute:402, DefaultBuildOperationExecutor$RunnableBuildOperationWorker (org.gradle.internal.operations)
execute:394, DefaultBuildOperationExecutor$RunnableBuildOperationWorker (org.gradle.internal.operations)
```

## 気付いた時にはもう `MavenDependencyDescriptor#excludes` に入っている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/ff4be10a-486f-c181-3130-ab67133a68a3.png)



pom.xml of jersey-common
====
* [<groupId>org\.glassfish\.jersey\.core</groupId>:<artifactId>jersey\-common</artifactId>:2.13](http://central.maven.org/maven2/org/glassfish/jersey/core/jersey-common/2.13/jersey-common-2.13.pom)
  * Parent: [<groupId>org\.glassfish\.jersey</groupId>:<artifactId>project</artifactId>:<version>2\.13</version>](http://central.maven.org/maven2/org/glassfish/jersey/project/2.13/project-2.13.pom)

はぁーなるほどね。。。

```xml
	<dependencyManagement>
		<dependencies>
			...
			<dependency>
				<groupId>org.glassfish.hk2</groupId>
				<artifactId>hk2-api</artifactId>
				<version>${hk2.version}</version>
				<exclusions>
					<exclusion>
						<groupId>javax.inject</groupId>
						<artifactId>javax.inject</artifactId>
					</exclusion>
				</exclusions>
			</dependency>
```


実際の所
=====

* `io.spring.dependency-management` を入れたときの挙動が正しい
* gradle 単体だと、exclude は読むが、依存の途中にある dependencyManagement を考慮しない
* 今回の例では `org.glassfish.jersey.core:jersey-common:2.13` -> `org.glassfish.hk2:hk2-api:2.3.0-b10` -> `javax.inject:javax.inject:1` の異存があるが、 `jersey-common` が `hk2-api` に依存する際に、`javax.inject:javax.inject` への依存を外している。（代わりに `org.glassfish.hk2.external:javax.inject` への実装がはいっているからこれはこれでよい）
  * 更に言うと、この dependencyManagement が parent pom に入ってるからハマった。。。 [<groupId>org\.glassfish\.jersey</groupId>:<artifactId>project</artifactId>:<version>2\.13</version>](http://central.maven.org/maven2/org/glassfish/jersey/project/2.13/project-2.13.pom)