Java Ecosystem Capabilities Gradle Plugin

Overview

Java Ecosystem Capabilities Gradle Plugin

This plugin adds Capabilities to the metadata of well-known components hosted on Maven Central that are used in many Java projects.

What is a 'Capability' in Gradle and why should I care?

In the video below, I explain the concept of Capability Conflicts and why they can help you to avoid "dependency hell" in your project. With this plugin, you enable Gradle to detect and automatically resolved typical capability conflicts in the Java Ecosystem.

How to use the plugin?

Apply the plugin to all (sub)projects of your build so that the capability-adding rules are active everywhere. There is nothing else you need to do. The rules will now be considered when dependencies are resolved. For general information about how to structure Gradle builds, and apply community plugins like this one to all subprojects, you can check out my Understanding Gradle video series.

Plugin dependency

Add this to the build file of your convention plugin's build (e.g. build-logic/build.gradle(.kts) or buildSrc/build.gradle(.kts)).

dependencies {
    implementation("de.jjohannes.gradle:java-ecosystem-capabilities:0.1")
}

Apply the plugin

In your convention plugin, apply the plugin.

plugins {
    ...
    id("de.jjohannes.gradle.java-ecosystem-capabilities")
}

Alternative: Copy rules into your build logic

Instead of applying this plugin, you may also copy selected rules to your own build logic and register them in your convention plugin(s) directly. In the list below, all rule implementations are linked. Here they are implemented in Java, but converting them to Kotlin or Groovy should be straightforward if you prefer.

I use the plugin and now there is a conflict - what now?

The plugin configures Gradle to resolve conflicts by selecting the highest version. If this is not possible, because there is no single highest version, you will get a conflict error.

If you get an error like this:

> Module 'com.sun.mail:jakarta.mail' has been rejected:
     Cannot select module with conflict on capability 'javax.mail:mail:2.0.1' also provided by [com.sun.mail:mailapi:2.0.1(compile)]

It means that you need to make a decision for the given capability - in this case javax.mail:mail - by selecting one of the modules that both provide the capability. In this case, you can decide between com.sun.mail:jakarta.mail (see first line of message) and com.sun.mail:mailapi (see end of second line).

A decision is made by defining a resolution strategy for the capability. This is best done in the place where you applied this plugin (e.g. one of your convention plugins):

configurations.all {
  resolutionStrategy.capabilitiesResolution {
    withCapability("javax.mail:mail") {        // Capability for which to make the decision
      select("com.sun.mail:jakarta.mail:0")    // The component to select
    }
  }
}

What is the concrete effect of the plugin?

The plugin makes sure that during dependency resolution, you do not end up with two components that 'do the same thing' in the dependency resolution result. That is, you won't have two Jars with different names (e.g. jakarta.xml.bind-api-3.0.1.jar and jaxb-api-2.3.1.jar) but same/similar classes on the classpath. In this example, Gradle will use jakarta.xml.bind-api in place of jaxb-api in all places. You can see all effects in this build scan from this artificial sample project that includes dependencies to all components covered by rules in this plugin.

Which Components does this plugin affect?

The following list shows all Capabilities and the Components they are added to. Each Capability's GA coordinates correspond to the GA coordinates of the Component that first introduced the Capability.

Something seems to be missing

This plugin collects rules that universally apply in the Java ecosystem. That means, that the information this plugin adds would ideally be already published in the metadata of the corresponding components. The idea is that every Java project can apply this plugin to avoid certain 'dependency hell' situations. Even if the project does not use any of the components this plugin affects directly, transitive dependency might bring in components that cause conflicts.

At the moment this plugin is only covering a fraction of the components on Maven Central that miss capability information. If you encounter more cases, please...

...contribute!

If you use this plugin and think it is missing a rule for a well-known component (or that a rule is incomplete/wrong), please let us know by

Please make sure, you clearly state which Capability it is about and which Components provide the Capability.

Special Case: Logging Libraries

This plugin does not contain rules for logging libraries, which is a specific area in which conflicts occur regularly. There is a separate plugin covering this topic by adding capabilities to the components of well-known logging APIs and implementations. Please apply that plugin in addition to this one:

plugins {
    ...
    id("de.jjohannes.java-ecosystem-capabilities")
    id("dev.jacomet.logging-capabilities")
}

I maintain a Component on Maven Central - How can I publish Capability information myself?

It would be great to see more components publishing capability information directly. If you wonder how you could do it, here is how:

Publishing with Gradle

Assuming the component you are publishing is org.ow2.asm:asm. You add the asm:asm capability as follows:

