How to manually add dependencies to Gradle's MavenPom/MavenPublication? - gradle

I am working on a plugin. This plugin gets attached to a project that does not apply the java plugin nor the java-library plugin but which should functionally "look" like a Java project[1]. Which means that it should publish a POM including dependencies. The exact dependencies are known and have been collected in a Configuration.
However, I cannot figure out how to manually attach dependencies to the MavenPublication such that they make it into the published pom (aside from directly editing the pom xml).
MavenPublication shadowMavenPublication = publishingExtension.getPublications().create( "mavenShadowArtifacts", MavenPublication.class );
// `shadowPublishArtifact` is a class defined in the plugin
shadowMavenPublication.artifact(
shadowPublishArtifact.getFile(),
(mavenArtifact) -> {
mavenArtifact.setClassifier( shadowPublishArtifact.getClassifier() );
mavenArtifact.setExtension( shadowPublishArtifact.getExtension() );
}
);
So at this point I have the MavenPublication and added my custom artifact to it. Internally this MavenPublication contains a number of "dependencies" as instances of MavenDependency. E.g. DefaultMavenPublication#runtimeDependencies, DefaultMavenPublication#apiDependencies, ... But those are things defined on internal-only contracts.
Using just public APIs, how can I add dependencies to get added to the pom?
P.S. As a bonus, answer the question on the Gradle forums and get points there too! :D
P.S.S. These dependencies come from another project (hibernate-core) in a multi-project build. The user has configured those dependencies themselves. I just "consume" those dependencies with a series of "dependency substitutions". That "source project" defines some exclusions to its dependencies. How can I access those exclusions do be able to transfer them to the dependencies I am creating for this copy project (hibernate-core-jakarta)?
Thanks!
[1] Its a long back-story, but the gist is that this plugin integrates the JakartaTransformer. The project is completely generated using the transformer. The tasks added by those 2 plugins cause problems.

MavenPublication class has pom property - You need to construct (or provide in Your plugin some API for that purpose) pom with all necessary dependencies. It will be published alongside with artifact.

As far as I know, dependencies are attached to the POM by evaluating the configurations of a software component: MavenPublication.from(SoftwareComponent) (source: DefaultMavenPublication).
The idea would be to provide a customized software component. This is only possible through a custom plugin, according to Creating and publishing custom components.

Related

Load Gradle plugin from custom plugin, dynamically

I am developing a Gradle plugin (https://github.com/hkhc/jarbird), which apply some other plugins in the code according to different scenarios.
I can do that by putting the plugin components as implementation dependencies in my plugin project. Then apply the project with project.apply() method with plugin ID or plugin class object.
However, this means unnecessary downloads of plugin components when I don't need those plugins. So I am finding a way to resolve the plugins dynamically.
I tried to do that by adding the dependency as compileOnly in the build script of my custom plugin, and load it in project.apply() of my plugin.
val artifactoryConfiguration = project.buildscript.configurations.detachedConfiguration(
DefaultExternalModuleDependency(
"org.jfrog.buildinfo",
"build-info-extractor-gradle",
"4.23.4"
)
)
artifactoryConfiguration.resolve()
When I made the coordinate wrong intentionally, I got ModuleVersionNotFoundException. So I am sure the resolve did take place. However, project.apply(ArtifactoryPlugin::class.java) still cause ClassNotFoundException when executing the plugin. It seems Gradle cannot load the plugin from a random detached configuration.
I got stuck at this point, and don't know how to make Gradle load a plugin that I resolve dynamically in my custom plugin.
Do I get the direction wrong or I missed something that makes this approach work?

Configuration with name 'testRuntimeClasspath' not found

I am designing a plugin to return all the dependencies of the project
I tried to get dependencies from project.getConfigurations() but it is always returning the error "Configuration with name 'testRuntimeClasspath' not found". Is there any way we can apply the plugin at the Execution Phase of the build.
public void apply(Project project) {
project.getConfigurations()
.getByName("testRuntimeClasspath")
.getAllDependencies();
}
The existing configurations in a Gradle build depend on the plugin(s) applied and any configuration created by the build author.
So your plugin should either support well known plugins and derive configurations name from them or have a way for the users of your plugin to register which configurations are to be queried that way or a combination of both.
Not sure what your plugin's goal is, but y9ou should be mindful when listing dependencies as it will force resolution of configurations that may otherwise not need to be resolved.

How can I bundle a local dependency into jar build by gradle?

The problem is that I have three sibling projects. Only two are important here lets call them shared and client. client depends on shared and since I've done that all locally I define that dependency like compile project(':shared') in the build.gradle for the client project. Now I want to publish the client with help of the maven-publish plugin. When I do that every project that depends on the client fails because it can't find the shared project anywhere.
Now that makes complete sense at it is not published anywhere it's just there when building the client. I now want the artifact of the client project to include all the classes by the shared project. Also I want the client artifact to no longer say it depends on the shared project but it should now depend on everything that shared depended on.
And I've already done a ton of research, I found this question and answer that shows how to include a specific dependency into the resulting artifact. The problem with that is that is includes all the dependencies of the shared project into the jar as well as the files of the shared project.
My questions are:
Is this a reasonable approach? If not what would be better?
How can I only put the classes of the direct dependency shared
into the jar build by client?
How can I exclude shared but not it's dependencies from the
artifacts the maven-publish plugin generates?
I found an answer to question 2:
In the build.gradle you need to add this:
configurations {
localCompile.transitive = false
compile.extendsFrom(localCompile)
}
jar {
from {
configurations.localCompile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Then simply define all local dependencies like localCompile project(":kuroji-websocket-shared").

Maven: xpp3 versus xpp3_min

In my Java Maven project, two of my codes direct dependencies use a sub-dependency of XPP3. However, one of them has the artifact ID xpp3 while the other one has the artifact ID xpp3_min. Both are version 1.1.4c. Does anyone know the difference between the two? My project allows both to be dependencies without marking either of them as excluded due to conflict.
Home page for XPP3 project: http://www.extreme.indiana.edu/xgws/xsoap/xpp/
Maven repository reference: http://mvnrepository.com/artifact/xpp3/xpp3_min and http://mvnrepository.com/artifact/xpp3/xpp3. Notice how both projects have the same description. I don't just want to naively assume that _min is a minimal version due to its name suffix.
I've opened both archives and the xpp3_min only includes the XmlPullParser.class and XmlPullParserException.class (and MXParser.class). It doesn't include other classes like XmlPullParserFactory etc...
A popular obj <-> xml serialzer package: XStream, has both a dependency on XPP3_MIN and XMLPULL, where XMLPULL implements the XmlPullParserFactory. If it had a dependency on XPP3 it sure would have a classloading issue.

Multiple reusable modules in maven

I have a couple of java modules set up in IDEA and I am wanting to mavenize them. These java modules use classes from one another.
I was not quite sure how I should take up this and I decide to add modules on a maven project using IDEA. Hence first I created a maven project, let's name it pm1 which has a class let's name it TempClass1. Now this class can be used in other maven project. Hence I added another maven module - pm11 and tried to use TempClass1 with in pm11. It worked and I notices that IDEA had added module dependency of pm1 in pm11. So whole structure looks as -
But now when I do mvn test from pm11 then it fails with error message package package1 does not exist and it looks to me that it is because package1 is in a different maven project. And I am not sure how I could use classes which reside in a different maven project. I hope I am clear in my question.
You can use classes of other maven projects, as long as there's a proper maven dependency defined in pom.xml. Ensure that the dependency is defined and its' scope is either undefined or relevant (You may have problems if the scope is provided for example).

Resources