Let's say I have class Person:
class Person{
  String firstName;
  String lastName;
  String email;
}
XML has format:
<person>
 <firstName value="asd" /> 
 <lastName value="bcd" />
 <email value="qwe" />
</person>
I can unmarshal/marshal this class using own XmlAdapter implementation for each of field FirstNameAdapter, LastNameAdapter, EmailAdapter. As you can see each field represented in similar way - field name as xml element and field value as element's attribute. Is it possible to create "universal" adapter to which I'll be able to transfer name of the field and it will extract value of that field ?
P.S. I know about MOXy JAXB implementation, but I'm wondering if it is possible by means of reference JAXB implementation.
Thanks!
You can use an XmlAdapter like this:
import java.io.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
@XmlType
class Valued {
    @XmlAttribute(name="value")
    public String value;
}
class ValuedAdapter extends XmlAdapter<Valued, String> {
    public Valued marshal(String s) {
        Valued v = new Valued();
        v.value = s;
        return v;
    }
    public String unmarshal(Valued v) {
        return v.value;
    }
}
@XmlRootElement
class Person {
    @XmlJavaTypeAdapter(ValuedAdapter.class)
    @XmlElement
    String firstName;
    @XmlJavaTypeAdapter(ValuedAdapter.class)
    @XmlElement
    String lastName;
}
class SO12928971 {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        p.firstName = "John";
        p.lastName = "Doe";
        JAXBContext jc = JAXBContext.newInstance(Person.class);
        StringWriter sw = new StringWriter();
        jc.createMarshaller().marshal(p, sw);
        String xml = sw.toString();
        System.out.println(xml);
        StringReader sr = new StringReader(xml);
        p = (Person)jc.createUnmarshaller().unmarshal(sr);
        assert "John".equals(p.firstName);
        assert "Doe".equals(p.lastName);
    }
}
The idea here is that XML Schema and therefore also JAXB has a clear distinction between element names and content types, even though many documents have a clear one-to-one correspondence between these two. So in the above code, the type Valued describes something that has a value attribute, without regards for the element name. The members you want to serialize are annotated as @XmlElement with no name included in that annotation. So they will generate elements with a name derived from the name of the member. The @XmlJavaTypeAdapter annotation will cause the serializer to treat these members as if their types vere Valued. So that is what their XML content type will be.
The schema for the above code looks like this:
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="person" type="person"/>
  <xs:complexType name="person">
    <xs:sequence>
      <xs:element name="firstName" type="valued" minOccurs="0"/>
      <xs:element name="lastName" type="valued" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="valued">
    <xs:sequence/>
    <xs:attribute name="value" type="xs:string"/>
  </xs:complexType>
</xs:schema>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With