gradlejavafx

Example of Using ObservableValue.subscribe() In Gradle


Could someone give a complete example of calling ObservableValue.subscribe() from a Gradle project?

Doing the following results in error: cannot find symbol on subscribe():

SimpleObjectProperty<Object> prop = new SimpleObjectProperty<Object>(null);
prop.subscribe(new Consumer<Object>() { public void accept(Object t) {} });

The subscribe() function was added in JavaFX 21, and I suspect Gradle is using an older version that does not have it, but I cannot figure out how to get Gradle to pick up the new version (if that even is the real problem). I am at my whits end on this.

My build.gradle.kt:

repositories {
  mavenCentral()
}

plugins {
  java
  application
  id("org.openjfx.javafxplugin") version "0.1.0"
}

javafx {
  version = "24"
  modules("javafx.base")
}

application {
  mainClass = "Main"
}

My src/java/main/Main.java:

import java.util.function.Consumer;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.stage.Stage;

public class Main extends Application {
  public static void main(String[] args) { launch(args); }
  @Override public void start(Stage stage) {
    ObservableValue<Object> prop = new SimpleObjectProperty<Object>(null);
    prop.subscribe(new Consumer<Object>() { public void accept(Object t) {} });
  }
}

The compilation result:

$ ./gradlew build

> Task :compileJava FAILED
/home/user/question/src/main/java/Main.java:11: error: cannot find symbol
    prop.subscribe(new Consumer<Object>() { public void accept(Object t) {} });
        ^
  symbol:   method subscribe(<anonymous Consumer<Object>>)
  location: variable prop of type ObservableValue<Object>
1 error
[Incubating] Problems report is available at: file:///home/user/question/build/reports/problems/problems-report.html

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler output below.
  /home/user/question/src/main/java/Main.java:11: error: cannot find symbol
      prop.subscribe(new Consumer<Object>() { public void accept(Object t) {} });
          ^
    symbol:   method subscribe(<anonymous Consumer<Object>>)
    location: variable prop of type ObservableValue<Object>
  1 error

* Try:
> Check your code and dependencies to fix the compilation error(s)
> Run with --scan to get full insights.

BUILD FAILED in 924ms
1 actionable task: 1 executed

Update:

The code from @Slaw works, but only if I don't use Gradle Wrapper/gradlew.

So the question becomes: Could someone give a complete example of calling ObservableValue.subscribe() from a Gradle project that uses Gradle wrapper?

Results without gradlew (using code from @Slaw):

$ tree -a
.
├── build.gradle.kts
├── settings.gradle.kts
└── src
    └── main
        └── java
            └── com
                └── example
                    └── Main.java

6 directories, 3 files

$ gradle -version

------------------------------------------------------------
Gradle 8.10.2
------------------------------------------------------------

Build time:    2024-09-23 21:28:39 UTC
Revision:      415adb9e06a516c44b391edff552fd42139443f7

Kotlin:        1.9.24
Groovy:        3.0.22
Ant:           Apache Ant(TM) version 1.10.14 compiled on August 16 2023
Launcher JVM:  21.0.5 (Oracle Corporation 21.0.5+1-nixos)
Daemon JVM:    /nix/store/f042x32jfm94d3cgaga8d6xl8vy6sg46-openjdk-21.0.5+11/lib/openjdk (no JDK specified, using current Java home)
OS:            Linux 6.6.69 amd64

$ gradle run

> Task :run
Property value = null
Property value = Hello, World!
Property value = Hi, mom!

BUILD SUCCESSFUL in 529ms
2 actionable tasks: 2 executed

Results with gradlew (using code from @Slaw):

$ tree -a
.
├── build.gradle.kts
├── settings.gradle.kts
└── src
    └── main
        └── java
            └── com
                └── example
                    └── Main.java

6 directories, 3 files

$ gradle wrapper

BUILD SUCCESSFUL in 449ms
1 actionable task: 1 executed

$ ./gradlew -version

------------------------------------------------------------
Gradle 8.10.2
------------------------------------------------------------

Build time:    2024-09-23 21:28:39 UTC
Revision:      415adb9e06a516c44b391edff552fd42139443f7

Kotlin:        1.9.24
Groovy:        3.0.22
Ant:           Apache Ant(TM) version 1.10.14 compiled on August 16 2023
Launcher JVM:  21.0.5 (Oracle Corporation 21.0.5+1-nixos)
Daemon JVM:    /nix/store/vc52hvhclai81s6yyg7mng0g0mfvnqim-openjdk-21.0.5+11/lib/openjdk (no JDK specified, using current Java home)
OS:            Linux 6.6.69 amd64

