194

How can I use the below code to unmarshal a XML string an map it to the JAXB object below?

JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Person person = (Person) unmarshaller.unmarshal("xml string here");

@XmlRootElement(name = "Person")
public class Person {
    @XmlElement(name = "First-Name")
    String firstName;
    @XmlElement(name = "Last-Name")
    String lastName;
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}
skaffman
  • 398,947
  • 96
  • 818
  • 769
c12
  • 9,557
  • 48
  • 157
  • 253

6 Answers6

328

To pass XML content, you need to wrap the content in a Reader, and unmarshal that instead:

JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

StringReader reader = new StringReader("xml string here");
Person person = (Person) unmarshaller.unmarshal(reader);
skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 6
    Could you expand this answer to include if the "xml string here" includes a SOAP envelope? – JWiley Mar 11 '14 at 14:25
  • what if you wanted to use a `Reader` in combination with a specific bean class ? Since there is no `unmarshall(Reader, Class)` method. E.g. is there a way to convert the `Reader` to a `javax.xml.transform.Source` ? – bvdb Jul 13 '16 at 10:29
  • 2
    In my case work as: `JAXBElement elemento = (JAXBElement)unmarshaller.unmarshal(reader); MyObject object = elemento.getValue();` – Cesar Miguel Jan 12 '17 at 00:26
  • 1
    @bvdb You can use `javax.xml.transform.stream.StreamSource` which has constructors that take `Reader`, `File`, or `InputStream`. – Muhd Dec 22 '17 at 06:49
  • Thanks! In my case I needed to do a little different: Person person = (Person) ((JAXBElement) unmarshaller.unmarshal(reader)).getValue(); – Gustavo Amaro May 08 '20 at 11:21
179

Or if you want a simple one-liner:

Person person = JAXB.unmarshal(new StringReader("<?xml ..."), Person.class);
Andrejs
  • 26,885
  • 12
  • 107
  • 96
  • 2
    This should be the accepted answer. That's a bit less complicated. – bobbel Apr 22 '16 at 12:08
  • Very simple. I totally agree, it must be the accepted answer. – Afaria Jun 17 '16 at 15:31
  • 12
    I actually disagree with the comments above. It certainly is easier but it creates the context on the fly so it can have performance impacts even if the context ends up being cached. Use with caution. – Crystark Feb 02 '17 at 16:02
  • So what is the alternative if we want to provide a class to the unmarshaller? The only method take a (node, class) in parameter and here we have a string. – Charles Follet Apr 14 '17 at 13:34
  • With this concise version I don't receive parsing errors, useful to debug a configuration. Probably I'm missing something... – beaver May 23 '18 at 10:00
  • I'm going with this one :) – GabrielBB Nov 22 '18 at 17:42
  • I appreciate that there's no cast involved, instead a type (?) is passed to the unmarshal method. – Thufir Jan 10 '19 at 05:41
21

There is no unmarshal(String) method. You should use a Reader:

Person person = (Person) unmarshaller.unmarshal(new StringReader("xml string"));

But usually you are getting that string from somewhere, for example a file. If that's the case, better pass the FileReader itself.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
4

If you already have the xml, and comes more than one attribute, you can handle it as follows:

String output = "<ciudads><ciudad><idCiudad>1</idCiudad>
<nomCiudad>BOGOTA</nomCiudad></ciudad><ciudad><idCiudad>6</idCiudad>
<nomCiudad>Pereira</nomCiudad></ciudads>";
DocumentBuilder db = DocumentBuilderFactory.newInstance()
    .newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(output));

Document doc = db.parse(is);
NodeList nodes = ((org.w3c.dom.Document) doc)
    .getElementsByTagName("ciudad");

for (int i = 0; i < nodes.getLength(); i++) {           
    Ciudad ciudad = new Ciudad();
    Element element = (Element) nodes.item(i);

    NodeList name = element.getElementsByTagName("idCiudad");
    Element element2 = (Element) name.item(0);
    ciudad.setIdCiudad(Integer
        .valueOf(getCharacterDataFromElement(element2)));

    NodeList title = element.getElementsByTagName("nomCiudad");
    element2 = (Element) title.item(0);
    ciudad.setNombre(getCharacterDataFromElement(element2));

    ciudades.getPartnerAccount().add(ciudad);
}
}

for (Ciudad ciudad1 : ciudades.getPartnerAccount()) {
System.out.println(ciudad1.getIdCiudad());
System.out.println(ciudad1.getNombre());
}

the method getCharacterDataFromElement is

public static String getCharacterDataFromElement(Element e) {
Node child = e.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;

return cd.getData();
}
return "";
}
1
If you want to parse using InputStreams

public Object xmlToObject(String xmlDataString) {
        Object converted = null;
        try {
        
            JAXBContext jc = JAXBContext.newInstance(Response.class);
        
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            InputStream stream = new ByteArrayInputStream(xmlDataString.getBytes(StandardCharsets.UTF_8));
            
            converted = unmarshaller.unmarshal(stream);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return converted;
    }
shweta
  • 23
  • 4
0

I cannot comment existing answers so I have to write a new one. No existing asnwers take into account the situaion where XML tags contains lower cases and upper cases letters. I lerned va trial and error that in this case you have to use

@XmlElement(name="ActualAttriubuteName")

Here is an example

<?xml version='1.0' encoding='utf-8'?><Terminal><TermInfo><IDM>1</IDM></TermInfo></Terminal>

The corresponfing beans are:

@XmlRootElement(name="Terminal")
public class Terminal implements Serializable{

private static final long serialVersionUID = -5541959943076783942L;

private TermInfo termInfo = null;


@Override
public String toString() {
    return "Terminfo [termInfo=" +termInfo.toString() + "]";
}   


@XmlElement(name="TermInfo")
public TermInfo getTermInfo() {
    return termInfo;
}


public void setTermInfo(TermInfo termInfo) {
    this.termInfo = termInfo;
}
   }

and

import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
public class TermInfo implements Serializable{

private static final long serialVersionUID = 6829846773317527647L;

private Integer idm = null;
    
@Override
public String toString() {
    return "id=" +idm + "]";
}   

@XmlElement(name="IDM")
public Integer getIdm() {
    return idm;
}

public void setIdm(Integer idm) {
    this.idm = idm;
} 
}

The unmarshal code is

        xml = "<?xml version='1.0' encoding='utf-8'?><Terminal><TermInfo><IDM>1</IDM></TermInfo></Terminal>";
    
    
      StringReader sr = new StringReader(xml);
     
      JAXBContext jaxbContext;
    try {
        jaxbContext = JAXBContext.newInstance(Terminal.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Terminal termInfo= (Terminal) unmarshaller.unmarshal(sr);    

        System.out.println(termInfo.toString());
        
        
        
        
        
    } catch (JAXBException e) { 
        // TODO Auto-generated catch block
        e.printStackTrace();
    }