0

I'm getting InvocationTargetException and NullPointerException when attempting to bind to custom class run by Task. I have working examples of binding to library classes ObeservableList, Long, Integer etc but now need to bind to values of custom class. I created TaskOutput class that includes StringProperty for binding purposes as follows:

public class TaskOutput  {

    private final StringProperty textValue = new SimpleStringProperty();

    public TaskOutput(String textValue) {

        this.textValue.set(textValue);
    }

    public String getTextValue() {

        return textValue.get();
    }

    public void setTextValue(String textValue) {

        this.textValue.set(textValue);
    }

    public final StringProperty nameProperty() {

        return this.textValue;
    }
}

This was tested successfully as follows:

TaskOutput newTaskOutput = new TaskOutput("Text of TaskOutput");
value.textProperty().bind(newTaskOutput.nameProperty());
System.out.println(value.getText());

Now I'm attempting to run a Task that provides a TaskOutput as its Value Property. The class extending Task is as follows:

public class NameGeneratorTask extends Task<TaskOutput> {

    private int counter;
    TaskOutput taskOutput;
    public NameGeneratorTask() {

        this.counter = 10;
        taskOutput = new TaskOutput("Test String from output");
    }

    @Override
    protected TaskOutput call() {

        this.updateTitle("Name Generator");

        do {

            if (this.isCancelled()) 
            {
                break;
            }
            updateValue(taskOutput);
            counter--;
        }
        while (counter > 0);
        return taskOutput;
    }
}

The Application class instantiates a Task Object and then passes it to the WorkerState class as follows:

public class FxConcurrentBespokeObjectVersion2 extends Application
{     

    NameGeneratorTask task;

    public static void main(String[] args) 
    {
        Application.launch(args);
    }

    @Override
    public void start(final Stage stage) 
    {
        task = new NameGeneratorTask();
        WorkerState pane = new WorkerState(task);
    }
}

The WorkerState class attempts to bind to the nameProperty of the TaskOutput being run by the Task as follows:

public class WorkerState
{   
    private final TextArea value = new TextArea("");

    public WorkerState(Worker<TaskOutput> worker) 
    {
        value.textProperty().bind(worker.valueProperty().get().nameProperty());
    }
}

Program compiles at this point but this exception is generated at runtime:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.NullPointerException
    at OriginalExBespokeObjectVersion2.WorkerState.<init>(WorkerState.java:21)
    at OriginalExBespokeObjectVersion2.FxConcurrentBespokeObjectVersion2.start(FxConcurrentBespokeObjectVersion2.java:29)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    ... 1 more
Exception running application OriginalExBespokeObjectVersion2.FxConcurrentBespokeObjectVersion2

As I mention, I've already managed to bind to library classes so don't see why I can't bind to my custom class in same scenario (though I can bind to it fine in standalone example above). Can anyone suggest please? In case anyone wonders, 'Why not use Task (String) ?'... The objective of my program is to return several properties from the same Task (String was just 1 example), hence needing to encapsulate the properties in a custom class.

lanewalk
  • 1
  • 1
  • What’s `Worker` here? I suspect that when you do the binding, `worker.valueProperty().get()` is returning `null` – James_D May 17 '20 at 14:10

1 Answers1

0

Yes, both worker.valueProperty() and worker.valueProperty().get() return null at this point. Earlier I tried this:

value.textProperty().bind( 
                new When(worker.valueProperty().isNull()).then("Unknown")
               .otherwise(worker.valueProperty().get().nameProperty()));

...but the outcome was the same. It get that being null is a problem but I can't see how it's different to before when I managed to bind fine with a library type such as Long. In that case this line worked fine: value.textProperty().bind(worker.valueProperty().asString()); I checked and in the case of property type being Long worker.valueProperty() was also null at time of bind and it wasn't an issue.

Update:

I checked the worker.valueProperty().asString() used in the working example and saw it was returning StringBinding so I modified my custom class to do the same as follows:

public class TaskOutput  {

    private final String textValue = new String("Start value");

    public TaskOutput() {


    }

    public StringBinding getStringBinding() {

        return new StringBinding() {

            @Override
            protected String computeValue() {

                return textValue;
            }   
        };
    }
}

I've deployed this in WorkerState class as follows:

value.textProperty().bind(worker.valueProperty().get().getStringBinding());

But still it's the same result, InvocationTargetException and Runtime Exception. Not sure what else I can try?

lanewalk
  • 1
  • 1
  • Because `valueProperty().asString()` creates a _binding_ which can handle `null` values. It's completely different from _getting the value_ and trying to invoke a method on a `null` reference. – Slaw May 17 '20 at 17:15
  • Also, if this is not an answer to the question please don't put it in the answer section. Assuming this is actually more information for your question you should edit your question to add it there. – Slaw May 17 '20 at 17:16