I would like a Java class containing JavaFX Property objects (DoubleProperty, StringProperty, IntegerProperty) to be written into an XML file using JAXB's marshall() method call. However, this class contains lots of data that I do not want written into the XML. This class is expected to be modified by developers often, so I prefer to mark the class "@XmlAccessorType(XmlAccessType.NONE)" and then add @XmlElement tags to anything I want written into the XML (so a developer doesn't add some new member variables into this class and then accidentally alter the XML file's format).
I see examples such as http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html, but none of them have "@XmlAccessorType(XmlAccessType.NONE) " for their main class. When I add this tag to my class, I get either runtime Exceptions (because JAXB cannot create a new object) or an empty XML tag in the output (because JAXB created a default object of ome kind but didn't put the desired value into it). I have experimentes with dozens of @Xml* tag combinations but I cannot find one that works.
Note that I cannot annotate any of the DoubleProperty/SimpleDoubleProperty classes because they are part of the standard Java API.
Here is a code example, demonstrating the troubles with getting the bankAccountBalance property into the XML file. (you can ignore the other data - I started with Blaise Doughan's code as a starting-point for this example).
package Demo2;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
public class Demo2 {
public static void main(String[] args) throws Exception {
Customer customer = new Customer();
Address address = new Address();
address.setStreet("1 A Street");
customer.setContactInfo(address);
customer.setBankAccountBalance(123.45);
JAXBContext jc = JAXBContext.newInstance(Customer.class, Address.class, PhoneNumber.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
abstract class ContactInfo {
}
class Address extends ContactInfo {
private String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
class PhoneNumber extends ContactInfo {
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
class Customer {
@XmlElement
private ContactInfo contactInfo;
// This tag runs OK but always outputs an empty XML tag ("<bankAccountBalance/>") regardless of the real value.
// @XmlElement
// This tag causes the following error:
// Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
// Invalid @XmlElementRef : Type "class javafx.beans.property.DoubleProperty" or any of its subclasses are not known to this context.
// @XmlElementRef
// This tag causes the following error:
// Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
// Invalid @XmlElementRef : Type "class javafx.beans.property.SimpleDoubleProperty" or any of its subclasses are not known to this context.
// @XmlElementRef(type=SimpleDoubleProperty.class)
private DoubleProperty bankAccountBalance;
public Customer() {
bankAccountBalance = new SimpleDoubleProperty(0);
}
public ContactInfo getContactInfo() {
return contactInfo;
}
public void setContactInfo(ContactInfo contactInfo) {
this.contactInfo = contactInfo;
}
public double getBankAccountBalance() {
return bankAccountBalance.get();
}
public void setBankAccountBalance(double bankAccountBalance) {
this.bankAccountBalance.set(bankAccountBalance);
}
}
Simply annotate the getter and not the DoubleProperty field, which nicely bypasses the javafx class. Don't forget to setValue so you see the result.
@XmlElement public double getBankAccountBalance() { return bankAccountBalance.get(); }