There are multiple ways of adding data to a object in fxml:
<property>
tagA tag with the name of a property can be added as child of an element used for creating a instance. The child of this tag is assigned to the property using the setter or added to the contents of the property (readonly list/map properties).
A class can be annotated with the @DefaultProperty
annotation. In this case elements can be directly added as child element without using a element with the name of the property.
property="value"
attributeProperties can be assigned using the property name as attribute name and the value as attribute value. This has the same effect as adding the following element as child of the tag:
<property>
<String fx:value="value" />
</property>
Properties can be set using static
setters too. These are static
methods named setProperty
that take the element as first parameter and the value to set as second parameter. Those methods can recide in any class and can be used using ContainingClass.property
instead of the usual property name.
Note: Currently it seems to be neccesary to have a corresponding static getter method (i.e. a static method named getProperty
taking the element as parameter in the same class as the static setter) for this to work unless the value type is String
.
The following mechanism is used to get a object of the correct class during assignments, e.g. to suit the parameter type of a setter method.
If the classes are assignable, then the value itself is used.
Otherwise the value is converted as follows
Target type | value used (source value s ) |
---|---|
Boolean , boolean | Boolean.valueOf(s) |
char , Character | s.toString.charAt(0) |
other primitive type or wrapper type | appropriate method for target type, in case the s is a Number , the valueOf(s.toString()) for the wrapper type otherwise |
BigInteger | BigInteger.valueOf(s.longValue()) is s is a Number , new BigInteger(s.toString()) otherwise |
BigDecimal | BigDecimal.valueOf(s.doubleValue()) is s is a Number , new BigDecimal(s.toString()) otherwise |
Number | Double.valueOf(s.toString()) if s.toString() contains a . , Long.valueOf(s.toString()) otherwise |
Class | Class.forName(s.toString()) invoked using the context ClassLoader of the current thread without initializing the class |
enum | The result of the valueOf method, additionally converted to an all uppercase String seperated by _ inserted before each uppercase letter, if s is a String that starts with a lowercase letter |
other | the value returned by a static valueOf method in the targetType, that has a parameter matching the type of s or a superclass of that type |
Note: This behavior isn't well-documented and could be subject to change.
public enum Location {
WASHINGTON_DC,
LONDON;
}
package fxml.sample;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.beans.DefaultProperty;
@DefaultProperty("items")
public class Sample {
private Location loaction;
public Location getLoaction() {
return loaction;
}
public void setLoaction(Location loaction) {
this.loaction = loaction;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
int number;
private final List<Object> items = new ArrayList<>();
public List<Object> getItems() {
return items;
}
private final Map<String, Object> map = new HashMap<>();
public Map<String, Object> getMap() {
return map;
}
private BigInteger serialNumber;
public BigInteger getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(BigInteger serialNumber) {
this.serialNumber = serialNumber;
}
@Override
public String toString() {
return "Sample{" + "loaction=" + loaction + ", number=" + number + ", items=" + items + ", map=" + map + ", serialNumber=" + serialNumber + '}';
}
}
package fxml.sample;
public class Container {
public static int getNumber(Sample sample) {
return sample.number;
}
public static void setNumber(Sample sample, int number) {
sample.number = number;
}
private final String value;
private Container(String value) {
this.value = value;
}
public static Container valueOf(String s) {
return new Container(s);
}
@Override
public String toString() {
return "42" + value;
}
}
Printing the result of loading the below fxml
file yields
Sample{loaction=WASHINGTON_DC, number=5, items=[42a, 42b, 42c, 42d, 42e, 42f], map={answer=42, g=9.81, hello=42A, sample=Sample{loaction=null, number=33, items=[], map={}, serialNumber=null}}, serialNumber=4299}
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import fxml.sample.*?>
<Sample xmlns:fx="http://javafx.com/fxml/1" Container.number="5" loaction="washingtonDc">
<!-- set serialNumber property (type coercion) -->
<serialNumber>
<Container fx:value="99"/>
</serialNumber>
<!-- Add elements to default property-->
<Container fx:value="a"/>
<Container fx:value="b"/>
<Container fx:value="c"/>
<Container fx:value="d"/>
<Container fx:value="e"/>
<Container fx:value="f"/>
<!-- fill readonly map property -->
<map g="9.81">
<hello>
<Container fx:value="A"/>
</hello>
<answer>
<Container fx:value=""/>
</answer>
<sample>
<Sample>
<!-- static setter-->
<Container.number>
<Integer fx:value="33" />
</Container.number>
</Sample>
</sample>
</map>
</Sample>