jaxb marshall field as xml node with attribute

jaxb

Solution

There are a couple of options available to you to support this use case.

OPTION #1 - `XmlAdapter` ANY JAXB (JSR-222) IMPLEMENTATION

This approach will work with any JAXB (JSR-222) compliant implementation.

ValueAdapter

An `XmlAdapter` allows you to marshal one object as if it were another object. In our `XmlAdapter` we will convert the `String` value to/from an object that has one property mapped with `@XmlAttribute`.

package forum13489697;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ValueAdapter extends XmlAdapter<ValueAdapter.Value, String>{

    public static class Value {
        @XmlAttribute
        public String value;
    }

    @Override
    public String unmarshal(Value value) throws Exception {
         return value.value;
    }

    @Override
    public Value marshal(String string) throws Exception {
        Value value = new Value();
        value.value = string;
        return value;
    }

}

Person

The `@XmlJavaTypeAdapter` annotation is used to specify that the `XmlAdapter` should be used with a field or property.

package forum13489697;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class Person {

    @XmlJavaTypeAdapter(ValueAdapter.class)
    public String name;

}

OPTION #2 - EclipseLink JAXB (MOXy)

I'm the EclipseLink JAXB (MOXy) lead and we offer the `@XmlPath` extension which allows you to easily do path based mapping.

Person

package forum13489697;

import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
public class Person {

    @XmlPath("name/@value")
    public String name;

}

jaxb.properties

To specify MOXy as your JAXB provider you need to include 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

DEMO CODE

The following demo code can be used with either option:

Demo

package forum13489697;

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/forum13489697/input.xml");
        Person person = (Person) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(person, System.out);
    }

}

input.xml/Output

<?xml version="1.0" encoding="UTF-8"?>
<person>
    <name value="arahant" />
</person>

Problem

``` public class Person { public String name; ... } ``` When I marhsal I want to get a Name node with value attribute ``` <name value="arahant" /> ``` instead of : ``` <name>arahant</name> ``` How can I achieve this? I tried looking at the XmlElementWrapper but that is allowed only for collections. Would I need to write custom code for this?

Original source