Search code examples
javaxmljaxbclasscastexception

JAXB ClassCastException due to root element having the same tag as its child element


I am unmarshalling an XML file taken from the World Bank web service. The root element and children elements have the same tag, as shown below. I am getting a ClassCastException when unmarshalling. This error goes away when I change the root element tag so that it is not the same as its children.

Is JAXB unable to handle this scenario or am I not using JAXB properly?

<data>
    <data>
    </data>
    ......
    <data>
    </data>
</data>

Here is my Java code for reference:

XML with the tag issue: http://api.worldbank.org/countries/all/indicators/SP.POP.TOTL?format=xml

main class

public class CountryPopParse {
    public List<CountryPop> parse() throws JAXBException, MalformedURLException, IOException{
        JAXBContext jc = JAXBContext.newInstance(CountryPops.class);
        Unmarshaller u = jc.createUnmarshaller();
        URL url = new URL("http://api.worldbank.org/countries/all/indicators/SP.POP.TOTL?format=xml");
        CountryPops countryPops = (CountryPops) u.unmarshal(url);
        return countryPops.getCountryPop();
    }  

    public static void main(String[] args) throws JAXBException, IOException, SQLException{
        CountryPopParse p = new CountryPopParse();
        List<CountryPop> popList= p.parse();
        System.out.println(popList.get(0).getDate());
    } 
}

root element class

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

    @XmlElement(name = "data", type = CountryPop.class)
    private List<CountryPop> countryPops = new ArrayList<>();

    public CountryPops(){        
    }

    public CountryPops(List<CountryPop> countryPops) {
        this.countryPops = countryPops;
    }

    public List<CountryPop> getCountryPop() {
        return countryPops;
    }
}

child element class

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

    @XmlElement(name="date")
    private int date;

    public int getDate() {
        return date;
    }    
}

Solution

  • Just remove the @XmlRootElement(name = "data") from the CountryPop class like the following:

    @XmlAccessorType(XmlAccessType.FIELD)
    public class CountryPop {
        @XmlElement(name="date")
        private int date;
    
        public int getDate() {
            return date;
        }    
    }
    

    And if you are handling the namespace wb should work fine.