Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB - Possible to make an optional attribute required if another optional attribute is set?

Tags:

java

xml

jaxb

If an optional attribute is set, then I want another attribute to be suddenly required. Also, this means the ladder optional attribute can only be set if the previous attribute is set.

ie,

name is Required

status is optional, but if set then country needs to be specified as well.

country is only set if status is given.

<field name="myField" status="citizen" country="England"/>

A valid xml tag can also be where status and country are null (and therefore not unmarshalled):

<field name="myField" />

It will probably be easier if I put the optional fields in their own xml tag? Maybe something like this:

<field name="myField">
     <option status="citizen" country="England"/>
</field>

Although would the first way be possible?

like image 493
4 revs Avatar asked Jan 21 '26 11:01

4 revs


1 Answers

You could use a beforeMarshal event and do the following:

Field

If you don't like having the beforeMarshal method on your domain class you could implement a Marshaller.Listener and set in on the Marshaller (see: http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/Marshaller.Listener.html).

package forum13918891;

import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Field {

    @XmlAttribute
    String name;

    @XmlAttribute
    String status;

    @XmlAttribute
    String country;

    private void beforeMarshal(Marshaller marshaller) {
        if(country != null && status == null) {
            throw new RuntimeException("country was set but status was not");
        }
    }

}

Demo

Below is some demo code to prove everything works.

package forum13918891;

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Field.class);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        Field field = new Field();
        field.name = "myField";
        marshaller.marshal(field, System.out);

        field.status = "citizen";
        field.country = "England";
        marshaller.marshal(field, System.out);

        field.status = null;
        marshaller.marshal(field, System.out);
    }

}

Output

Below is the output from running the demo code.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<field name="myField"/>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<field name="myField" status="citizen" country="England"/>
Exception in thread "main" java.lang.IllegalStateException: java.lang.reflect.InvocationTargetException
    at com.sun.xml.bind.v2.runtime.XMLSerializer.fireMarshalEvent(XMLSerializer.java:758)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.fireBeforeMarshalEvents(XMLSerializer.java:743)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:491)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
    at forum13918891.Demo.main(Demo.java:21)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.fireMarshalEvent(XMLSerializer.java:755)
    ... 6 more
Caused by: java.lang.RuntimeException: country was set but status was not
    at forum13918891.Field.beforeMarshal(Field.java:21)
    ... 11 more
like image 77
bdoughan Avatar answered Jan 24 '26 03:01

bdoughan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!