A propos de Gradle "Implementation" vs "Api" :
C'est une question de visibilité à la compilation des dépendances transitives.
Donc ça n'est intéressant que quand on écrit une librairie et c'est du point de vue des consommateurs.
J'avais dessiné ces schémas pour comprendre:
Il faut plusieurs niveau de dépendances et il faut réfléchir "compile time classpath" et "runtime classpath"
L'example qui est souvent donné:
Une librairie utilise StringUtils de apache commons lang. C'est seulement au niveau du code, aucun type n'est exposé dans les signatures de méthodes ou dans la hiérarchie des types. Si la dépendance est déclarée en "compile" (maven) ou "api" (gradle), un consommateur de cette librairie va pouvoir utiliser apache commons lang dans son propre code. Mais dans ce cas, il utilise une dépendance de manière implicite. C'est mauvais car le jour où la libraire change son implementation et remplace apache commons par guava, le code des consommateurs va être cassé.
Alors que si la librairie déclare sa dépendance en "implementation", les consommateurs ne verront cette dépendance au compile time et ne pourront pas l'utiliser.
Au runtime toutes les dépendances sont incluses de toute façon.
Contrairement à ce qui a été dit même avec une dépendance de type "implementation", le consommateur ne va pas pouvoir échanger EclipseLink et Hibernate. Ca c'est plus un pattern de serveur d'application. Dans ce cas il faut que le code écrit n'est aucune référence vers les implementations.
Du coup "compileOnly" et "compileOnlyApi" c'est la même chose, mais pour les libs qui ne seront pas présentes au runtime dans tous les cas.
* "compileOnly" n'est pas du tout visible à la compilation des consommateurs.
* "compileOnlyApi" défini les libs présentes à la compilation et présentes à la compilation pour les consommateurs
C'est très pointu, mais au final un très bon modèle.