I have to read multiple XML files using Spring Batch.
I'm using XStream and i'm struggling to read ArrayList Of objects.
Error stack :
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.3.jar:2.4.3]
Caused by: com.thoughtworks.xstream.converters.ConversionException:
---- Debugging information ----
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : workCompany
class : java.util.ArrayList
required-type : java.util.ArrayList
converter-type : com.thoughtworks.xstream.converters.collections.CollectionConverter
path : /person/works/Work/workCompany
line number : 15
class[1] : com.oualid.xmltojava.model.Works
converter-type[1] : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
class[2] : com.oualid.xmltojava.model.Person
version : 5.3.4
-------------------------------
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) ~[xstream-1.4.9.jar:1.4.9]
My POJOs :
package com.oualid.xmltojava.model;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import java.util.List;
@XStreamAlias("Person")
public class Person {
@XStreamAlias("personId")
private Integer personId;
@XStreamAlias("firstName")
private String firstName;
@XStreamAlias("lastName")
private String lastName;
@XStreamAlias("email")
private String email;
@XStreamAlias("age")
private Integer age;
@XStreamAlias("contactDetails")
private List<String> contactDetails;
@XStreamAlias("works")
private Works works;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Integer getPersonId() {
return personId;
}
public void setPersonId(Integer personId) {
this.personId = personId;
}
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<String> getContactDetails() {
return contactDetails;
}
public void setContactDetails(List<String> contactDetails) {
this.contactDetails = contactDetails;
}
public Works getWorks() {
return works;
}
public void setWorks(Works works) {
this.works = works;
}
}
package com.oualid.xmltojava.model;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import java.util.List;
@XStreamAlias("works")
public class Works {
@XStreamImplicit(itemFieldName = "Work")
private List<Work> Work;
public List<Work> getWorks() {
return Work;
}
public void setWorks(List<Work> works) {
this.Work = works;
}
}
package com.oualid.xmltojava.model;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("Work")
public class Work {
@XStreamAlias("workCompany")
private String workCompany;
@XStreamAlias("workMission")
private String workMission;
public String getWorkCompany() {
return workCompany;
}
public void setWorkCompany(String workCompany) {
this.workCompany = workCompany;
}
public String getWorkMission() {
return workMission;
}
public void setWorkMission(String workMission) {
this.workMission = workMission;
}
}
One of my XML file :
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person>
<personId>1</personId>
<firstName>PETER</firstName>
<lastName>SCHMIDT</lastName>
<email>[email protected]</email>
<contactDetails>
<string>contact1</string>
<string>contact2</string>
</contactDetails>
<age>28</age>
<works>
<Work>
<workCompany>ESI</workCompany>
<workMission>Java Developper</workMission>
</Work>
<Work>
<workCompany>ESI</workCompany>
<workMission>JS Developper</workMission>
</Work>
</works>
</person>
</persons>
Ther reader
@Bean
public StaxEventItemReader<Person> reader(){
StaxEventItemReader<Person> reader = new StaxEventItemReader<Person>();
//reader.setResource(new ClassPathResource("persons.xml"));
reader.setFragmentRootElementName("person");
Map<String,String> aliasesMap =new HashMap<String,String>();
aliasesMap.put("person", "com.oualid.xmltojava.model.Person");
aliasesMap.put("works", "com.oualid.xmltojava.model.Works");
aliasesMap.put("Work", "com.oualid.xmltojava.model.Work");
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliasesMap);
reader.setUnmarshaller(marshaller);
return reader;
}
For information, this reader is passed into multiResourceItemReader
and it works just fine if i don't have <works></works>
in my XML file
I post the response if any one else will face the same problem :
even when i added the @XStreamImplicit(itemFieldName = "Work")
i find out that the marshaller is not aware of this annotation.
So there is two possible solutions for me :
1- @Mahmoud Ben Hassine solution above.
2- Simply activate the auto detect annotation to true
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAutodetectAnnotations(true);
And of course don't forget to add the annotation for your List :
@XStreamImplicit(itemFieldName = "Work")
private List<Work> Work;
I prefered the second one because i have a really complexe XML to read with a lot of object collections, so annotations wil be clean i guess.
Happy coding :)