Skip to content

Instantly share code, notes, and snippets.

@yushijinhun
Last active December 19, 2019 04:27
Show Gist options
  • Save yushijinhun/87abb48d605b1a519f714349da043837 to your computer and use it in GitHub Desktop.
Save yushijinhun/87abb48d605b1a519f714349da043837 to your computer and use it in GitHub Desktop.
[JDK-8203870]OpenJDK FXML Read-Only List Properties Bug

Issue in JDK Bug System: JDK-8203870


Expected output:

listProp: [elementA, elementB]
Problem did not appear

Actual output:

listProp: [elementA]
Problem appeared

Workaround: comment the parameterized constructor.

According to Read-Only List Properties, the elements defined in listProp should be added to the listProp property of Test.

When FXMLLoader reaches a node whose type is Test, it checks its constructors. If Test has a parameterized constructor and the constructor has a @NamedArg annotation (JavaFXBuilderFactory.scanForConstructorAnnotations()), FXMLLoader will create the object when the end element is read (using a ProxyBuilder). Otherwise, it creates the object when the start element is read (InstanceDeclarationElement.constructValue()).

When FXMLLoader reaches the listProp property node, it creates a PropertyElement representing this property. If its parent (Test) is created directly (without using a ProxyBuilder), the value of the PropertyElement is set to the return value of Test.getListProp(). If its parent is going to be created using a ProxyBuilder, the value of PropertyElement is set to a temporary container. As the string elements are read, they are added to value.

For the directly created Test instance, the string elements are added to its listProp property while they are read. But for the Test instance created by a ProxyBuilder, these elements should be added by ProxyBuilder shortly after the Test instance is built. However, ProxyBuilder hasn't taken Read-Only List Properties into consideration. ProxyBuilder.getUserValue() returns the first element and strips others at line 456, which causes the strange behavior.

<?xml version="1.0" encoding="UTF-8"?>
<?import test.Test?>
<?import java.lang.String?>
<Test xmlns:fx="http://javafx.com/fxml">
<listProp>
<String fx:value="elementA"/>
<String fx:value="elementB"/>
</listProp>
</Test>
package test;
import java.io.IOException;
import javafx.beans.NamedArg;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
public class Test {
private ObservableList<String> listProp = FXCollections.observableArrayList();
public Test() {}
// The problem is solved after the constructor is commented
public Test(@NamedArg("stringProp") String stringProp) {}
//
public ObservableList<String> getListProp() {
return listProp;
}
public static void main(String[] args) throws IOException {
Test region = new FXMLLoader(Test.class.getResource("/test.fxml")).load();
System.out.println("listProp: " + region.listProp);
if (region.listProp.size() == 2) {
System.out.println("Problem did not appear");
} else {
System.out.println("Problem appeared");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment