Anand B
Anand B

Reputation: 3085

Hide a value in xml that can be retrieved only when unmarshalling

Is it possible to hide a value in XML such that it can be retrieved only when unmarshalling.

Upvotes: 3

Views: 2392

Answers (2)

bdoughan
bdoughan

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

bdoughan
bdoughan

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

Related Questions