configurations {
    apiElements {
        outgoing {
            capability("${project.group}:${project.name}:${project.verson}") // keep default capability 'org.ow2.asm:asm'
            capability("asm:asm:${project.verson}")                          // add 'asm:asm'
        }
    }
    runtimeElements {
        outgoing {
            capability("${project.group}:${project.name}:${project.verson}") // keep default capability 'org.ow2.asm:asm'
            capability("asm:asm:${project.verson}")                          // add 'asm:asm'
        }
    }
}

See also: Documentation in Gradle Manual

Publishing with Maven

Assuming the component you are publishing is org.ow2.asm:asm. You add the asm:asm capability as follows:




  
    
      de.jjohannes
      gradle-module-metadata-maven-plugin
      0.2.0
      
        
          
            gmm
          
        
      
      
        
          
            asm
            asm
          
        
      
    
  


See also: Documentation of gradle-module-metadata-maven-plugin Maven Plugin

Comments
  • Make conflict resolution and rules configurable

    Make conflict resolution and rules configurable

    E.g.:

    a) If there's a mismatch of Guava versions, please fail instead of selecting something b) Please don't add capabilities for cglib, because, well, it adds conflict


    Looks like it might be configured in a Gradle extension, or there might be a "plugin per ecosystem" like id("de.jjohannes.gradle:java-ecosystem-capabilities.cglib"), id("de.jjohannes.gradle:java-ecosystem-capabilities.guava"), ...

    enhancement 
    opened by vlsi 11
  • Missing `org.apache.tomcat:tomcat-annotations-api` artifact

    Missing `org.apache.tomcat:tomcat-annotations-api` artifact

    Hi, thanks for the awesome initiative with this plugin!

    I believe org.apache.tomcat:tomcat-annotations-api could be added to JakartaAnnotationApiRule.

    Also com.sun.activation:javax.activation in JakartaActivationApiRule.

    Also com.sun.mail:javax.mail to JakartaMailApiRule.

    Also, I'm not sure how these rules are supposed to work, but why doesn't JakartaActivationApiRule contain javax.activation:activation in it (or is that implicitly coming from the capability's group and name)?

    opened by boris-petrov 3
  • Make plugin compatible with component metadata rules declared in settings.gradle

    Make plugin compatible with component metadata rules declared in settings.gradle

    Similar to https://github.com/ljacomet/logging-capabilities/issues/18 (which I merely copy/pasted here)

    Currently, the plugin declares component metadata rules in the project, making it impossible to declare other rules in the settings.

    I think the plugin should be split to have the component metadata rules in a settings plugin (actually, a plugin that could be applied either to a project or the settings, so projets that prefer project-level component metadata rules or have other plugins doing the same –or just because they want to leverage version catalogs and that cannot be done for settings plugins :chicken::egg:– can continue using them).

    Or maybe the plugin could detect if it's also been applied to the settings (not sure if it's possible though) so it can conditionally add the rules to the project?

    Or maybe the plugin could detect when it's applied to the settings and automatically inject the capabilities resolution rules into all projects, so it could be applied to either (but not both), and wouldn't need to be split?

    Or just make it applicable to either settings (without registering the capabilities resolution rules) and projects, and declare component metadata rules in both cases? but that would make it incompatible with rulesMode FAIL_ON_PROJECT_RULES, and would warn for any other rulesMode.

    bug 
    opened by tbroyer 3
  • Merge jjohannes/missing-metadata-guava into this plugin

    Merge jjohannes/missing-metadata-guava into this plugin

    Looks like https://github.com/jjohannes/missing-metadata-guava is related, and the name of java-ecosystem-capabilities sounds good for an umbrella project.

    new rules 
    opened by vlsi 3
  • Add rules for more Jakarta components

    Add rules for more Jakarta components

    See list here: https://github.com/eclipse/transformer/blob/main/org.eclipse.transformer.jakarta/src/main/resources/org/eclipse/transformer/jakarta/jakarta-versions.properties

    BOMs:

    • javax:javaee-api
    • jakarta.platform:jakartaee-bom
    wontfix 
    opened by jjohannes 2
  • Typo in 'Publishing with Gradle' section (README.md)

    Typo in 'Publishing with Gradle' section (README.md)

    Awesome that this section is here!!!

    In the code snippet all occurrences of version are spelt verson

    configurations {
        apiElements {
            outgoing {
                capability("${project.group}:${project.name}:${project.verson}") // keep default capability 'org.ow2.asm:asm'
                capability("asm:asm:${project.verson}")                          // add 'asm:asm'
            }
        }
        runtimeElements {
            outgoing {
                capability("${project.group}:${project.name}:${project.verson}") // keep default capability 'org.ow2.asm:asm'
                capability("asm:asm:${project.verson}")                          // add 'asm:asm'
            }
        }
    }```
    docs 
    opened by cloudshiftchris 1
  • Handle `jakarta.mail:jakarta.mail-api`

    Handle `jakarta.mail:jakarta.mail-api`

    Which is the new version of com.sun.mail:jakarta.mail... however there's a twist as with everything Jakarta related... :smile: This one package was split it two as far as I understand - jakarta.mail:jakarta.mail-api and org.eclipse.angus:jakarta.mail... so I'm not sure how java-ecosystem-capabilities would handle this.

    opened by boris-petrov 1
  • CommonsIo rule should set capability commons-io:commons-io

    CommonsIo rule should set capability commons-io:commons-io

    The org.apache.commons:commons-io:1.3.2 release was the only one with this group. Everything else is published with group commons-io. For that reason that group should be used for the capability.

    opened by britter 0
  • Added `org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api` to `JavaxServletApiRule`

    Added `org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api` to `JavaxServletApiRule`

    For that one I'm not really sure whether the behavior is the desired one. The org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api dependency seems to be a bundle that contains both the javax.servlet:servlet-api, jakarta.servlet:jakarta.servlet-api, additional module-info.java and xml files.

    opened by DreierF 0
  • Rule for `org.bouncycastle`

    Rule for `org.bouncycastle`

    There are org.bouncycastle:bcprov-jdk15on and org.bouncycastle:bcprov-jdk18on which are conflicting.

    Same for bcmail, bcutil, bcpkix and maybe others.

    new rules 
    opened by boris-petrov 0
  • Rule for javax.servlet.jsp / jstl

    Rule for javax.servlet.jsp / jstl

    From custom Nebula rule:

      "substitute": [
        {
          "module": "javax.servlet:jsp-api",
          "with": "javax.servlet.jsp:javax.servlet.jsp-api:2.+",
          "reason": "jsp-api has been replaced with javax.servlet.jsp-api",
          "author": "[email protected]",
          "date": "2022-04-01"
        },
        {
          "module": "javax.servlet.jsp:jsp-api",
          "with": "javax.servlet.jsp:javax.servlet.jsp-api:2.+",
          "reason": "jsp-api has been replaced with javax.servlet.jsp-api",
          "author": "[email protected]",
          "date": "2022-04-01"
        },
        {
          "module": "javax.servlet.jsp.jstl:jstl-api",
          "with": "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.+",
          "reason": "jstl-api has been replaced with javax.servlet.jsp.jstl-api",
          "author": "[email protected]",
          "date": "2022-04-01"
        }
      ]```
    new rules 
    opened by cloudshiftchris 0
  • Add rule to handle old org.apache.geronimo javamail spec

    Add rule to handle old org.apache.geronimo javamail spec

    Custom Nebula substitution rule:

      "substitute": [
        {
          "module": "org.apache.geronimo.specs:geronimo-javamail_1.4_spec",
          "with": "javax.mail:javax.mail-api:1.4.+",
          "reason": "use formal mail api",
          "author": "[email protected]",
          "date": "2022-04-01"
        },
        {
          "module": "javax.mail:mail",
          "with": "javax.mail:javax.mail-api:1.4.+",
          "reason": "use formal mail api",
          "author": "[email protected]",
          "date": "2022-04-01"
        }
      ]
    
    new rules 
    opened by cloudshiftchris 0
  • Better contributing instructions

    Better contributing instructions

    Expand on https://github.com/gradlex-org/java-ecosystem-capabilities#contribute

    E.g.:

    • How should a rule class look like (e.g. conventions for constants in class)?
    • Where to add code to register the rule?
    • How to test and extend the test sample?
    docs 
    opened by jjohannes 0
