XStream XStreamMarshaller CannotResolveClassException java.util.ArrayList

XStream XStreamMarshaller CannotResolveClassException java.util.ArrayList

我必须使用 Spring 批处理读取多个 XML 文件。

我正在使用 XStream,但我很难读取对象的 ArrayList。

错误堆栈:

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]

我的 POJO :

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;
    }
}

我的一个 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<persons>
    <person>
        <personId>1</personId>
        <firstName>PETER</firstName>
        <lastName>SCHMIDT</lastName>
        <email>pschmidt0@aboutads.info</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>

然后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;
    }

有关信息,此 reader 已传递到 multiResourceItemReader,如果我的 XML 文件中没有 <works></works>,它也能正常工作

Spring Batch 不直接处理解组,而是将其委托给 spring-oxm 的 org.springframework.oxm.Unmarshaller。所以这个问题与 Spring Batch 本身无关,而是 XStream.

的映射问题

也就是说,根据您定义集合 Person.worksWorks.Work 的方式,您需要在编组器定义中添加隐式集合映射,如下所示:

Map<Class<?>, String> implicitCollections = new HashMap<>();
implicitCollections.put(Works.class, "Work");
marshaller.setImplicitCollections(implicitCollections);

编辑: 你可以找到一个完整的例子 here

我post如果其他人会遇到同样的问题,我会回复:

即使我添加了 @XStreamImplicit(itemFieldName = "Work"),我也发现编组器不知道这个注释。

所以我有两种可能的解决方案:

1- @Mahmoud Ben Hassine 上面的解决方案。

2- 只需激活自动检测注释即可 true

XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAutodetectAnnotations(true);

当然不要忘记为您的列表添加注释:

@XStreamImplicit(itemFieldName = "Work")
private List<Work> Work;

我更喜欢第二个,因为我有一个非常复杂的 XML 阅读大量对象集合,所以我想注释会很干净。

编码愉快:)