Spring MVC - 接收 XML 对象并反序列化为集合

Spring MVC - receiving XML Objects and deserialzing into Collection

我正在尝试使用特定的标记/对象​​层次结构反序列化 XML 有效负载(SOAP 消息的主体,除此之外别无其他)。尝试将未包装的对象聚合到列表中时,会抛出 MismatchedInputException。

示例负载

<libraryRequest>
  <libraryProfile>
    <libraryId>
    <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>...</currentBooks>
  </libraryProfile>
</libraryRequest>

Java 个对象是

public class LibraryRequest {
    private LibraryProfile libraryProfile;
    @XmlElement(name = "libraryProfile")
    public LibraryProfile getLibraryProfile(){
    ...
    }
// setters

public class LibraryProfile {
    // constructors, getters & setters for primitive types 

    private List<BookInfo> bookInfos;
    public List<BookInfo> getBookInfo(){
        return this.BookInfos;
    }
    // rest of the functions

我的问题是我不知道有多少 currentBooks 标签会出现在 XML 有效负载中,而且它们不会出现在包装器元素中。我需要跟踪每个 currentBook 元素,这就是我使用 Collection 的原因,但我无法使用 currentBooks 标签中包含的信息正确填充集合。

我能否使用 JAXB 将 XML 序列分组为 Java Collection/List,如果不能,我能否使用 Jackson 的 XML 功能将展开的 XML 标签分组到 Java 集合中?

主要目标是使用 XML 请求进入 Spring 控制器,并将 XML 序列正确反序列化为 Java 列表/集合。任何建议都会有所帮助。

我正在使用 Spring Boot 1.5.8(更高版本以不同的方式给我带来麻烦)和 Jackson 版本 2.9.5

这是基于XmlElement explanation from actimem.com

机械师解释说: - @XmlElement 仅在字段名称不等于 xml 标记名称时才需要。 - 如果您想将字段 newBookInfo 重命名为 newestBook 但不更改 xml,您只需重命名字段并用 @XmlElement(name="newBookInfo") 注释 - @XmlElementWrapper 明确不用于建议 JAXB 它应该直接在父节点中搜索列表标签

XML表示classes Book

@XmlAccessorType(XmlAccessType.FIELD)
public static class Book {
    private String bookId;
    private String bookTitle;
    // ... accessors and toString 
}

LibraryProfile

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class LibraryProfile {
    private String libraryId;
    private String libraryName;
    private Book newBookInfo;
    // the trick is NOT to use @XmlElementWrapper here
    private List<Book> currentBooks;
    private String foobar; // just to show a tag after the list 
    // ... accessors
}

基于你的问题的输入(我跳过了 <libraryRequest> 以保持示例简短)

  <libraryProfile>
    <libraryId>1</libraryId>
    <libraryName>library of alexandria</libraryName>
    <newBookInfo>
      <bookId>42</bookId>
      <bookTitle>the answer</bookTitle>
    </newBookInfo>
    <currentBooks>
      <bookId>2</bookId>
      <bookTitle>the second</bookTitle>
    </currentBooks>
    <currentBooks>
      <bookId>1</bookId>
      <bookTitle>the first</bookTitle>
    </currentBooks>
    <foobar>test-foo</foobar>
  </libraryProfile>

这里是测试 class:

package com.Whosebug.answer;

import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.StringReader;

public class Tester {

    public static final String INPUT = "..."; // here goes your xml

    public static void main(String[] args) throws Exception {
        LibraryProfile lib = JAXB.unmarshal(new StringReader(INPUT), LibraryProfile.class);
        System.out.println(lib.getLibraryName() + " currently contains");
        System.out.println(lib.getCurrentBooks());
        System.out.println("the newest book is: " + lib.getNewBookInfo());
    }
}

现在的输出是

library of alexandria currently contains
[Book{bookId='2', bookTitle='the second'}, Book{bookId='1', bookTitle='the first'}]
the newest book is: Book{bookId='42', bookTitle='the answer'}