Releases(v1.0)
Owner
Jendrik Johannes
Jendrik Johannes
A Maven plugin which fixes Scala dependencies incompatible with Java 9+

scala-suffix Maven Plugin A Maven plugin which fixes Scala dependencies incompatible with Java 9+. A bit of context First of all, you need this plugin

Maciej Gorywoda 7 Jan 5, 2022
Jenkins plugin exposes functionalities for the Popcorn by Lectra open-source Jenkins platform on Kubernetes

Popcorn Jenkins Plugin This Jenkins plugin exposes functionalities for the Popcorn by Lectra open-source Jenkins platform on Kubernetes. This plugin i

Lectra 4 Apr 6, 2022
Spotless-intellij-gradle - An IntelliJ plugin to allow running the Spotless gradle task from within the IDE.

Spotless Intellij Gradle An IntelliJ plugin to allow running the spotless gradle task from within the IDE on the current file selected in the editor.

Ryan Gurney 30 Dec 17, 2022
A browser automation framework and ecosystem.

Selenium Selenium is an umbrella project encapsulating a variety of tools and libraries enabling web browser automation. Selenium specifically provide

Selenium 25.5k Jan 7, 2023
Build criterion and ecosystem above multi-model databases

ShardingSphere - Building a Criterion and Ecosystem Above Multi-Model Databases Official Website: https://shardingsphere.apache.org/ Stargazers Over T

