Getting a list of all dependencies in the Versions Catalogue from Gradle v7+ - gradle

Gradle 7 introduced a versions catalogue. With it I can easily refer to a dependency as e.g. libs.jacksonCore if it is defined in gradle/libs.versions.toml:
[versions]
jackson = "2.11.1"
[libraries]
jacksonCore = { module = "com.fasterxml.jackson.core:jackson-core", version.ref = "jackson" }
But is there a way to programmatically get a list of all the defined dependencies?
Right now I use reflection on the libs object (which is of class org.gradle.accessors.dm.LibrariesForLibs) as a workaround, but that's really ugly:
Map deps = libs.metaClass.methods
.findAll { it.returnType.name.endsWith("provider.Provider") }
.findAll { it.name.startsWith("get") }
.collect { libs."$it.name"().get() }
.collectEntries { [
(it.getModule().toString()): it.getVersionConstraint().toString()
] }

I used the reflection hack in the OP since I couldn't get findDependency() to work on the already-defined libs in Gradle 7.3 (it worked in 7.2). By fetching the VersionCatalog manually I managed to get rid of the hack:
def libz = rootProject.extensions
.getByType(VersionCatalogsExtension).named("libs")
def deps = libz.getDependencyAliases()
.collect { libz.findDependency(it).get().get() }
.collectEntries {
[(it.getModule().toString()): it.getVersionConstraint().toString()]
}
I'd still be interested in other improvements, though.

Related

no build output compiled for common module of Kotlin Multiplatform project

I'm trying to figure out why dependent projects for my Kotlin MPP library don't see any provided modules in their common modules even though the targets (jvm, android) can see them.
Published via maven-publish.
The /build directory for the library contains nothing I can identify as an intermediate representation of my common modules, leading me to think that I need to explicitly tell Gradle to produce the files to be included as common in the published package.
As it is, the .aar and .jar files produced in the android and desktop (jvm) modules each look normal, but the published common module is empty.
I need that common module to be populated before I can code against it inside the common module of dependent projects.
Here is the relevant section of my build.gradle.kts. I omit the repository config as it appears to work.
I basically followed the instructions from kotlinlang.org.
I've looked at the maven-publish plugin configuration, the settings for the kotlin-multiplatformm plugin, and the configured project structure.
kotlin version is 1.6.10, unable to update due to Jetbrains Compose dependency.
plugins {
kotlin("multiplatform")
id("com.android.library")
id("maven-publish")
}
kotlin {
android {
publishLibraryVariants = listOf("release", "debug")
}
jvm("desktop") {
compilations.all {
kotlinOptions {
jvmTarget = "11"
}
}
}
val publicationsFromMainHost = listOf(jvm("desktop").name, "kotlinMultiplatform")
publishing {
publications {
matching { it.name in publicationsFromMainHost }.all {
val targetPublication = this#all
tasks.withType<AbstractPublishToMaven>()
.matching { it.publication == targetPublication }
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.3.2")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val androidMain by getting {
dependencies {
implementation("androidx.startup:startup-runtime:1.1.1")
}
}
val androidTest by getting {
dependencies {
implementation("junit:junit:4.13.2")
implementation("androidx.test:core:1.4.0")
implementation("androidx.test:runner:1.4.0")
implementation("androidx.test:rules:1.4.0")
implementation("org.robolectric:robolectric:4.6.1")
}
}
val desktopMain by getting
val desktopTest by getting {
dependencies {
implementation("junit:junit:4.13.2")
}
}
}
}
The answer is to manually supply the Kotlin stdlib dependency, rather than relying on the gradle plugin to add it.
When there are only jvm-based builds present, commonMain will be built with platform type of jdk8 rather than common. By making an explicit dependency on stdlib-common, it will be coerced back to the common platform, and then the correct metadata will be created and published.
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
}
}
}
}

Gradle 7.2 Version Catalog specify library build type

