Search code examples
javajaxbjaxb2

Unmarshalling a simple XML


I am having hard time unmarshalling the following XML using JAXB. This is the xml which is having only one field with an attribute. I have referred many tutorials where they only do an example of reading a string in fields which s not helpful in my case.

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>  
<CircuitImpactConfigs id="1">
    <Objects>
        <Object type="1" impactAnalysisDataBuilderClassName="tttttttt"/>
        <Object type="2" impactAnalysisDataBuilderClassName="yyyyyyyyy"/>
        <Object type="3" impactAnalysisDataBuilderClassName="eeeeeee" />
        <Object type="4" impactAnalysisDataBuilderClassName="iiiiiiiii"/>
        <Object type="5" impactAnalysisDataBuilderClassName="rrrrrrrrrr"/>
        <Object type="6" impactAnalysisDataBuilderClassName="zzzzzz"/>
        <Object type="7" impactAnalysisDataBuilderClassName="qqqqqqqqqqq"/>
    </Objects>

    <ForceSwitchMode name="FORCE_SWITCHED" />

</CircuitImpactConfigs>  

Based on what i learnt from tutorial My Classes are CircuitImpactConfigs.java

   import java.util.List;

import javax.xml.bind.annotation.*;

@XmlRootElement(name = "CircuitImpactConfigs")
@XmlAccessorType(XmlAccessType.FIELD)
public class CircuitImpactConfigs {

    private ForceSwitchMode ForceSwitchMode;
    List<Obj> Object;

    @XmlElement
    public List<Obj> getObject() {
        return Object;
    }

    public void setObject(List<Obj> object) {
        Object = object;
    }

    @XmlElement
    public ForceSwitchMode getForceSwitchMode() {
        return ForceSwitchMode;
    }

    public void setForceSwitchMode(ForceSwitchMode forceSwitchMode) {
        ForceSwitchMode = forceSwitchMode;
    }


}

and

import javax.xml.bind.annotation.XmlAttribute;

public class ForceSwitchMode {

    private String name;

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

and

import javax.xml.bind.annotation.XmlAttribute;

public class Obj {
    String type;
    String impactAnalysisDataBuilderClassName;

    @XmlAttribute
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @XmlAttribute
    public String getImpactAnalysisDataBuilderClassName() {
        return impactAnalysisDataBuilderClassName;
    }

    public void setImpactAnalysisDataBuilderClassName(String impactAnalysisDataBuilderClassName) {
        this.impactAnalysisDataBuilderClassName = impactAnalysisDataBuilderClassName;
    }

}

I am getting null list when doing the unmarshalling. This is the class where i create the JAXBcontext object and create unmarshalling object.

import java.io.File;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

public class CircuitImpactConfUnmarshaller {
    public static void main(String[] args) throws JAXBException {
        File file = new File("CircuitImpact.xml");
        System.out.println(file.exists());
        JAXBContext jaxbContext = JAXBContext.newInstance(CircuitImpactConfigs.class);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        CircuitImpactConfigs que = (CircuitImpactConfigs) jaxbUnmarshaller.unmarshal(file);

        System.out.println(que.getForceSwitchMode().getName());
        List<Obj> list = que.getObject();
        System.out.println(list);
    }
}

the last print statement is giving null. I understand i am doing something wrong in the class Obj


Solution

  • JAXB uses implicit naming conventions and explicit annotations to define a mapping between a XML and a Java structure.

    Either element and attribute names in the XML match field names in Java (match by naming convention) or you need to use annotations to establish the mapping.

    The Java list CircuitImpactConfigs.Object is not getting filled because the mapping failed, since the corresponding element in the XML is named Objects.

    You can now either rename CircuitImpactConfigs.Object to CircuitImpactConfigs.Objects or use the name parameter of a JAXB annotation to define the corresponding name:

    @XmlElement(name="Objects")
    public List<Obj> getObject() {
    

    EDIT: As you indicate in your comments there are still other mapping issues with your code. I would suggest that you adapt another approach:

    1. Create a CircuitImpactConfigs object with all subobjects filled.
    2. Marhsall that object to a XML file.
    3. Check that the XML is in the expected format. If not, tweak the mapping.

    Following this approach you can be sure that a XML file in the desired format can be unmarshalled to your Java structure. The code to marshall is

    CircuitImpactConfigs que = ...
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    marshaller.marshal(que, System.out);