Reputation: 3085
Is it possible to hide a value in XML such that it can be retrieved only when unmarshalling.
Upvotes: 3
Views: 2392
Reputation: 148977
The following approach could be used with any JAXB (JSR-222) implementation.
Demo
A Marshaller.Listener
could be used to null out a value before the object is marshalled and then restore it afterwards.
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14231799/input.xml");
Person person = (Person) unmarshaller.unmarshal(xml);
System.out.println(person.password);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setListener(new Marshaller.Listener() {
private String password;
@Override
public void afterMarshal(Object object) {
if(object instanceof Person) {
Person person = (Person) object;
person.setPassword(password);
password = null;
}
}
@Override
public void beforeMarshal(Object object) {
if(object instanceof Person) {
Person person = (Person) object;
password = person.getPassword();
person.setPassword(null);
}
}
});
marshaller.marshal(person, System.out);
System.out.println(person.password);
}
}
input.xml
<Person>
<password> some password </password>
</Person>
Output
some password
<?xml version="1.0" encoding="UTF-8"?>
<Person/>
some password
Upvotes: 1
Reputation: 148977
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
Below are some options for implementing this use case if you are using MOXy as your JAXB provider. To use MOXy as your JAXB provider you need to include a file named jaxb.properties
in the same package as your domain model with the following entry:
OPTION #1 - XmlAdapter
An XmlAdapter
could be used to null out a property value during the marshal operation. While the XmlAdapter
is a standard JAXB class, returning null from the marshal
method causes an exception to occur when the JAXB reference implementation is used.
StringAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
@Override
public String marshal(String string) throws Exception {
return null;
}
@Override
public String unmarshal(String string) throws Exception {
return string;
}
}
Person
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement(name="Person")
public class Person {
String password;
@XmlJavaTypeAdapter(StringAdapter.class)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
OPTION #2 - Setter With No Getter
When MOXy is used as the JAXB provider if you have a property with an annotated setter and no getter then MOXy will treat it as a readonly property.
import javax.xml.bind.annotation.*;
@XmlRootElement(name="Person")
public class Person {
String password;
@XmlElement
public void setPassword(String password) {
this.password = password;
}
}
OPTION #3 - MOXy's @XmlReadOnly
Extension
MOXy's @XmlReadOnly
extension can also be used to mark a property as read only.
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlReadOnly;
@XmlRootElement(name="Person")
public class Person {
String password;
@XmlReadOnly
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
DEMO CODE
input.xml
<Person>
<password> some password </password>
</Person>
*Demo*
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14231799/input.xml");
Person person = (Person) unmarshaller.unmarshal(xml);
System.out.println(person.password);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(person, System.out);
}
}
Output
some password
<?xml version="1.0" encoding="UTF-8"?>
<Person/>
Upvotes: 2