gradle default configuration, what is it and how can I define it - gradle

I am having a weird error, for which I found a lot of hits in google but most about android studio or library imports and I don't use android studio nor am I trying to build any app/library so I'll try and ask here and see if I understand the background of it.
I have a project in which I have this plugin:
https://gitlab.com/zkovari/gradle-mermaid-plugin/-/blob/master/examples/single-project/build.gradle
This is a plugin that displays my dependencies as a mermaid graph.
Everything was fine until today I updated some dependencies and created a sub-project to do something else.
I'm trying to generate the graph again and somehow it's failing with this error message.
> Task :generateMermaidDependenciesDiagram FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':generateMermaidDependenciesDiagram'.
> Configuration with name 'default' not found.
I can see in the source code of the plugin that it automatically sets some configurations
#Override
public void apply(Project project) {
GenerateMermaidDependenciesDiagram generateDependencyDiagramsTask = project.getTasks()
.create(GENERATE_MERMAID_DEPENDENCIES_DIAGRAM_TASK_NAME, GenerateMermaidDependenciesDiagram.class);
generateDependencyDiagramsTask.setConfiguration("default");
generateDependencyDiagramsTask
.setOutput(project.getBuildDir().toPath().resolve("mermaid/dependencies.mmd").toFile());
generateDependencyDiagramsTask.setDiagramGenerator(new MermaidDiagramGenerator());
}
So my question is a bit high level but what is the "default" configuration?
And in my project I don't really have any configuration block I simply have my dependencies:
dependencies {
implementation group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: awsVersion, transitive: false
...
testCompile group: 'org.slf4j', name: 'slf4j-simple', version: slf4jVersion
}
My structure looks like this:
project:
-- build.gradle
-- settings.gradle
-- sub-project:
--- build.gradle
I think this stopped working when I added my sub-project but the plugin is applied at the root project level.
I do have a dependency between my sub-project and my root project (one of my sub-project tasks depends on the root project)
I'm trying to understand that this might be very similar but I'm not fully getting it.
Gradle: What Is The Default Configuration and How Do I Change It
I do apply the java plugin on my main project so I expect the configuration.default should exist.
Even if I think I shouldn't do it I tried to re-define a default configuration extending implementation but that did not work
https://docs.gradle.org/current/userguide/declaring_dependencies.html
configurations {
default.extendsFrom implementation
}
build file 'C:\dev\repo\connector-custom\build.gradle': 66: unexpected token: default # line 66, column 5.
default.extendsFrom implementation
I did a quick test and removing my subproject did work so I know the problem is there but no idea why.
It means somehow I must pass to my subproject the default configuration of the main project?

Related

JavaFX and Gradle: What is the correct way to load a default view?

