1
votes

I have gone through the official doc and many StackOverflow questions about the difference betweenapi and implementation configurations. I think I understand the basic, but I really want to understand what it means by dependencies are exposed or not exposed.

This is what I have got so far. When I publish my Java library (written in Kotlin, but not relevant), the dependency scope in the published pom file is either complie when api is used or runtime when implementation is used, i.e.

dependencies {
    api "..."
}
<dependency>
      <groupId>...</groupId>
      <artifactId>...</artifactId>
      <version>...</version>
      <scope>compile</scope> 
</dependency>
dependencies {
    implementation "..."
}
<dependency>
      <groupId>...</groupId>
      <artifactId>...</artifactId>
      <version>...</version>
      <scope>runtime</scope> 
</dependency>

So does exposing dependencies in this case really just mean adding them to classpath (compile scope)?

One of the many answers about api vs implementation says it is merely about build optimization, it makes sense that the build time will be reduced if we not adding everything in the classpath maybe?

And a bonus question, the Gradle doc says api configuration comes with java-library plugin, but apparently, I can use it without applying the plugin, how is this possible?

// Gradle 6.1.1
plugins {
    id 'org.jetbrains.kotlin.jvm' version 'XXX'
}
dependencies {
    api "myLibrary"
}
1

1 Answers

1
votes

So does exposing dependencies in this case really just mean adding them to classpath (compile scope)?

Yes, it's pretty much just a matter of having them on the consumer's compile classpath or not.

One of the many answers about api vs implementation says it is merely about build optimization, it makes sense that the build time will be reduced if we not adding everything in the classpath maybe?

Well, good software design advocates not exposing internal implementation details. This is why you have public and private class members in the code. You could argue that this principal is solid when it comes to dependencies as well. I see the following benefits:

  • A consumer does not implicitly start relying on "internal" transitive dependencies. If they did, it would mean that you can't remove them from the library without breaking the consumers.
  • A reduced classpath may make compilation slightly faster. I don't think it matters a whole lot for normal projects though. Maybe it is more impactful if you rely on Java or Kotlin annotation processors or Groovy AST transformations that feels like scanning the entire classpath through each time.
  • Not having unnecessary modules on the compilation classpath means a library will not have to be recompiled if those modules changes.

The last one is the biggest benefit in my opinion. Let's say you have a big multi-project where a shared sub-project internally relies on Apache Commons Lang. If you have declared Lang as an api dependency and update it, then all other projects relying on this shared project need to be recompiled. If you declare it as an implementation dependency instead, this will not happen. All those projects will still need to be re-tested of cause as the runtime behaviour might have changed (this is handled correctly by default in Gradle).

And a bonus question, the Gradle doc says api configuration comes with java-library plugin, but apparently, I can use it without applying the plugin, how is this possible?

This is because the Kotlin plugin also declares an api configuration. It has the same semantics as configured by the java-library plugin.

If your project is a multi-project, you can still add the java-library plugin even if it is using the Kotlin plugin. An additional change that this will cause is that consumers will see the output directory for the compiled classes instead of the final jar file. This removes the need to construct the jar during normal development, which should reduce build time. On the other hand, there is apparently a potential performance problem on Windows if you have a lot of classes in a single project, so the usual your mileage may vary disclaimer applies here as well (I don't know how many "a lot" is though).