$ ./gradlew run

> Task :compileJava FAILED
/home/user/question/src/main/java/com/example/Main.java:16: error: cannot find symbol
    property.subscribe(value -> System.out.println("Property value = " + value));
            ^
  symbol:   method subscribe((value)->S[...]alue))
  location: variable property of type SimpleObjectProperty<Object>
1 error

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.

* Try:
> Run with --info option to get more log output.
> Run with --scan to get full insights.

BUILD FAILED in 446ms
1 actionable task: 1 executed

Update 2:

I have now solved this issue. It was a problem with my Java installation. After discovering that Gradle was behaving differently than Gradle Wrapper, I was able to figure out that they were using different was using a different JAVA_HOME and different Java installations. In one of my NixOS overlays, I had the following settings:

p.jdk.override {
  enableJavaFX = true;
  openjfx_jdk = p.openjfx.override { withWebKit = true; };
};

Changing p.openjfx.override to p.openjfx23.override fixes the issue.

It still puzzles me that Gradle Wrapper used the JavaFX in my Java installation and not the one specified in build.gradle.kts, but at least for my system the issue is now resolved.


Solution

  • Based on the error, I would assume the problem is you're not using JavaFX 21+. But your build script clearly shows you using JavaFX 24, so I'm not sure why an older version would be being used. Perhaps one of the following things is causing problems?

    Though I'm not sure why any of those (potential) problems would specifically cause issues with subscribe. Regardless, here is a minimal example.

    Versions

    Project Structure

    <project-directory>
    │   build.gradle.kts
    │   settings.gradle.kts
    │
    └───src
        └───main
            └───java
                └───com
                    └───example
                            Main.java
    

    Gradle Files

    settings.gradle.kts

    rootProject.name = "subscribe-example"
    

    build.gradle.kts

    plugins {
      id("org.openjfx.javafxplugin") version "0.1.0"
      application
    }
    
    repositories {
      mavenCentral()
    }
    
    javafx {
      modules("javafx.base")
      version = "24.0.1"
    }
    
    application {
      mainClass = "com.example.Main"
    }
    

    Source Files

    com/example/Main.java

    package com.example;
    
    import javafx.beans.property.SimpleObjectProperty;
    
    public class Main {
    
      /*
       * The types in the 'javafx.base' module do not require the JavaFX platform
       * to be running in order to use them. So, you can simply perform the test
       * in the main method without having to extend 'javafx.application.Application'
       * or depending on 'javafx.graphics' at all.
       */
      
      public static void main(String[] args) {
        var property = new SimpleObjectProperty<>();
        property.subscribe(value -> System.out.println("Property value = " + value));
    
        property.set("Hello, World!");
        property.set("Hi, mom!");
      }
    }
    

    Execution

    PS <project-directory>> gradle run
    
    > Task :run
    Property value = null
    Property value = Hello, World!
    Property value = Hi, mom!
    
    BUILD SUCCESSFUL in 1s
    2 actionable tasks: 2 executed
    

    And with the wrapper (which still works):

    PS <project-directory>> gradle wrapper 
    
    BUILD SUCCESSFUL in 1s
    1 actionable task: 1 up-to-date
    PS <project-directory>> ./gradlew --version
    
    ------------------------------------------------------------
    Gradle 8.14
    ------------------------------------------------------------
    
    Build time:    2025-04-25 09:29:08 UTC
    Revision:      34c560e3be961658a6fbcd7170ec2443a228b109
    
    Kotlin:        2.0.21
    Groovy:        3.0.24
    Ant:           Apache Ant(TM) version 1.10.15 compiled on August 25 2024
    Launcher JVM:  24.0.1 (Eclipse Adoptium 24.0.1+9)
    Daemon JVM:    C:\Program Files\Eclipse Adoptium\jdk-24.0.1.9-hotspot (no JDK specified, using current Java home)
    OS:            Windows 10 10.0 amd64
    
    PS <project-directory>> ./gradlew run      
    
    > Task :run
    Property value = null
    Property value = Hello, World!
    Property value = Hi, mom!
    
    BUILD SUCCESSFUL in 1s
    2 actionable tasks: 1 executed, 1 up-to-date