--- title: The Java Library Plugin source: https://docs.gradle.org/6.3/userguide/java_library_plugin.html tags: - IT/Development/Gradle --- The Java Library plugin expands the capabilities of the [Java plugin](https://docs.gradle.org/6.3/userguide/java_plugin.html) by providing specific knowledge about Java libraries. In particular, a Java library exposes an API to consumers (i.e., other projects using the Java or the Java Library plugin). All the source sets, tasks and configurations exposed by the Java plugin are implicitly available when using this plugin. ## [](#sec:java_library_usage)[Usage](#sec:java_library_usage) To use the Java Library plugin, include the following in your build script: Example 1. Using the Java Library plugin `Groovy``Kotlin` build.gradle.kts ``` plugins { `java-library` } ``` ## [](#sec:java_library_separation)[API and implementation separation](#sec:java_library_separation) The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an *API* exposed to consumers. A library is a Java component meant to be consumed by other components. It’s a very common use case in multi-project builds, but also as soon as you have external dependencies. The plugin exposes two [configurations](https://docs.gradle.org/6.3/userguide/declaring_dependencies.html#sec:what-are-dependency-configurations) that can be used to declare dependencies: `api` and `implementation`. The `api` configuration should be used to declare dependencies which are exported by the library API, whereas the `implementation` configuration should be used to declare dependencies which are internal to the component. Example 2. Declaring API and implementation dependencies `Groovy``Kotlin` build.gradle.kts ``` dependencies { api("org.apache.httpcomponents:httpclient:4.5.7") implementation("org.apache.commons:commons-lang3:3.5") } ``` Dependencies appearing in the `api` configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the `implementation` configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. This comes with several benefits: - dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive dependency - faster compilation thanks to reduced classpath size - less recompilations when implementation dependencies change: consumers would not need to be recompiled - cleaner publishing: when used in conjunction with the new `maven-publish` plugin, Java libraries produce POM files that distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don’t mix what is needed to compile the library itself and what is needed to compile against the library). | | | | --- | --- | | | The `compile` configuration still exists but should not be used as it will not offer the guarantees that the `api` and `implementation` configurations provide. | If your build consumes a published module with POM metadata, the Java and Java Library plugins both honor api and implementation separation through the scopes used in the pom. Meaning that the compile classpath only includes `compile` scoped dependencies, while the runtime classpath adds the `runtime` scoped dependencies as well. This often does not have an effect on modules published with Maven, where the POM that defines the project is directly published as metadata. There, the compile scope includes both dependencies that were required to compile the project (i.e. implementation dependencies) and dependencies required to compile against the published library (i.e. API dependencies). For most published libraries, this means that all dependencies belong to the compile scope. If you encounter such an issue with an existing library, you can consider a [component metadata rule](https://docs.gradle.org/6.3/userguide/component_metadata_rules.html#sec:component_metadata_rules) to fix the incorrect metadata in your build. However, as mentioned above, if the library is published with Gradle, the produced POM file only puts `api` dependencies into the compile scope and the remaining `implementation` dependencies into the runtime scope. If your build consumes modules with Ivy metadata, you might be able to activate api and implementation separation as described [here](https://docs.gradle.org/6.3/userguide/variant_model.html#sub:ivy-mapping-to-variants) if all modules follow a certain structure. | | | | --- | --- | | | Separating compile and runtime scope of modules is active by default in Gradle 5.0+. In Gradle 4.6+, you need to activate it by adding `enableFeaturePreview('IMPROVED_POM_SUPPORT')` in *settings.gradle*. | ## [](#sec:java_library_recognizing_dependencies)[Recognizing API and implementation dependencies](#sec:java_library_recognizing_dependencies) This section will help you identify API and Implementation dependencies in your code using simple rules of thumb. The first of these is: - Prefer the `implementation` configuration over `api` when possible This keeps the dependencies off of the consumer’s compilation classpath. In addition, the consumers will immediately fail to compile if any implementation types accidentally leak into the public API. So when should you use the `api` configuration? An API dependency is one that contains at least one type that is exposed in the library binary interface, often referred to as its ABI (Application Binary Interface). This includes, but is not limited to: - types used in super classes or interfaces - types used in public method parameters, including generic parameter types (where *public* is something that is visible to compilers. I.e. , *public*, *protected* and *package private* members in the Java world) - types used in public fields - public annotation types By contrast, any type that is used in the following list is irrelevant to the ABI, and therefore should be declared as an `implementation` dependency: - types exclusively used in method bodies - types exclusively used in private members - types exclusively found in internal classes (future versions of Gradle will let you declare which packages belong to the public API) The following class makes use of a couple of third-party libraries, one of which is exposed in the class’s public API and the other is only used internally. The import statements don’t help us determine which is which, so we have to look at the fields, constructors and methods instead: ### [](#example_making_the_difference_between_api_and_implementation)[Example: Making the difference between API and implementation](#example_making_the_difference_between_api_and_implementation) The *public* constructor of `HttpClientWrapper` uses `HttpClient` as a parameter, so it is exposed to consumers and therefore belongs to the API. Note that `HttpGet` and `HttpEntity` are used in the signature of a *private* method, and so they don’t count towards making HttpClient an API dependency. On the other hand, the `ExceptionUtils` type, coming from the `commons-lang` library, is only used in a method body (not in its signature), so it’s an implementation dependency. Therefore, we can deduce that `httpclient` is an API dependency, whereas `commons-lang` is an implementation dependency. This conclusion translates into the following declaration in the build script: Example 3. Declaring API and implementation dependencies `Groovy``Kotlin` build.gradle.kts ``` dependencies { api("org.apache.httpcomponents:httpclient:4.5.7") implementation("org.apache.commons:commons-lang3:3.5") } ``` ## [](#sec:java_library_configurations_graph)[The Java Library plugin configurations](#sec:java_library_configurations_graph) The following graph describes the main configurations setup when the Java Library plugin is in use. ![java library ignore deprecated main](../../_resources/java-library-ignore-deprecated-m_e457a826129c4d7a8.png) - The configurations in *green* are the ones a user should use to declare dependencies - The configurations in *pink* are the ones used when a component compiles, or runs against the library - The configurations in *blue* are internal to the component, for its own use And the next graph describes the test configurations setup: ![java library ignore deprecated test](../../_resources/java-library-ignore-deprecated-t_4076702d61284ad79.png) | | | | --- | --- | | | The *compile*, *testCompile*, *runtime* and *testRuntime* configurations inherited from the Java plugin are still available but are deprecated. You should avoid using them, as they are only kept for backwards compatibility. | The role of each configuration is described in the following tables: | | | | | | | --- | --- | --- | --- | --- |Table 1. Java Library plugin - configurations used to declare dependencies | Configuration name | Role | Consumable? | Resolvable? | Description | | --- | --- | --- | --- | --- | | `api` | Declaring API dependencies | no | no | This is where you should declare dependencies which are transitively exported to consumers, for compile. | | `implementation` | Declaring implementation dependencies | no | no | This is where you should declare dependencies which are purely internal and not meant to be exposed to consumers. | | `compileOnly` | Declaring compile only dependencies | no | no | This is where you should declare dependencies which are only required at compile time, but should not leak into the runtime. This typically includes dependencies which are shaded when found at runtime. | | `runtimeOnly` | Declaring runtime dependencies | no | no | This is where you should declare dependencies which are only required at runtime, and not at compile time. | | `testImplementation` | Test dependencies | no | no | This is where you should declare dependencies which are used to compile tests. | | `testCompileOnly` | Declaring test compile only dependencies | no | no | This is where you should declare dependencies which are only required at test compile time, but should not leak into the runtime. This typically includes dependencies which are shaded when found at runtime. | | `testRuntimeOnly` | Declaring test runtime dependencies | no | no | This is where you should declare dependencies which are only required at test runtime, and not at test compile time. | | | | | | | | --- | --- | --- | --- | --- |Table 2. Java Library plugin — configurations used by consumers | Configuration name | Role | Consumable? | Resolvable? | Description | | --- | --- | --- | --- | --- | | `apiElements` | For compiling against this library | yes | no | This configuration is meant to be used by consumers, to retrieve all the elements necessary to compile against this library. Unlike the `default` configuration, this doesn’t leak implementation or runtime dependencies. | | `runtimeElements` | For executing this library | yes | no | This configuration is meant to be used by consumers, to retrieve all the elements necessary to run against this library. | | | | | | | | --- | --- | --- | --- | --- |Table 3. Java Library plugin - configurations used by the library itself | Configuration name | Role | Consumable? | Resolvable? | Description | | --- | --- | --- | --- | --- | | compileClasspath | For compiling this library | no | yes | This configuration contains the compile classpath of this library, and is therefore used when invoking the java compiler to compile it. | | runtimeClasspath | For executing this library | no | yes | This configuration contains the runtime classpath of this library | | testCompileClasspath | For compiling the tests of this library | no | yes | This configuration contains the test compile classpath of this library. | | testRuntimeClasspath | For executing tests of this library | no | yes | This configuration contains the test runtime classpath of this library | ## [](#sec:java_library_classes_usage)[Using classes instead of jar for compilation](#sec:java_library_classes_usage) A feature of the `java-library` plugin is that projects which consume the library only require the classes folder for compilation, instead of the full JAR. This enables lighter inter-project dependencies as resources processing (`processResources` task) and archive construction (`jar` task) are no longer executed when only Java code compilation is performed during development. | | | | --- | --- | | | The usage or not of the classes output instead of the JAR is a *consumer* decision. For example, Groovy consumers will request classes *and* processed resources as these may be needed for executing AST transformation as part of the compilation process. | ### [](#sub:java_library_known_issues_memory)[Increased memory usage for consumers](#sub:java_library_known_issues_memory) An indirect consequence is that up-to-date checking will require more memory, because Gradle will snapshot individual class files instead of a single jar. This may lead to increased memory consumption for large projects, with the benefit of having the `compileJava` task up-to-date in more cases (e.g. changing resources no longer changes the input for `compileJava` tasks of upstream projects) ### [](#sub:java_library_known_issues_windows_performance)[Significant build performance drop on Windows for huge multi-projects](#sub:java_library_known_issues_windows_performance) Another side effect of the snapshotting of individual class files, only affecting Windows systems, is that the performance can significantly drop when processing a very large amount of class files on the compile classpath. This only concerns very large multi-projects where a lot of classes are present on the classpath by using many `api` or (deprecated) `compile` dependencies. To mitigate this, you can set the `org.gradle.java.compile-classpath-packaging` system property to `true` to change the behavior of the Java Library plugin to use jars instead of class folders for everything on the compile classpath. Note, since this has other performance impacts and potentially side effects, by triggering all jar tasks at compile time, it is only recommended to activate this if you suffer from the described performance issue on Windows. ## [](#sec:library_distribution)[Distributing a library](#sec:library_distribution) Aside from [publishing](https://docs.gradle.org/6.3/userguide/publishing_setup.html) a library to a component repository, you may sometimes need to package a library and its dependencies in a distribution deliverable. The [Java Library Distribution Plugin](https://docs.gradle.org/6.3/userguide/java_library_distribution_plugin.html) is there to help you do just that.