Search code examples
javajaxbunmarshallingcdata

Unmarshall inner CDATA in xml String


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?


Solution

  • 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).