You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC中XML无包装标签反序列化为Java集合的问题

如何用JAXB或Jackson XML反序列化无外层包装的XML列表到Java集合?

我在尝试反序列化SOAP消息体的XML负载(仅消息体部分)时遇到了MismatchedInputException,问题出在将无外层包装的<currentBooks>元素聚合到List的时候。

示例XML负载

<libraryRequest>
  <libraryProfile>
    <libraryId>...</libraryId>
    <libraryName>...</libraryName>
    <newBookInfo>
      <bookId>...</bookId>
      <bookTitle>...</bookTitle>
      <datePublished>...</datePublished>
    </newBookInfo>
    <currentBooks>
      <bookId>...</bookId>
      <bookTitle>...</bookTitle>
      <datePublished>...</datePublished>
    </currentBooks>
    <currentBooks>
      <bookId>...</bookId>
      <bookTitle>...</bookTitle>
      <datePublished>...</datePublished>
    </currentBooks>
    <!-- 更多currentBooks元素 -->
  </libraryProfile>
</libraryRequest>

对应的Java对象结构

public class LibraryRequest {
    private LibraryProfile libraryProfile;

    @XmlElement(name = "libraryProfile")
    public LibraryProfile getLibraryProfile() {
        return libraryProfile;
    }

    // setter 方法
}

public class LibraryProfile {
    // libraryId、libraryName、newBookInfo 的构造器、getter/setter
    private List<BookInfo> bookInfos;

    public List<BookInfo> getBookInfos() {
        return bookInfos;
    }

    // setter 方法
}

public class BookInfo {
    private String bookId;
    private String bookTitle;
    private String datePublished;

    // 构造器、getter/setter
}

我的核心问题是:XML中的<currentBooks>标签没有外层包装元素,且数量不确定,需要把每个<currentBooks>都映射到LibraryProfile里的List<BookInfo>集合,但目前无法正确填充数据。请问能否用JAXB实现?如果不行的话,用Jackson XML功能可以做到吗?最终目标是让Spring Controller接收XML请求后能正确反序列化为Java集合。我使用的是Spring Boot 1.5.8和Jackson 2.9.5。


解决方案

方法一:使用JAXB实现映射

JAXB可以通过@XmlElement注解直接指定列表元素的名称,不需要外层包装。你需要修改LibraryProfile类的bookInfos字段的注解:

public class LibraryProfile {
    // 其他字段的getter/setter

    private List<BookInfo> bookInfos;

    @XmlElement(name = "currentBooks") // 指定XML中对应的元素名称
    public List<BookInfo> getBookInfos() {
        return bookInfos;
    }

    public void setBookInfos(List<BookInfo> bookInfos) {
        this.bookInfos = bookInfos;
    }
}

这样JAXB在反序列化时,会自动把所有<currentBooks>元素收集到bookInfos这个List里,不需要额外的外层包装标签。

另外要确保BookInfo类的字段也正确加上@XmlElement注解,对应XML里的子元素:

public class BookInfo {
    @XmlElement(name = "bookId")
    private String bookId;
    @XmlElement(name = "bookTitle")
    private String bookTitle;
    @XmlElement(name = "datePublished")
    private String datePublished;

    // 无参构造器(JAXB必须要求)、getter/setter
}

方法二:使用Jackson XML实现映射

如果你更倾向于用Jackson处理XML,同样可以通过注解配置来解决无包装列表的问题:

  1. 首先确保你的Spring Boot项目已经引入了Jackson XML依赖:
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.5</version>
</dependency>
  1. 修改LibraryProfile类,使用Jackson XML的专属注解:
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

public class LibraryProfile {
    // 其他字段的getter/setter

    private List<BookInfo> bookInfos;

    // 禁用外层包装,指定每个元素的XML名称
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "currentBooks")
    public List<BookInfo> getBookInfos() {
        return bookInfos;
    }

    public void setBookInfos(List<BookInfo> bookInfos) {
        this.bookInfos = bookInfos;
    }
}
  1. BookInfo类同样需要用Jackson的注解映射字段:
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

public class BookInfo {
    @JacksonXmlProperty(localName = "bookId")
    private String bookId;
    @JacksonXmlProperty(localName = "bookTitle")
    private String bookTitle;
    @JacksonXmlProperty(localName = "datePublished")
    private String datePublished;

    // 构造器、getter/setter
}
  1. 在Spring Controller中,确保正确配置请求接收:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LibraryController {

    @PostMapping(value = "/library", consumes = MediaType.APPLICATION_XML_VALUE)
    public void handleLibraryRequest(@RequestBody LibraryRequest request) {
        // 处理请求,此时request中的libraryProfile.bookInfos已经正确填充了所有currentBooks数据
    }
}

注意事项

  • JAXB要求实体类必须有无参构造器,否则会反序列化失败;Jackson虽然不强制,但建议也加上无参构造器避免潜在问题。
  • 如果你同时使用JAXB和Jackson,要注意Spring Boot默认的消息转换器优先级,避免冲突。如果优先使用Jackson XML,可以配置MappingJackson2XmlHttpMessageConverter作为主要的XML转换器。

内容的提问来源于stack exchange,提问作者user8811650

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:55:59