I have this class
public class Header {
#XmlAnyElement(lax = true)
protected List<Object> any;
// getters/setters omitted
}
How can I (in JAX-WS WebMethod) create an element ID in header that would look like this?
<Header>
<ID>value</ID>
</Header>
You could have a class like the following and add an instance of it into the any property, or you could add an instance of org.w3c.dom.Element representing the ID element to the collection.
#XmlRootElement(name="ID")
#XmlAccessorType(XmlAccessType.FIELD)
public class ID {
#XmlValue
private String value;
}
Related
I need to unmarshall the following xml String named retornoExtrato in my code
<?xml version="1.0" encoding="UTF-8" ?>
<extrato xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<erro>
<codigo/>
<descricao/>
</erro>
<consultaextrato>
<header><![CDATA[SOME MULTIPLE
LINES HEADER]]></header>
<body><![CDATA[SOME MULTIPLE
LINES BODY]]></body>
<trailer><![CDATA[SOME MULTIPLE
LINES TRAILER]]></trailer>
</consultaextrato>
</extrato>
into an Extrato object, here are my classes (constructors, getters and setters ommited when default)
#XmlRootElement(name = "extrato")
public class Extrato {
private Erro erro;
private ConsultaExtrato consultaExtrato;
}
#XmlRootElement(name = "erro")
public class Erro {
private String codigo;
private String descricao;
}
#XmlRootElement(name = "consultaextrato")
public class ConsultaExtrato {
private String header;
private String body;
private String trailer;
#XmlCDATA
public String getHeader() {
return header;
}
#XmlCDATA
public String getBody() {
return body;
}
#XmlCDATA
public String getTrailer() {
return trailer;
}
}
The situation is when unmarshalling:
Erro always get umarshelled
ConsultaExtrato is getting null
Unmarshaller jaxbUnmarshaller = JAXBContext.newInstance(Extrato.class).createUnmarshaller();
Extrato extrato = (Extrato) jaxbUnmarshaller.unmarshal(new StringReader(retornoExtrato));
On the other hand, if I create a xml with only the consultaextrato tag, it gets unmarshelled ok. But it doesn't seems to work as an inner tag.
I've tried some extra jaxb annotation in all classes, none worked. What am I missing here?
You need to tell JAXB that the XML element <consultaextrato>
within the <extrato> element corresponds to
the Java property consultaExtrato in your Extrato class.
You do this by annotating this property (or rather its getter or setter method)
with #XmlElement and giving the XML name there:
#XmlElement(name = "consultaextrato")
If you don't do this, then JAXB would derive the XML element name
from the Java property name (i.e. consultaExtrato) and thus
get no match because of the different spelling.
And by the way: The #XmlRootElement(name = "consultaextrato")
has an effect only if the <consultaextrato> is the root element
of your XML content, but not if <consultaextrato> is a nested
element within another element (in your case within <extrato>
element).
I'm trying to parse existing XML files for a java application and some of the elements have mixed content occasionally as demonstrated below:
XML_STRING
<root>
<name>Michael</name>
<question>Text here</question>
</root>
XML_STRING_2
<root>
<name>Michael</name>
<question>Text here<measure>More Text</measure></question>
</root>
I Made the below classes to unmarshall this data.
Root Class
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root implements Serializable
{
private String name;
private Question question;
}
Question Class
#XmlAccessorType(XmlAccessType.NONE)
public class Question implements Serializable
{
#XmlValue
private String questionText;
private String measure;
}
I can't seem to get both the Text Here and More Text to be stored inside the Question class.
JAXBContext.newInstance(Root.class)
.createUnmarshaller()
.unmarshal(new ByteArrayInputStream(XML_STRING_2.getBytes("UTF-8")));
I'm printing the result of the above code snippet (with Lombok's #ToString() annotation added to Root and Question) for both XML_STRING and XML_STRING_2.
XML_STRING: Root(name=Michael, question=Question(questionText=Text here, measure=null))
XML_STRING_2:Root(name=Michael, question=Question(questionText=, measure=null))
I was able to get something I could work with by using #XmlMixed along with #XmlElementRefs inside Question and creating a Measure class.
#XmlAccessorType(XmlAccessType.NONE)
public class Question implements Serializable
{
#XmlMixed
#XmlElementRefs({
#XmlElementRef(name = "measure", type=Measure.class)
})
private List<?> content;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="measure") // If this is removed I get the error: "Invalid #XmlElementRef : Type `Measure` or any of its subclasses are not known to this context."
public class Measure
{
#XmlValue
private String value;
}
I'm now getting the below output, which i can use via instanceof checking the items inside content
Root(name=Michael, question=Question(content=[Text here]))
Root(name=Michael, question=Question(content=[Text here, Measure(value=More Text)]))
The Root file remained unchanged.
I have a Xml Like this
<entry>
<comboBox>
<name>xxx</name>
<details>sdfd</details>
</comboBox>
</entry>
In the other entry I have XML like this
<entry>
<numberField>
<name>xxx</name>
<details>sdfd</details>
</numberField>
</entry>
I want to map both comboBox and numberField to the same class in Java called Field
How do I annotate Java Fields in Entry Class?
In your Entry class you need to annotate the Java field with
#XmlElements
and list the individual element names there. Like this:
#XmlAccessorType(XmlAccessType.FIELD)
public class Entry {
#XmlElements({
#XmlElement(name = "comboBox", type = Field.class),
#XmlElement(name = "numberField", type = Field.class)
})
private Field field;
}
I have added type = Field.class in the annotation above only for clarity.
In your case you can omit it. Then JAXB will pick up Field from the property type decaration , which has the same desired effect.
The Field class can be straight-forward like this:
#XmlAccessorType(XmlAccessType.FIELD)
public class Field {
#XmlElement
private String name;
#XmlElement
private String details;
}
I think you should make two sub classes of an object which has the common annoted fields.
Each sub class just has to define jaxb #XmlRootElement (number field or combobox)
I have to create POJOs so that I can generate XML using JAXB for the below XML (Just a sample because child elements may go beyond 40).
Here, important thing to note is that I cannot declare these elements as properties in POJO because I won't be knowing the elements name.
<User>
<FirstName>Mahendra</FirstName>
<MiddleName>Singh</MiddleName>
<LastName>Dhoni</LastName>
<Organization>
<Name>Electronics</Name>
<id>elc001</id>
</Organization>
<Manager>
<Name>Sourabh</Name>
<id>emp_001</id>
</Manager>
</User>
I have created POJO for above XML as:
Fields1.java : For elements having value only.
public class Fields1
{
#XmlTransient
public String fieldName1;
#XmlValue
public String value;
// getter,setter
}
Fields2.java : For elements having child elements.
public class Fields2
{
#XmlTransient
public String fieldName2;
#XmlElement(name="NAME")
public String name;
#XmlElement(name="ID")
public String id;
// getter,setter
}
User.java : Root element class
public class User
{
#XmlVariableNode("fieldName1")
public List<Fields1> fields1;
#XmlVariableNode("fieldName2")
public List<Fields2> fields2;
// getter, setter
}
Here, #XmlVariableNode is helping me to generate elements name dynamically.
1. But, it only works fine if there is only single property
2. and if, there are two properties then it just works for the first one and ignores the next.
AFAIK, multiple #XmlVariableNodes in the same class are not possible. EclipseLink's documentation states:
Since this [#XmlVariableNode] makes use of the any logic during unmarshal and MOXy only
handles one Any mapping on a class if a class makes use of the
XmlVariableNode annotation then that class can not have XmlAnyElement
annotations or any other variables that would cause AnyObject or
AnyCollection mappings to be created.
(Source: EclipseLink/DesignDocs/406697)
You might be able to solve your problem by using nested #XmlVariableNodes:
public class TopLevelField {
#XmlTransient
public String fieldName;
#XmlVariableNode("fieldName")
public List<NestedField> fields;
// ...
}
public class NestedField {
#XmlTransient
public String fieldName;
#XmlValue
public String value;
// ...
}
#XmlRootElement
public class User {
#XmlVariableNode("fieldName")
public List<TopLevelField> fields;
}
I have a situation in which a Java object contains a generic Payload<T> that needs to be marshalled into xml. So given the following classes:
AbstractBox
#XmlTransient
public abstract class AbstractBox {
String type = this.getClass().getSimpleName();
String name = this.getClass().getCanonicalName();
// setters/getters snipped
public abstract String saySomething();
}
SmallBox
#XmlRootElement(name="small-box")
#XmlType(name="small-box")
public class SmallBox extends AbstractBox {
#XmlElement
public String getMsg() {
return saySomething();
}
public void setMsg(String msg) {
// do nothing
}
#Override
public String saySomething() {
return "I'm a small box";
}
}
Payload
#XmlTransient
public class Payload<T> {
private T payload;
public T getPayload() {
return payload;
}
public void setPayload(T payload) {
this.payload = payload;
}
}
and some code like this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class JaxbAnnotationsTest<P>
{
String name;
int age;
int id;
Payload<P> payload;
// setters and getters snipped
public static void main(String[] args) {
JaxbAnnotationsTest<AbstractBox> example = new JaxbAnnotationsTest<AbstractBox>();
example.setName("Brion");
example.setId(100);
example.setAge(34);
Payload<AbstractBox> object = new Payload<AbstractBox>();
object.setPayload(new SmallBox());
example.setPayloadContainer(object);
try {
XmlMapper xmapper = new XmlMapper();
xmapper.writeValue(System.out, example);
} catch (Exception ex) {
System.err.println("Damn..." + ex.getMessage());
}
}
I expect to see:
<JaxbAnnotationsTest>
<name>Brion</name>
<age>34</age>
<id>100</id>
<payloadContainer>
<small-box>
<type>SmallBox</type>
<name>sandbox.xml.jaxb.annotations.SmallBox</name>
<msg>I'm a small box</msg>
</small-box>
</payloadContainer>
</JaxbAnnotationsTest>
but instead I get:
<JaxbAnnotationsTest>
<name>Brion</name>
<age>34</age>
<id>100</id>
<payloadContainer>
<payload>
<type>SmallBox</type>
<name>sandbox.xml.jaxb.annotations.SmallBox</name>
<msg>I'm a small box</msg>
</payload>
</payloadContainer>
</JaxbAnnotationsTest>
I've tried using #XmlType on the concrete subclass to change payload to small-box but that didn't work either. If I remove the Payload<P> object and simply have a class member payload of generic type P then the paymentContainer tag goes away, but payload remains and does not use the small-box name I've specified.
Is there a way for me to force JAXB (any implementation) to set the tag to the name specified in the subclass instead of the generic type property?
Update:
The selected answer provides the solution but I wanted to follow up in the question as well. My problem was two-fold:
I was using #XmlTransient on the Payload<T> class and needed to instead use an #XmlAnyElement annotation on the setPayload(T payload) method (though I suspect it doesn't matter which method of the setter/getter pair is annotated as long as only one has the annotation).
I was using Jackson 2's JacksonJaxbXmlProvider which is an incomplete JAXB implementation that was ignoring the #XmlRootElement of the element used as the value of the #XmlAnyElement-annotated property.
Changing my JAXB provider to use the Java 6/7 built-in JAXB provider generated the output I expected.
Your Payload class expects any bean type as a property, so JAXB doesn't know how to marshall that particular object (in this case SmallBox). Since you need to keep the generic property in Payload the solution should be
Remove #XmlTransient annotation to make these types available for marshalling (I am wondering how it worked with this annotation as you mentioned)
Annotate setPayload in Payload class with #XmlAnyElement as follows
public class Payload {
private T payload;
public T getPayload() {
return payload;
}
#XmlAnyElement
public void setPayload(T payload) {
this.payload = payload;
}
}
#XmlAnyElement javadoc says
Maps a JavaBean property to XML infoset representation and/or JAXB
element.
This means any known bean type (annotated with #XmlRootElement) which is passed into setPayload() will be resolved by the JAXB to their corresponding type, here that bean is SmallBox, otherwise to a default element type ( i think it should be the default implementation of org.w3c.dom.Element). After this change it will marshall the JaxbAnnotationsTest nicely to following xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxbAnnotationsTest>
<age>34</age>
<id>100</id>
<name>Brion</name>
<payloadContainer>
<small-box>
<name>org.mycode.SmallBox</name>
<type>SmallBox</type>
<msg>I'm a small box</msg>
</small-box>
</payloadContainer>
</jaxbAnnotationsTest>
Hope that will help you.