问题
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.
回答1:
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?
来源:https://stackoverflow.com/questions/61850707/invocationtargetexception-when-binding-to-custom-class-run-by-javafx-concurrent