Reputation: 8796
Is it possible to set an attribute/element value to a JAXB object using only the name of that property?
Example:
If I have a class
@XmlRootElement(name = "book")
public class Book {
@XmlElement(name = "title")
private String name;
@XmlElement(name = "author")
private String author;
// setters and getters
}
Can I set the name without using its setter(setName()
), but only knowing the xml element name? Which in this case is "title"
. It could look like this:
JAXBContext context = JAXBContext.newInstance(Book.class);
Something s = context.create***();
s.setValueToObject(book, "title", "New name"); // should do the same like book.setName("New name")
Upvotes: 3
Views: 3992
Reputation: 149007
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
SETTING VALUES BY PROPERTY NAME
You could use the java.lang.reflect
APIs to set a value on your object.
package forum13952415;
import java.lang.reflect.Field;
import javax.xml.bind.*;
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
Customer customer = new Customer();
setValueToObject(customer, "firstName", "Jane");
setValueToObject(customer, "lastName", "Doe");
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
private static void setValueToObject(Object object, String property, Object value) throws Exception {
Class clazz = object.getClass();
Field field = clazz.getDeclaredField(property);
field.setAccessible(true);
field.set(object, value);
}
}
SETTING VALUES BY XPATH
MOXy offers the ability to get/set values in a domain object by XPath. Below is an example.
Demo
In the example below we need to dig down to the underlying MOXy implementation to get access to the setValueByXPath
method.
package forum13952415;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.JAXBHelper;
import org.eclipse.persistence.oxm.XMLContext;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
XMLContext xmlContext = JAXBHelper.unwrap(jc, XMLContext.class);
Customer customer = new Customer();
xmlContext.setValueByXPath(customer, "@id", null, 123);
xmlContext.setValueByXPath(customer, "first-name/text()", null, "Jane");
xmlContext.setValueByXPath(customer, "last-name/text()", null, "Doe");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
Output
Below is the output from running the demo code.
<?xml version="1.0" encoding="UTF-8"?>
<customer id="123">
<first-name>Jane</first-name>
<last-name>Doe</last-name>
</customer>
Customer
Below is a sample domain model. I've used one where the XML names are different from the Java names.
package forum13952415;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
@XmlAttribute(name="id")
private int primaryKey;
@XmlElement(name="first-name")
private String firstName;
@XmlElement(name="last-name")
private String lastName;
}
jaxb.properties
To use MOXy as your JAXB provider you need to add a file called jaxb.properties
in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Upvotes: 1
Reputation: 11310
The best way is to provide them over its setters.
if your method
s.setValueToObject(book, "title", "New name"); // should do the same like book.setName("New name")
do the setter work for you. then it's also correct
Upvotes: 0