The Apache Software Foundation 17.8k Jan 9, 2023
SlimeVR-Server - Server app for SlimeVR ecosystem

SlimeVR Server Server app for SlimeVR ecosystem Server orchestrates communication between multiple sensors and integrations, like SteamVR. Sensors imp

null 362 Dec 31, 2022
jedibot is an application that aims to do beneficial actions on the Ethereum blockchain for the DeFi ecosystem while earning a profit for the user.

jedibot is an application that aims to do beneficial actions on the Ethereum blockchain for the DeFi ecosystem while earning a profit for the user. These actions include maintaining the DAI peg, providing liquidity and liquidating undercollateralized assets.

我是高天才! 10 Feb 5, 2022
:package: Gradle/Maven plugin to package Java applications as native Windows, Mac OS X, or GNU/Linux executables and create installers for them.

JavaPackager JavaPackager is a hybrid plugin for Maven and Gradle which provides an easy way to package Java applications in native Windows, Mac OS X

Francisco Vargas Ruiz 665 Jan 8, 2023
Maven port of the Netflix Gradle code generation plugin for graphql. https://github.com/Netflix/dgs-codegen

This is port of the netflix codegen plugin for Gradle. Found here. COPIED FROM NETFLIX DOCUMENTATION. The DGS Code Generation plugin generates code fo

null 63 Dec 24, 2022
A gradle plugin based on ANTLR to generate UML diagrams from kotlin source code.

A gradle plugin based on ANTLR to generate UML diagrams from kotlin source code.

Alex Porter 15 Oct 26, 2022
A Gradle plugin that improves the experience when developing Android apps, especially system tools, that use hidden APIs.

HiddenApiRefinePlugin A Gradle plugin that improves the experience when developing Android apps, especially system tools, that use hidden APIs. Backgr

Rikka apps 125 Jan 5, 2023
A gradle plugin for developing javaagent applications.

Javaagent Packing A gradle plugin for developing javaagent applications. Why this plugin Fast packing all dependencies Used many dependencies? Javaage

微莹·纤绫 0 May 13, 2022
Houston Asset Server Gradle plugin

Houston Asset Server Gradle plugin It is a helper that helps achieve synchronization automation through the build script of the schema serialized in p

null 1 Jan 28, 2022
A gradle plugin generates resConfig & languages array from project res folder.

For Android application projects that accept user-submitted translations, the number of supported languages may be large and growing. When new languages are added, developers need to manually update resConfig (1) and language array xml/class (2). Manual means there could be human error.

Rikka apps 28 Nov 12, 2022
Gradle plugin for Android applications for detecting unexpected changes in AndroidManifest.xml

manifest-guard Gradle plugin for Android applications for detecting unexpected changes in AndroidManifest.xml The problem being solved Every third-par

Daniil Popov 39 Dec 24, 2022
sql2o is a small library, which makes it easy to convert the result of your sql-statements into objects. No resultset hacking required. Kind of like an orm, but without the sql-generation capabilities. Supports named parameters.

sql2o Sql2o is a small java library, with the purpose of making database interaction easy. When fetching data from the database, the ResultSet will au

Lars Aaberg 1.1k Dec 28, 2022
Tuya 37 Dec 26, 2022
This Web Application Allows A user to upload a two minutes Video. It uses Server Side Capabilities of Nodejs and Spring Boot .

VideoStreamingApplication Purpose Of This Application These days trend of short videos are on rise youtube recently realsed "Shorts" . So , taking ins

Prateek Kumar 57 Nov 13, 2022
HUAWEI 3D Modeling Kit project contains a sample app. Guided by this demo, you will be able to implement full 3D Modeling Kit capabilities, including 3D object reconstruction and material generation.

HUAWEI 3D Modeling Kit Sample English | 中文 Introduction This project includes apps developed based on HUAWEI 3D Modeling Kit. The project directory is

HMS 59 Jan 1, 2023