Reputation: 3048
I have this situation
@XmlType(name ="", propOrder={"value"})
@XmlRootElement(name = "compound")
public class Compound extends Value {
@XmlElements({
@XmlElement(name="simple", type=Simple.class),
@XmlElement(name="compound", type=Compound.class)
})
protected List<Value> value;
// ...
}
So a Compound is a List of both Simple and/or Compound. Both extend from Value that is defined as
public abstract class Value implements Serializable {}
Simple is a class marked with an adapter to marshal/unmarshal to/from a simple string
@XmlJavaTypeAdapter(SimpleAdapter.class)
public class Simple extends Value {
private java.lang.String simple;
// ...
}
Compound does not need an adapter.
The problem is that if I use a Simple 'as is', it correctly marshals/unmarshals as
<simple>my.text.here</simple>
but if I use it inside a Compound it outputs something like
<compound>
//...
<simple>
<value>my.text.here</value>
</simple>
//...
</compound>
And I'm just wondering why... Do I miss something? How can i remove that 'value'? It seems to me that the Adapter is not used at all, is it possible to use adapters in types marked inside @XmlElements?
EDIT
After few tests i found that the problem could be in how i handle a Simple instance. So I simplify my initial question in:
Given the a Simple class like
@XmlRootElement("simple")
public class Simple {
private java.lang.String innerText;
// getters/setters
}
how can i obtain a marshalled output like
<simple>
my.inner.text.here
</simple>
instead of
<simple>
<value>my.inner.text.here</value>
</simple>
?
Upvotes: 7
Views: 2905
Reputation: 149047
The answer given by bamana is correct, however the exception you are seeing is due to a bug in the JAXB reference implementation. This bug also existed in EclipseLink JAXB (MOXy) but has been fixed in the 2.3.0 stream, a nighty download can be obtained here:
As a workaround you could use the XmlAdapter approach that was in your original question:
SimpleAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class SimpleAdapter extends XmlAdapter<String, Simple> {
@Override
public Simple unmarshal(String v) throws Exception {
Simple simple = new Simple();
simple.setSimple(v);
return simple;
}
@Override
public String marshal(Simple v) throws Exception {
return v.getSimple();
}
}
Simple
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(SimpleAdapter.class)
public class Simple extends Value {
private java.lang.String simple;
public java.lang.String getSimple() {
return simple;
}
public void setSimple(java.lang.String simple) {
this.simple = simple;
}
}
Compound
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "compound")
@XmlAccessorType(XmlAccessType.FIELD)
public class Compound extends Value {
@XmlElements({ @XmlElement(name = "simple", type = Simple.class),
@XmlElement(name = "compound", type = Compound.class) })
protected List<Value> value;
public List<Value> getValue() {
return value;
}
public void setValue(List<Value> value) {
this.value = value;
}
}
Value
import java.io.Serializable;
public abstract class Value implements Serializable {}
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Compound.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Compound compound = (Compound) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(compound, System.out);
}
}
input.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<compound>
<simple>
<simple>FOO</simple>
</simple>
<compound/>
</compound>
Upvotes: 0
Reputation: 1625
It sounds like you want private java.lang.String innerText;
to be the @XmlValue of your Simple class. Try to annotate the String in Simple with the @XmlValue tag:
@XmlRootElement("simple")
public class Simple {
@XmlValue
private java.lang.String innerText;
//getters/setters
}
Or if you were using annotations on your getter method (which I assume based on your XML output in the question change your @XmlElement tag to a @XmlValue tag:
@XmlValue
public java.lang.String getInnerText() {
return innerText;
}
When I do this I get the output you are looking for in your edited question.
Upvotes: 2