I keep getting "Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0."
I've looked and tried a dozen fixes and tutorials all with the same error. I've moved the view to the every folder and renamed it incase underscores aren't allowed. I've tried every permutation of "/path/file.fxml" I can think of
I have a feeling my code is depreciated but all I can do is get intellij to highlight .load()
Here is my code:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ScoreSheet extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new
FXMLLoader(ScoreSheet.class.getResource("views/main_menu.fxml"));
primaryStage.setTitle("Score Sheet");
Group root = new Group();
Scene scene = new Scene(fxmlLoader.load(), 405, 720);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Here is my stacktrace:
Starting Gradle Daemon...
Connected to the target VM, address: '127.0.0.1:51285', transport: 'socket'
Gradle Daemon started in 616 ms
> Configure project :
Found module name 'ScoreSheetTest.main'
Disconnected from the target VM, address: '127.0.0.1:51285', transport: 'socket'
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :jar UP-TO-DATE
Connected to the target VM, address: 'localhost:51290', transport: 'socket'
Disconnected from the target VM, address: 'localhost:51290', transport: 'socket'
Connected to the target VM, address: '127.0.0.1:51285', transport: 'socket'
> Task :ScoreSheet.main() FAILED
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.2/userguide/command_line_interface.html#sec:command_line_warnings
3 actionable tasks: 1 executed, 2 up-to-date
Exception in Application start method
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalStateException: Location is not set.
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2541)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
at ScoreSheetTest.main/com.company.scoresheet.ScoreSheet.start(ScoreSheet.java:16)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':ScoreSheet.main()'.
> Process 'command '/Users/username/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1
BUILD FAILED in 4s
Disconnected from the target VM, address: '127.0.0.1:51285', transport: 'socket'
2:05:57 PM: Execution finished ':ScoreSheet.main()'.
Edit: File structure image
Edit 2: Here is my build.gradle:
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
group 'com.iharptech'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
implementation 'org.openjfx:javafx-controls:18'
}
test {
useJUnitPlatform()
}
sourceSets {
main {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.fxml"]
}
}
}
Gradle Deprecation Warnings
These warnings are almost certainly not related to your IllegalStateException.
If you want to know which deprecated features were used, then you can do what the warning message says and use --warning-mode all. If the features were used by your own build script, then you can look up the replacements and fix the problem yourself. However, if the features were used by a plugin then really your only options are: (1) Update to use the latest version of the plugin; (2) If already using the latest version, submit a bug report with the plugin authors (if one doesn't already exist); (3) Maybe, if possible, use a different plugin.
Using Gradle with an IDE
When you use a build tool such as Gradle (or e.g., Maven), then you should let the build tool handle all dependencies and other configurations (as much as is possible). In other words, you should be declaring the JavaFX dependencies in your build script, not in IntelliJ.
You should also have the IDE delegate build and run tasks to Gradle. That way Gradle is responsible for everything build related, and the IDE is only responsible for making it easier to write code.
IntelliJ works really well with Gradle. Any dependencies you add to Gradle will be known by IntelliJ. And any tasks supplied by Gradle will also be known by IntelliJ.
Declare JavaFX Dependencies in Gradle
You're using the OpenJFX javafx-gradle-plugin. That project's README has documentation for how to declare which JavaFX modules you need for your project. Note the latest version of this plugin is 0.0.12. You should update your build script to use that version.
Local JavaFX SDK
If you're using a downloaded JavaFX SDK, as your comments seem to imply, then you can use:
javafx {
sdk = '/path/to/sdk' // replace with your own path
modules = ['javafx.controls', 'javafx.fxml'] // modify list as needed
}
For the sdk path, you may want to setup a variable that is then passed by the person who invokes Gradle. That way people on other computers can still build your project without modifying the build script. Though if this is a personal project on a single computer then a static, absolute path should be fine for now.
I don't know when this feature was added to the plugin, so you may need to update to the latest version.
Maven Central JavaFX JARs
You could instead have Gradle download the needed JavaFX JAR files from Maven Central.
javafx {
modules = ['javafx.controls', 'javafx.fxml'] // modify list as needed
version = '18' // change version as needed
}
repositories {
mavenCentral()
}
Executing Gradle Tasks
You should make run configurations to execute Gradle tasks, rather than letting the IDE use its own build and execution system.
To execute any Gradle task via IntelliJ, you can open up the Gradle tab (typically on the right side of IntelliJ, if I'm not mistaken), select a task, and execute it.
Or you could manually create a "run configuration". Make sure to choose "Gradle" when selecting the type of configuration. Tell it which project the task is for and which task to execute.
The Application Plugin
Typically, with JVM projects, when you want to be able to execute your project you should apply the application plugin.
plugins {
// other plugins...
'application'
}
You already do this. But you also need to configure the main class and, if present, the main module.
application {
mainModule = '<module-name>'
mainClass = '<fully-qualified-class-name>'
}
The application plugin adds the run task. To execute your project, have IntelliJ execute the run task.
Resources
For general information about resources, how to load them, what paths to use, and some troubleshooting techniques, I recommend this Q&A:
How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?
But specifically regarding your setup, you should remove this part from your Gradle build script:
sourceSets {
main {
resources {
srcDirs = ["src/main/java"]
includes = ["**/*.fxml"]
}
}
}
It's not needed. Keeping it means src/main/resources is no longer considered a resource root, which you probably do not want.
With that change, and executing the project via the run task, using "/views/main_menu.fxml" should work for you as the resource path.

How to execute gradle task during project import in Intellij Idea

Let's assume my build.gradle file contains task generateSources which as name suggests generates additional java files. It's easy to ensure that generateSources is executed before compileJava: compileJava.dependsOn generateSources. How can I make sure generateSources is called when importing project into Intellij Idea as well?
To elaborate on #vladimir-sitnikov's answer: I added the idea-ext-plugin to my root project:
apply plugin: 'org.jetbrains.gradle.plugin.idea-ext'
// ...
buildscript {
dependencies {
classpath "org.jetbrains.gradle.plugin.idea-ext:org.jetbrains.gradle.plugin.idea-ext.gradle.plugin:0.7"
}
}
Because without that I wasn't able to use it in my sub project, but now it works like this:
idea.project.settings.taskTriggers {
beforeSync tasks.getByName("generateSources")
}
Adding the plugin to the sub-project only didn't do it.
Note: The plugin's documentation is kind of limited, but in "DSL spec v. 0.2" is stated
beforeSync - before each Gradle project sync. Will NOT be executed on initial import
Didn't try that, but it works with existing projects.
This can be done via id("org.jetbrains.gradle.plugin.idea-ext") plugin (https://github.com/JetBrains/gradle-idea-ext-plugin).
See sample code in Gradle sources: https://github.com/gradle/gradle/blob/135fb4751faf2736c231636e8a2a92d47706a3b9/buildSrc/subprojects/ide/src/main/kotlin/org/gradle/gradlebuild/ide/IdePlugin.kt#L147
You can set the task in Gradle tool window: Execute Before Sync:

InvokeDynamic not supported when building for Android

I'm running Gluon/charm version 3.0.0. I added a Java8-compiled library into my JavaFX project (created via the IntelliJ plugin) and on iOS it works and builds as expected, but when executing the gradle tasks android or androidInstall I get this error back:
[ant:java] Java Result: 1
:createMainDexList FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':createMainDexList'.
> Exception in thread "main" com.android.dx.cf.iface.ParseException: InvokeDynamic not supported
at com.android.dx.cf.cst.ConstantPoolParser.determineOffsets(ConstantPoolParser.java:226)
at com.android.dx.cf.cst.ConstantPoolParser.parse(ConstantPoolParser.java:132)
at com.android.dx.cf.cst.ConstantPoolParser.parseIfNecessary(ConstantPoolParser.java:124)
at com.android.dx.cf.cst.ConstantPoolParser.getPool(ConstantPoolParser.java:115)
at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:491)
at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
at com.android.dx.cf.direct.DirectClassFile.parseToEndIfNecessary(DirectClassFile.java:397)
at com.android.dx.cf.direct.DirectClassFile.getAttributes(DirectClassFile.java:311)
at com.android.multidex.MainDexListBuilder.hasRuntimeVisibleAnnotation(MainDexListBuilder.java:191)
at com.android.multidex.MainDexListBuilder.keepAnnotated(MainDexListBuilder.java:167)
at com.android.multidex.MainDexListBuilder.<init>(MainDexListBuilder.java:121)
at com.android.multidex.MainDexListBuilder.main(MainDexListBuilder.java:91)
at com.android.multidex.ClassReferenceListBuilder.main(ClassReferenceListBuilder.java:58)
...while preparsing cst 0002 at offset 0000000f
...while parsing de/<removed>/traffic_light/library/Test.class
What I find a bit weird is that I don't even have a Test class for traffic_light, not even in the library. Searching for the error I found that it probably needs Java 8 to invokeDynamic/Support Lambdas, but for example Gluon's Presenter itself uses Lambdas.
Also, googling I find this hit about the same issue but sadly Gluon removed their forum and the page isn't cached anywhere.
Typically this error happens when you add some third party dependencies to the project that use lambda expressions, since currently the retrolambda plugin is applied to the source code of your project only.
You can try:
Remove that dependency and add its source code instead.
Apply retrolambda to the original dependency, and then add it to your project.
Or use the most recent jfxmobile plugin: the 1.0.10-SNAPSHOT will apply retrolambda to both the source code and the third party dependencies (even if no source code is provided).
For the last option, just change the jfxmobile plugin version on top of your build.gradle file:
buildscript {
repositories {
jcenter()
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.0.10-SNAPSHOT'
}
}

gradle: how to write a groovy task

I've been trying to work through the user guide. This seems like an incredibly simple thing I want to do, but I just can't figure out how to make it work.
I want to write an external groovy file to define a task, then call that task in build.gradle. Here's my build.gradle file:
// Apply the groovy plugin to add support for Groovy
apply plugin: 'groovy'
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'jcenter' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
// In this section you declare the dependencies for your production and test code
dependencies {
// We use the latest groovy 2.x version for building this library
compile 'org.codehaus.groovy:groovy-all:2.4.7'
compile gradleApi()
compile localGroovy()
// We use the awesome Spock testing and specification framework
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile 'junit:junit:4.12'
}
task myTask (type: my.package.MyTask)
Then, under src/main/groovy/my/package I have MyTask.groovy:
package my.package
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class MyTask extends DefaultTask {
String greeting = 'hello from MyTask'
#TaskAction
def greet(){
println greeting
}
}
I can't even list the tasks:
$ gradle tasks
FAILURE: Build failed with an exception.
* Where:
Build file '/projects/gradle/build.gradle' line: 21
* What went wrong:
A problem occurred evaluating root project 'gradle'.
> Could not get unknown property 'my' for root project 'gradle' of type org.gradle.api.Project.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 3.193 secs
At this point, I have absolutely no idea what's going on or how to do what I want. This seems like the most simple possible example but following the user guide has gotten me nowhere. No matter what I do, I can't get past that exception.
How do I write a groovy file and use that to define a new task in the build file?
You have to place your groovy files under:
rootProjectDir/buildSrc/src/main/groovy
Reference:
https://docs.gradle.org/current/userguide/custom_tasks.html#N14573
EDIT
I never tried changing the location of buildSrc but it appears to be an unresolved issue:
https://issues.gradle.org/browse/GRADLE-2816
(correct it if I'm wrong)
Now that you've got your src moved to buildSrc you'll also need to fix a small typo in MyTask.groovy:
Instead of
import org.gradle.api.tasks.DefaultTask
use
import org.gradle.api.tasks.TaskAction
That ought to fix your #TaskAction annotation.

Creating a post build copy task with Gradle

I am struggling with the Gradle build lifecycle; specifically with the split between the configuration and execution phases. I have read a number of sections in the Gradle manual and have seen a number of ideas online, but have not found a solution to the following problem:
I want to run a specific task to produce an artifact at the end of my java-library-distribution build that is a flattened version of the runtime configuration jars. That is, I only want to produce the artifact when I run the specific task to create the artifact.
I have created the following task:
task packageSamplerTask(type: Tar, dependsOn: distTar) {
description "Packages the build jars including dependencies as a flattened tar file. Artifact: ${distsDir}/${archivesBaseName}-${version}.tar"
from tarTree("${distsDir}/${archivesBaseName}-${version}.tar").files
classifier = 'dist'
into "${distsDir}/${archivesBaseName}-dist-${version}.tar"
}
Although this task does produce the required artifact, the task runs during gradle's configuration phase. This behavior has the following consequences:
Irrespective of which task I run from the command line, this packageSamplerTask task is always run, often unnecessarily; and
If I clean the project, then the build fails on the next run because $distsDir doesn't exist during the configuration phase (obviously).
It appears that if I extend the Copy task in this manner I'm always going to get this kind of premature behavior.
Is there a way to use the << closure / doLast declarations to get what I want? Or is there something else I'm missing / should be doing?
Update
After further work I have clarified my requirements, and resolved my question as follows (specifically):
"I want to package my code and my code's dependencies as a flat archive of jars that can be deployed as a jMeter plugin. The package can then be installed by unpacking into the jMeter lib/ext directory, as is. The package, therefore, must not include the jMeter jars (and their dependencies) which are used for building and testing"
Because Gradle doesn't appear to support the Maven-like provided dependency management, I created a new configuration for my package which excludes the jMeter jars.
configurations {
jmpackage {
extendsFrom runtime
exclude group: 'org.apache.jmeter', name: 'ApacheJMeter_core', version: '2.11'
exclude group: 'org.apache.jmeter', name: 'ApacheJMeter_java', version: '2.11'
}
}
And then created the following task (using the closure recommendation from Peter Niederwieser):
task packageSamplerTask(type: Tar, dependsOn: assemble) {
from { libsDir }
from { configurations.jmpackage.getAsFileTree() }
classifier = 'dist'
}
This solution appears to work, and it allows me to use just theGradle java plugin, too.
The task declaration is fine, but the flattening needs to be deferred too:
...
from { tarTree("${distsDir}/${archivesBaseName}-${version}.tar").files }
Also, the Tar file should be referred to in a more abstract way. For example:
from { tarTree(distTar.archivePath).files }
First your task isn't executed in the configuration phase but like EVERY task it is configured in that phase. And your closure is just a configuration of your task (a Configuration closure, not an Action closure). That is why your code is "executed" in the configuration phase".
If you want your code to be executed in the execution phase have to write it in a doLastclosure or doFirst. But in your case it is better to keep it in a configuration closure, because you are configuring your task.
To make sure your build doesn't fail because of the missing folder, you can create it with distsDir.mkdirs().

Resources