How can I bundle a local dependency into jar build by gradle? - 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").

Related

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

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.

Collect Gradle project's dependency constraints

I am looking for a way to collect all the dependency constraints (enforced with a regular platform and/or enforcedPlatform and/or "manually") for a given project from a custom Gradle plugin.
In Maven world, you can resolve an "artifact descriptor" that will give access to the effective list of all the managed dependencies enforced on the artifact. I couldn't find so far how this kind of info could be collected in Gradle.
Any advice? Thanks!
based on the clarification of the question - below can be a start (requires more work - for some reason my local shows configuration as default - not the compile/runtime)
allprojects {
afterEvaluate {
configurations.findAll {it.canBeResolved==true}.each { println it + "\n" ; it.allDependencies.each { println it } }
}
}
The question (appears to me) is sharing the test code across modules in a multi-module project
Short answer - No - there is direct test dependency share across modules.
To share test code between modules internally via build settings
Official gradle route https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures
Simple hack
testImplementation files(project(':core-module').sourceSets.test.output.classesDirs)
add the above line either individually where you need or in root with subprojects() with appropriate condition
*there are other possible routes as well *
ex: via configuration child.testImplementation extends parent.testImplementation (or runtime)

Gradle: Combine jars from sub-projects

I have a multi module gradle project. The project contains two subproject, i.e. a spring-boot application server and an npm front-end ui (which is just static javascript).
I can build both sub-projects. I can define:
implementation(project(':ui'))
in the dependencies section of the spring application and I get a running jar in the server projects build folder successfully serving the frontend.
However, I want to be able not to combine the two not within the server sub-project, but rather in the enclosing project.
I thought of something like:
build.gradle:
allprojects {
group = 'com.example.webapp'
version = '0.0.1-SNAPSHOT'
}
dependencies {
implementation(project(':server'))
implementation(project(':ui'))
}
settings.gradle:
rootProject.name = 'webapp'
include 'server', 'ui'
I think, I am completely wrong. Everything I find about gradle is either completely basic, or assumes way more than what I understood about it so far.
EDIT:
With my solution approach I am getting the following error:
A problem occurred evaluating root project 'webapp'.
Could not find method implementation() for arguments [project ':server'] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
EDIT 2:
The basic idea is from https://ordina-jworks.github.io/architecture/2018/10/12/spring-boot-angular-gradle.html
The implementation not found is caused by the lack of plugins applied to your root project. The implementation configuration is created by the java plugins in Gradle.
What you are trying to achieve requires a good understanding of Gradle and all the magic provided by the Spring Boot plugin.
You are effectively trying to reproduce some of that integration in your root project, without the help of the plugins.
An approach that might be easier would be to migrate your application project to be the root project and then have the ui as a subproject.

Gradle get what repository a dependency was resolved from (smart fat jar)

I have a use case where I need to create a smart fat jar. What, exactly does that mean?
Essentially I have different repositories which our application dependencies can be resolved from, some of them exist in a globally replicated file share (which is served as an ivy repository), while others exist in a private maven repository that is not productionized, and should not be used directly by applications in production.
I would like to create a fat jar in a smart way, such that:
If the dependency came from the private maven repository, it should be added to the fat jar.
If the dependency came from the file share, it points to the jar'directly in that file share (i.e. that fat jar's manifest adds that jar to the classpath.
Do any facilities exist for me to be able to distinguish where a dependency is resolved from?
For example:
repositories {
stableIvy()
unreliableMaven()
}
dependencies {
...
}
As of Gradle 5.2 there is no API that allows you to acces that information. However this is internally known by Gradle. You could file a feature request against the project.

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.

Resources