问题:
I have two packages, one for objects and the other for creating GUI. I am trying to create a TableView in JavaFX and I have to use PropertyValuesFactory<>(property) t...
可以将文章内容翻译成中文,广告屏蔽插件会导致该功能失效:
问题:
I have two packages, one for objects and the other for creating GUI. I am trying to create a TableView
in JavaFX and I have to use PropertyValuesFactory<>(property)
to get the value of the object. So I have a bug where if I put the Person and GUI class in the same package everything would work for fine, but when the Person class is put in the objects package everything goes bad and I get this error:
WARNING: Can not retrieve property 'name' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@6771b7fb with provided class type: class uni.rest.objects.Person
java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class uni.rest.objects.Person (in module main) because module main does not open uni.rest.objects to javafx.base
This is also the line of code where the error happens:
person_column.setCellValueFactory(new PropertyValueFactory<>("name"));
So I assume that the property value location might have to be changed... I would appreciate any help.
回答1:
The PropertyValueFactory
class uses reflection to access the model class' properties. The module system added in Java 9 adds greater encapsulation which prevents modules from reflectively accessing other modules unless given permission by directives in module-info.java
.
The documentation of PropertyValueFactory
mentions what you need to do if deploying your application as a module:
Deploying an Application as a Module
If the referenced class is in a named module, then it must be reflectively accessible to the javafx.base
module. A class is reflectively accessible if the module opens the containing package to at least the javafx.base
module. Otherwise the call(TableColumn.CellDataFeatures)
method will log a warning and return null
.
For example, if the Person
class is in the com.foo
package in the foo.app
module, the module-info.java
might look like this:
module foo.app {
opens com.foo to javafx.base;
}
Alternatively, a class is reflectively accessible if the module exports the containing package unconditionally
Another option is to forgo PropertyValueFactory
and use a custom Callback
. The PropertyValueFactory
was more of a convenience for when lambdas were not a thing; before lambdas, if one wanted to use a custom Callback
, one would have to create an anonymous class each time which was verbose. Since lambdas, however, one can do:
person_column.setCellValueFactory(features -> features.getValue().nameProperty());
Obviously, this works best if the model exposes a JavaFX property. The advantages of a custom Callback
include avoidance of reflection and type safety.