I'm refactoring a multi module project with version catalogs and I have to add a dependency that is currently like this:
implementation com.mygroup:my-artifact:1.0.0:debug#aar
Since version catalogs doesn't allow to specify the aar type, a workaround would be to specify it directly in the gradle file like this:
implementation(libs.myDependency) { artifact { type = 'aar' } }
This works, but there's an extra complexity: I need to also specify the build type, in the example from above is debug, I cannot find a way to add it.
What I've tried is:
TOML
[libraries]
myDependency = { module = "com.mygroup:my-artifact", version = "1.0.0:debug" }
Gradle
implementation(libs.myDependency) { artifact { type = 'aar' } }
For some reason this doesn't work, how can I also specify the build type?
Found a way to do this! Need to add the classifier into the artifact.
So for the given regular declaration:
build.gradle
dependencies {
implementation com.mygroup:my-artifact:1.0.0:debug#aar
}
The version catalogs way would be:
TOML
[libraries]
myDependency = { module = "com.mygroup:my-artifact", version = "1.0.0" }
build.gradle
dependencies {
implementation(libs.myDependency) { artifact { classifier = 'debug'; type = 'aar' } }
}
or (multiline)
build.gradle
dependencies {
implementation(libs.myDependency) {
artifact {
classifier = 'debug'
type = 'aar'
}
}
}

How to add a dependency in a multiplatform kotlin / native intellij project?

I have the following build.gradle configuration:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.41'
}
repositories {
mavenCentral()
}
kotlin {
linuxX64("linux") {
binaries {
executable {
entryPoint = 'sample.main'
runTask?.args('')
}
}
}
sourceSets {
linuxMain {
dependencies {
api("org.http4k:http4k-core:3.183.0")
}
}
linuxTest {
}
}
}
And the following source file src/linuxMain/kotlin/sample/SampleLinux.kt :
package sample
fun hello(): String = "Hello, Kotlin/Native!"
fun main() {
println(hello())
}
How to add a external library in order to be able to use autocomplete in imports for the library org.http4k:http4k-core:3.183.0?
As you can see, I tried to add the line api("org.http4k:http4k-core:3.183.0") in linuxMain dependencies, but although intellij show the library in External Libraries section, I cannot work with the packages neither classes of http4k in SampleLinux.kt file: any org.http4k..... import attempt is not recognized and generates compilation error.
After a quick look, I am almost sure that http4k is JVM-only library, at least for now. According to this issue, they are still waiting for Native to grow. If you are interested, it would be nice if one can ask the library maintainers again. As far as K/N has grown a lot by the last year, maybe they change their mind.

Gradle Kotlin DSL with wsdl2java

