update gradle from 4.4 to 5.4 make joda-time dependancy issue - gradle

HI I've migrated a project to gradle version 5.4 from 4.4. Since then gradlew build returns error as below.
....ConvTable.java:6: error: package org.joda.time does not exist
import org.joda.time.DateTime;
...ConvetService.java:5: error: package org.joda.time does not exist
import org.joda.time.DateTime;
...ConvetService.java:34: error: cannot find symbol
ConvTableP getLastCononTableDate(String fromCurrency, String toCurrency, DateTime dateTimeZone) throws IOException;
symbol: class DateTime
location: interface ConvetService
Note: Some input files use or override a deprecated API.
Note: Recompile with -Xlint:deprecation for details
* What went wrong:
Execution failed for task ':cur-api:compileJava'
gradle file looks like below. and its a sub project of bigger one
apply plugin: "j-library"
apply plugin: "m-publish"
group = "com.t.cur"
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
publishing { publications { mavenJava(MavenPublication) { } }
repositories {
maven { url "${mv_repo_url}" } }
}
dependencies {
implementation "com.t.com:x-core:1.0.0"
implementation "commons-lang:commons-lang:2.6"
}

My guess is that as part of the upgrade, you changed compile configurations with implementation. One of the differences with the new configuration is that the dependencies will not be exposed to consuming projects as part of the compilation classpath. The idea is that the dependencies you put into implementation are implementation specific and should not "leak" onto the consuming projects. This speeds up the build when using incremental compilation as dependent classes are only recompiled if the public API changes but not the internal implementation. There is also a case to be made for providing looser coupling between projects, though this is a bit more subjective. The implementation dependencies will still be part of, and resolved, in the runtimeClasspath configuration though.
So (assuming this is the underlying issue of cause), the dependency x-core used to provide Joda as a transitive dependency for compilation. But this is no longer the case.
There are two ways to fix it. If you use Joda as part of the public API of x-core, you need to declare it using the api configuration instead of implementation (and use the java-library plugin if you don't already). This will make Joda part of the compilation classpath of dependent projects.
On the other hand, if this sub-project just happens to use Joda as well, but in a completely unrelated way to x-core, you should declare it as dependency here as well (either as implementation or api using the same rules as before).

Related

Custom Configuration dependency declaration

I am trying to convert build.gradle to kotlin dsl. Using gradle 7.4.1.What the right way to declare custom configuration. For custom configuration like
configurations { grafana }
sourceSets { grafana }
and within dependencies block
grafanaImplementation "org.slf4j:slf4j-simple:1.7.36"
grafanaImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
grafanaRuntimeOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
While I am in kotlin-dsl I am doing
val grafana by configurations.creating
val grafanaSourceSet = sourceSets.create("grafana")
and within dependency block
grafana("org.slf4j:slf4j-simple:1.7.36")
grafana("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
When I try to put grafanaImplementation/ grafanaRuntimeOnly within kotlin dsl, it fails.
What is the equivalent of grafanaImplementation/ grafanaRuntimeOnly within kotlin dsl
Quick fix
When you do
val grafanaSourceSet = sourceSets.create("grafana")
behind the scenes Gradle will create the required configurations, grafanaImplementation, grafanaRuntimeOnly, etc, so you can use them without error like this:
val grafanaSourceSet = sourceSets.create("grafana")
dependencies {
"grafanaImplementation"("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
"grafanaRuntimeOnly"("org.slf4j:slf4j-simple:1.7.36")
}
This approach is more like how Groovy works - it basically disables type-checking and the strings will be evaluated during Gradle execution.
Generated DSL accessors
However, string-typing is not why we like Kotlin! We want type-safety and auto completion hints. That's exactly what we see with the implementation() and runtimeOnly(). So how do we get them for grafanaImplementation() and grafanaRuntimeOnly()?
Basically, Gradle will scan the registered config and when it sees that a plugin creates an implementation configuration, it generates Kotlin DSL accessors. However, it can't generate accessors for the build.gradle.kts that contains the definition for the accessors... that's too late. So we need to define the config earlier. We can do that with a buildSrc plugin.
buildSrc Grafana convention plugin
Set up a buildSrc project (this is covered more in the Gradle docs or other StackOverflow answers)
Create a pre-compiled script plugin for Grafana config
// $projectRoot/buildSrc/src/main/kotlin/grafana.convention.gradle.kts
plugins {
// using 'sourceSets' requires the Java plugin, so we must apply it
java
}
val grafanaSourceSet = sourceSets.create("grafana")
Note that this convention plugin is quite opinionated as it applies the Java plugin. In more complex setups you might want to instead react to the Java plugin, rather than always applying it.
Now apply the convention plugin, and Gradle will generate the Kotlin DSL accessors!
// $projectRoot/build.gradle.kts
plugins {
id("grafana.convention")
}
dependencies {
// no string-typing needed!
grafanaImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
grafanaRuntimeOnly("org.slf4j:slf4j-simple:1.7.36")
}

How can I access the dependencies of an application from within the build file of a dependency embedded in the application?

I have a Gradle-based library that is imported as a dependency into consuming applications. In other words, an application that consumes my library will have a build.gradle file with a list of dependencies that includes both my library as well as any other dependencies they wish to import.
From within my library's build.gradle file, I need to write a Gradle task that can access the full set of dependencies declared by the consuming application. In theory, this should be pretty straightforward, but hours of searching has not yielded a working solution yet.
The closest I've come is to follow this example and define an additional task in the library's build.gradle file that runs after the library is built:
build {
doLast {
project.getConfigurations().getByName('runtime')
.resolvedConfiguration
.firstLevelModuleDependencies
.each { println(it.name) }
}
}
I keep getting an error message that the 'runtime' configuration (passed into getByName and referenced in the Gradle forum post I linked) cannot be found. I have tried other common Gradle configurations that I can think of, but I never get any dependencies back from this code.
So: what is the best way to access the full set of dependencies declared by a consuming application from within the build file of one of those dependencies?
Okay, I mostly figured it out. The code snippet is essentially correct, but the configuration I should have been accessing was 'compileClasspath' or 'runtimeClasspath', not 'runtime'. This page helped me understand the configuration I was looking for.
The final build task in the library looks roughly like this:
build {
doLast {
// ...
def deps = project.getConfigurations().getByName('compileClasspath')
.resolvedConfiguration
.firstLevelModuleDependencies
.each {
// it.name will give you the dependency in the standard Gradle format (e.g."org.springframework.boot:spring-boot:1.5.22.RELEASE")
}
}
}

Adding gradle dependencies

I have a simple gradle 7.2 project, with a simple kotlin file, running java 11, on ubuntu 20.04 in vs code
For my project, I need to add some simple dependencies to java.security such that I'll be able to encrypt and hash some things.
So I need to add it as a dependency.
The project is created by running gradle init and picking all the default options.
I then want to be able to do an import like: import java.security.MessageDigest and use the java.security package.
I guess I'll have to add the dependency in the build file, which currently looks like this:
plugins {
// Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin.
id("org.jetbrains.kotlin.jvm") version "1.5.0"
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Align versions of all Kotlin components
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
// This dependency is used by the application.
implementation("com.google.guava:guava:30.1.1-jre")
// Use the Kotlin test library.
testImplementation("org.jetbrains.kotlin:kotlin-test")
// Use the Kotlin JUnit integration.
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
application {
// Define the main class for the application.
mainClass.set("com.what.isthis.AppKt")
}
I now search google high and low for how a reference to the java.security package can be added in gradle, but find absolutely nothing anywhere.
Following a guide like this it looks like I could just add a in this manner:
implementation 'org.springframework.boot:spring-boot-starter-validation:2.4.0'
If what I wanted was a reference to this validation library. But I can never get to test it, because I can't find any info on how I would target java.security anywhere.
Looking at the docsI tried to just grab the names I could find here, but this did not compile:
implementation 'java.security Package'
So yes, how do I get thjis dependency. And in general how do find the names that I need for getting dependencies in general?
java.security package is part of the Java language itself as you can see from the documentation, for this reason you don't need to include it explicitly it should already be available to you.
Please make sure you have proper Java SDK set up in IDE. Try to configure different distribution/type than you use currently.
Even if you have logic in Kotlin class it should properly resolve an import and compile.
import java.security.MessageDigest
fun main() {
val test = MessageDigest.getInstance("SHA-256")
println("Test Succeeded")
}
You're not finding examples of declaring java.security packages in Gradle because you don't need to declare them; they're included in the JDK so you can import them natively in any class without declaring them in gradle. Try creating this class in any given package within your project and running it. It should succeed.
import java.security.MessageDigest;
public class Test {
public static void main(String[] args) throws Exception {
MessageDigest test = MessageDigest.getInstance("SHA-256");
System.out.println("Test Succeeded");
}
}

How can I use a dependencyManagement version with a classifier with Spring's Gradle dependency management plugin?

Per dependency-management-plugin#67, a classifier cannot be specified within the dependencySet block. This limitation is discussed in a related question (Is it possible to set a dependencySet entry's classifier using Spring's Gradle dependency management plugin).
dependencyManagement {
dependencies {
dependencySet(group:'com.querydsl', version: '4.2.2') {
entry 'querydsl-apt' // This needs to use the "general" classifier
entry 'querydsl-mongodb'
}
}
}
dependencies {
annotationProcessor 'com.querydsl:querydsl-apt:4.2.2:general' // Version needed to use a classifier
implementation 'com.querydsl:querydsl-mongodb'
}
One workaround to this limitation would be to use an ext block, and define a version variable:
ext {
querydslVersion = 4.2.2
}
dependencyManagement {
dependencies {
dependencySet(group:'com.querydsl', version: querydslVersion) {
entry 'querydsl-mongodb'
}
}
}
dependencies {
annotationProcessor "com.querydsl:querydsl-apt:$querydslVersion:general" // Version needed to use a classifier
implementation 'com.querydsl:querydsl-mongodb'
}
A downside to this approach are that it requires setting a property that wouldn't otherwise be set (and might need to be made available between modules in a multi-module plugin, making the build less obvious). It also doesn't work particularly well if the dependency version is transitively pulled in via a BOM (e.g. imports { mavenBom 'org.springframework.boot:spring-boot-dependencies:2.3.1.RELEASE'}, since that requires manually keeping the version in sync with the BOM's value.
Is there still a way to use the version defined in the dependency management section, despite this limitation?
The Spring Dependency Management Plugin gives programmatic access to the managed versions by way of the managedVersions map. This can be used to get the dependency version of the artifact, which can be used to specify the version to use:
dependencies {
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.managedVersions['com.querydsl:querydsl-apt']}:general"
implementation 'com.querydsl:querydsl-mongodb'
}

Using Gradle 5.1 "implementation platform" instead of Spring Dependency Management Plugin

I have written a Gradle Plugin that contains a bunch of common setup configuration so that all of our projects just need to apply that plugin and a set of dependencies. It uses the Spring Dependency Management Plugin to setup the BOM imports for Spring as shown in the code snippet below:
trait ConfigureDependencyManagement {
void configureDependencyManagement(final Project project) {
assert project != null
project.apply(plugin: "io.spring.dependency-management")
final DependencyManagementExtension dependencyManagementExtension = project.extensions.findByType(DependencyManagementExtension)
dependencyManagementExtension.imports {
mavenBom "org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE"
}
}
}
Whilst that still works in Gradle 5.1 I wanted to replace the Spring Dependency Management Plugin with the new dependency mechanism for BOM Imports so I updated the above to now be this:
trait ConfigureDependencyManagement {
void configureDependencyManagement(final Project project) {
assert project != null
project.dependencies.platform("org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE")
}
}
Unfortunately that change means none of the dependencies defined by these BOMs are being imported and I get errors like these when building projects?
Could not find org.springframework.boot:spring-boot-starter-web:.
Required by:
project :
Could not find org.springframework.boot:spring-boot-starter-data-jpa:.
Required by:
project :
Could not find org.springframework.boot:spring-boot-starter-security:.
Required by:
project :
Am I correct in thinking the Spring Dependency Management Plugin is no longer needed with Gradle 5.1 and if so then am I missing something for this to work?
The platform support in Gradle 5 can replace the Spring dependency management plugins for BOM consumption. However the Spring plugin offers features that are not covered by the Gradle support.
Regarding your issue, the problem comes from the following line:
project.dependencies.platform("org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE")
This will simply create a Dependency, it still needs to be added to a configuration. by doing something like:
def platform = project.dependencies.platform("org.springframework.boot:spring-boot-dependencies:2.1.0.RELEASE")
project.dependencies.add("configurationName", platform)
where configurationName is the name of the configuration that requires the BOM. Note that you may have to add this BOM to multiple configurations, depending on your project.

Resources