Michael Clayton Michael Clayton - 2 months ago 18
Java Question

Entry cannot be cast to javax.xml.bind.JAXBElement

I keep getting the JAXB cast error.

I'm not sure what to correct at this point.

The unmarshalling:

try{
Client client = Client.create();
client.addFilter(new HTTPBasicAuthFilter(API_KEY, ""));
WebResource webResource = client.resource("https://url.entries.xml");
webResource.setProperty("", API_KEY);
ClientResponse response = webResource.accept("application/xml").get(ClientResponse.class);

if(response.getStatus() != 200){
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}

String output = response.getEntity(String.class);
System.out.println("\n============getFtoCResponse============");
System.out.println(output);


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

Entries itsEntries = (Entries)((JAXBElement)unmarshaller.unmarshal(new StringReader(output))).getValue();


/* Object o = unmarshaller.unmarshal(new StringReader(output));
System.out.println(o.getClass());*/

}catch(Exception e){
e.printStackTrace();
}


Here are the first 16 lines from my Entry.java class, I have annotated setters and getters:

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


private String DateCreated;
private String EntryId;
private String Field1;
private String Field2;
private String Field3;
private String Field4;


And here is my Entries class, to be used to get a list of Entry objects:

@XmlRootElement(name = "Entries")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entries extends Object {

@XmlElement(name="Entries")
private List<Entry> entryList = new ArrayList<Entry>();

@XmlElement(name="Entries")
public List<Entry> getEntryList() {
return entryList;
}


public void setEntryList(List<Entry> entryList) {
this.entryList = entryList;
}

}


Error Message:


Entry cannot be cast to javax.xml.bind.JAXBElement


Question Update

Entries:

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

@XmlElement(name = "Entries")
private List<Entry> entryList = new ArrayList<Entry>();


public List<Entry> getEntryList() {
return this.entryList;
}


public void setEntryList(List<Entry> entryList) {
this.entryList = entryList;
}

}


Entry:

@XmlAccessorType(XmlAccessType.FIELD)
public class Entry {

private String DateCreated;
private String EntryId;
private String Field1;
private String Field2;
private String Field3;


XML:

<?xml version="1.0" encoding="UTF-8"?>
<Entries>
<Entry>
<EntryId>1</EntryId>
<Field3>John</Field3>
<Field4>Doe</Field4>
<Field12>21 jump street</Field12>
<Field14></Field14>
<Field15>USA</Field15>
<Field11>USA</Field11>
</Entry>
</Entries>

Answer

As far as I can see you have several issues in your current code. The second issue listed here is the root cause of your exception.

1. Not the right class provided to JAXBContext.newInstance(Class)

You are supposed to provide the class of the root element which seems to be Entries in your case so it should be JAXBContext.newInstance(Entries.class)

2. The way you extract the Entries instance

The expected code is rather this:

Entries itsEntries = (Entries)unmarshaller.unmarshal(new StringReader(output));

This is actually the reason why you get this exception, as unmarshal provides directly the type corresponding to the root element not a JAXBElement as you seem to expect.

3. The mapping is not correct

Up to now in the class Entries, Entries is mapped twice on the field entryList and on the method getEntryList() which is not correct as you need to map it only once, since you set the annotation @XmlAccessorType(XmlAccessType.FIELD), you are supposed to annotate only the field.

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

    @XmlElement(name="Entries")
    private List<Entry> entryList = new ArrayList<Entry>();

    public List<Entry> getEntryList() {
        return entryList;
    }

The second issue is the fact that you have 2 classes Entry and Entries that are mapped with the exact same element's name using the annotation @XmlRootElement(name = "Entries") such that JAXB cannot know which class to use when it finds a root element whose name is Entries, in your case the class Entries is the only root element so the annotation should be set on this class only. The mapping of the class Entry is already defined on the mapping of the field entryList such that you have no need to set this annotation on the class.

@XmlAccessorType(XmlAccessType.FIELD)
public class Entry {
    ...
}

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

The third issue is related to the fact that you don't map properly the elements Entry in the class Entries which is actually the reason why you have an empty list when you try to unmarshal your XML content, the correct mapping is:

@XmlElement(name="Entry")
private List<Entry> entryList = new ArrayList<Entry>();

4. No need to extend Object

Assuming that you are referring to java.lang.Object, you have no need to make your class Entries extends java.lang.Object as it is implicit.