Migrating from Groovy to Kotlin and stumbled on a simple problem on wsdl2java generation.
Question is simple, does anyone have good example with it. Google wasn't very helpful and not good in Kotlin DSL yet also syntax wise.
Also using OpenJDK11.
plugins {
id("no.nils.wsdl2java") version "0.10"
}
wsdl2java {
enabled = true
wsdlsToGenerate = [
[
"-xjc",
"-p", "bla.bla.generated",
"-wsdlLocation", "classpath:wsdl/v1.wsdl",
"-autoNameResolution", "$projectDir/src/main/resources/wsdl/v1.wsdl"
],
[
"-xjc",
"-p", "bla.bla.generated",
"-wsdlLocation", "classpath:wsdl/v2.wsdl",
"-autoNameResolution", "$projectDir/src/main/resources/wsdl/v2.wsdl"
]]
generatedWsdlDir = file("$projectDir/src/main/java")
wsdlDir = file("$projectDir/src/main/resources/wsdl")
}
dependencies {
implementation(project(":common"))
implementation(project(":etcd"))
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-hateoas")
implementation("org.springframework.boot:spring-boot-starter-quartz")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-web-services")
api("no.nils:wsdl2java")
compileOnly("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
}
tasks.jar {
archiveFileName.set("ext.jar")
}
I got wsdl2java working through trial and error with the following:
plugins {
id("no.nils.wsdl2java") version "0.10"
}
wsdl2javaExt {
cxfVersion = "3.3.0"
deleteGeneratedSourcesOnClean = true
}
tasks.withType<no.nils.wsdl2java.Wsdl2JavaTask> {
// The use of ArrayList(listOf) is necessary as the Wsdl2JavaTask seems to make inline changes to its arguments
wsdlsToGenerate = listOf(
ArrayList(listOf("-p", "dk.grydholt.integration.sacho",
"-autoNameResolution", "-xjc-npa",
"-wsdlLocation", "classpath:wsdl/sacho/EduModelService.wsdl",
"$projectDir/src/main/resources/wsdl/sacho/EduModelService.wsdl")))
generatedWsdlDir = file("$projectDir/src/generated/java")
wsdlDir = file("$projectDir/src/main/resources/wsdl/sacho")
}
sourceSets {
create("generated") {
java.srcDirs(listOf("src/generated/java"))
}
}
Notice the use of ArrayList. It took me some time to debug as you'll get strange type errors if you do listOf(listOf("...")).
you could do it like:
plugins {
id("no.nils.wsdl2java") version "0.12"
}
dependencies {
// SOAP dependencies
implementation("org.springframework.boot:spring-boot-starter-web-services") {
exclude(module = "spring-boot-starter-tomcat")
}
implementation("org.glassfish.jaxb:jaxb-runtime")
implementation("org.apache.cxf.xjc-utils:cxf-xjc-runtime:3.3.1")
}
wsdl2java {
wsdlDir = file("$projectDir/src/main/wsdl")
wsdlsToGenerate = listOf(
// look here for other parameters: https://cxf.apache.org/docs/wsdl-to-java.html
listOf(
// activate plugin to add a toString() method to generated classes
// equivalent to: -Xts:style:org.apache.cxf.xjc.runtime.JAXBToStringStyle.DEFAULT_STYLE
"-xjc-Xts",
// generate getters methods for Booleans
"-xjc-Xbg",
// adds the #Generated annotation to classes generated.
"-mark-generated",
// automatically resolve naming conflicts without requiring the use of binding customizations.
"-autoNameResolution",
// map each of the namespaces to its own java package
// this is done 'cause the namespaces are conflicting between the different WSDLs files
// we have, which is leading to class overwriting during code generation
// you should look up these URLs in the WSDLs and come with package names in case
// you find out about conflicts
"-p", "http://xxx/xi/A1S/Global=e.r.t.y",
"-p", "http://xxx/xi/A1S/Global=e.r.t.ye",
"-p", "http://xxx/xi/A1S/Global=e.r.t.xer",
"$wsdlDir/mywsdl.wsdl"
)
)
}
however, `no.nils.wsdl2java` plugin does not work for gradle 7.*

How do I get IntelliJ to recognize gradle generated sources dir?

So I have an XJC javaExec that spins like a top but IntelliJ doesn't recognize the generated output despite having marked generated-src/java as such. Do I need to tweak the idea plug-in or something?
Note: The plug-in itself is loaded in subProjects from the root build.gradle.
XJC Project:
description = "Generates sources and compiles them into a Jar for $project"
configurations { xjc }
dependencies {
xjc 'org.glassfish.jaxb:jaxb-xjc:2.2.11'
xjc 'org.glassfish.jaxb:jaxb-runtime:2.2.11'
}
task xjc (type:JavaExec) {
doFirst{
File generatedSrcDir = file("$buildDir/generated-src/java")
if (!generatedSrcDir.exists()) {
generatedSrcDir.mkdirs()
}
}
main = "com.sun.tools.xjc.XJCFacade"
classpath configurations.xjc
def argsList = [
"-mark-generated",
"-no-header",
"-verbose", // or -quiet or nothing for default.
"-target", "2.1",
"-encoding", "UTF-8",
"-d", "$buildDir/generated-src/java",
"-catalog","$projectDir/src/main/resources/commons-gradle.cat",
file("$projectDir/src/main/resources/v1/") ]
args argsList
inputs.files files(file("$projectDir/src/main/resources/v1/"))
outputs.files files(file("$buildDir/generated-src/java"),file("$buildDir/classes"))
}
compileJava {
dependsOn xjc
source "${buildDir}/generated-src"
}
In the project that depends on this one I simply have:
compile project(":path:to:schemas:the-test-schema")
I've tried:
idea {
module {
def buildDir = file("$buildDir")
def generatedDir = file("$buildDir/generated-src")
def listOfDirs = []
buildDir.eachDir { file ->
if (file.name != buildDir.name && file.name != generatedDir.name)
listOfDirs.add(file)
}
excludeDirs = listOfDirs.toArray()
generatedSourceDirs += file("$buildDir/generated-src/java")
scopes.COMPILE.plus += [ configurations.xjc ]
}
}
I'll point out a solution by Daniel Dekany, from a Gradle discussion thread actually linking to this question. To quote:
apply plugin: "idea"
...
sourceSets.main.java.srcDir new File(buildDir, 'generated/javacc')
idea {
module {
// Marks the already(!) added srcDir as "generated"
generatedSourceDirs += file('build/generated/javacc')
}
}
Works well for me.
The code of this answer, rewritten using Kotlin DSL, will look like this:
plugins {
idea
}
val generatedSourcesPath = file("out/production/classes/generated")
java.sourceSets["main"].java.srcDir(generatedSourcesPath)
idea {
module {
generatedSourceDirs.add(generatedSourcesPath)
}
}
In my case, it didn't work unless I added the generate sources directory to both sourceDirs and generatedSourceDirs:
def generatedSourcesDir = file('src/generated/main/java')
idea {
module {
sourceDirs += generatedSourcesDir
generatedSourceDirs += generatedSourcesDir
}
}
in 2020 you probably did not refresh the project in IDEA
because it actually works oob.
30 mins of reading outdated solutions :(
It's happening in some versions. There are some issues that we can look at and read carefully.
But for myself, from the IntelliJ IDEA 2019 the solutions below aren't working anymore:
https://youtrack.jetbrains.com/issue/IDEA-210065 (it says Obsolete)
https://youtrack.jetbrains.com/issue/IDEA-152581 (it's saying Fixed here)
https://youtrack.jetbrains.com/issue/IDEA-117540/generated-sources-inside-output-directory-are-excluded-by-default
https://intellij-support.jetbrains.com/hc/en-us/community/posts/4906059373074-Class-defined-in-generated-sources-not-found-by-Intellij-editor-but-found-by-compiler-gradle-build-
Discussion in the Gradle forum about this: https://discuss.gradle.org/t/how-do-i-get-intellij-to-recognize-gradle-generated-sources-dir/16847
According to #Daniel Dekany, this worked in IDEA 2017.1.2, and worked for me until 2019:
plugins {
id 'idea'
}
idea {
module {
generatedSourceDirs += file('build/generated/sources/annotationProcessor')
}
}
But from 2019 to 2022, the solution that worked for me was:
def generatedDir = "${buildDir}/generated/sources"
sourceSets {
main {
java {
srcDir generatedDir
}
}
}
idea {
module {
generatedSourceDirs.addAll(file(generatedDir))
}
}
ext {
// path to IDEA generated sources directory
ideaGeneratedSourcesDir = "$projectDir/src/main/generated"
}
compileJava {
//……
options.annotationProcessorGeneratedSourcesDirectory = file(ideaGeneratedSourcesDir)
//options.headerOutputDirectory.set(file(ideaGeneratedSourcesDir)) (tested no effect)
//……
}
// above work for me, and i try all method this question mentioned it's not work! env: idea2019.3, wrapped gradle6.3-all, zh-CN, JDK8, [x] annotation processing is disabled(no effect, in global settings ), no idea plugin([x]plugins {id idea}), [x]sourceSets no need to set(genereated srcDir)
myCodeGenExample:
task vertxCodeGen(type: JavaCompile) {
group 'build'
source = sourceSets.main.java
destinationDir = file(ideaGeneratedSourcesDir)
classpath = configurations.compileClasspath
options.annotationProcessorPath = configurations.annotationProcessor
options.debugOptions.debugLevel = "source,lines,vars"
options.compilerArgs = [
"-proc:only",
"-processor", "io.vertx.codegen.CodeGenProcessor",
// where the non Java classes / non resources are stored (mandatory) - the processors requires this option to know where to place them
"-Acodegen.output=$destinationDir.absolutePath",
]
}
refresh the gradle, continously exist

Resources