Gradle — scope зависимостей в опубликованных артефактах

При публикации Gradle-модуля в Maven-репозиторий scope зависимостей маппится в POM иначе, чем он работает локально.

Маппинг Gradle → Maven POM

Gradle scopeMaven POM scopeВидимость для потребителя
apicompilecompile + runtime
implementationruntimeтолько runtime
compileOnly— (не попадает в POM)невидима
runtimeOnlyruntimeтолько runtime
compileOnlyApiprovided (в Gradle module metadata)только compile

Главный gotcha

implementation не скрывает зависимость от потребителя в опубликованном артефакте. Она попадает в POM как runtime и будет на runtime classpath всех потребителей.

implementation скрывает зависимость только на этапе компиляции у потребителя (классы не видны в IDE, не компилируются напрямую), но в runtime JAR-ы присутствуют.

Когда это важно

Если библиотека A зависит от B через implementation, и сервис S подключает A — то B окажется в runtime classpath сервиса S. Это может привести к:

  • Split package — если A и B содержат классы в одном Java-пакете
  • Конфликтам версий — если B тянет несовместимые транзитивы
  • Раздуванию classpath — ненужные JAR-ы в деплое

Чтобы зависимость не утекала

  • compileOnly — если зависимость нужна только для компиляции/генерации кода
  • Исключение из публикации через конфигурацию maven-publish

Проверка

У потребителя проверить транзитивы:

./gradlew :module:dependencies --configuration runtimeClasspath | grep "<имя-зависимости>"