Soap 如何解组WSImport为子集合生成的嵌套静态包装类

Soap 如何解组WSImport为子集合生成的嵌套静态包装类,soap,jaxb,wsdl,unmarshalling,wsimport,Soap,Jaxb,Wsdl,Unmarshalling,Wsimport,我正在编写一个基于SOAP的web服务和一个客户端应用程序,该应用程序使用从XML文件读取的导入数据调用web服务。 我使用wsimport从WSDL文件为客户机生成必要的类 导入文件Books.xml必须如下所示: <?xml version="1.0" encoding="UTF-8"?> <books> <book isbn="aaa" title="Aaa" subtitle="aaa" description="aaa" pages="25" la

我正在编写一个基于SOAP的web服务和一个客户端应用程序,该应用程序使用从XML文件读取的导入数据调用web服务。 我使用wsimport从WSDL文件为客户机生成必要的类

导入文件Books.xml必须如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book isbn="aaa" title="Aaa" subtitle="aaa" description="aaa" pages="25" language="german">
         <publisher name="a" postcode="a" countrycode="a" />
         <authors>
             <author firstname="a" lastname="a" birthday="1999-01-01" />
         </authors>
    </book>
</books>
这将产生以下结果:

<books xmlns:ns2="http://technikumwien.at/">
    <book isbn="aaa" title="Aaa" subtitle="aaa" description="aaa" pages="25" language="german">
        <ns2:publisher publisherId="0" name="a" postcode="a" countrycode="a"/>
        <ns2:authors/>
    </book>
</books>
我查看了wsimport生成的客户机Book.java—作者列表已转换为嵌套的静态类:

/**
 * <p>Java-Klasse für anonymous complex type.
 * 
 * <p>Das folgende Schemafragment gibt den erwarteten Content an, der in dieser Klasse enthalten ist.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element ref="{http://technikumwien.at/}author" maxOccurs="unbounded" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "author"
})
public static class Authors {

    protected List<Author> author;

    /**
     * Gets the value of the author property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the author property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getAuthor().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Author }
     * 
     * 
     */
    public List<Author> getAuthor() {
        if (author == null) {
            author = new ArrayList<Author>();
        }
        return this.author;
    }

}
* * * *列表中允许以下类型的对象 *{@link Author} * * */ 公共列表作者{ 如果author==null{ 作者=新ArrayList; } 返回此.author; } } 我注意到@XmlType注释的name属性已创建为空,如果我将@XmlTypename=替换为@XmlTypename=作者,则解组成功捕获书籍的Author子元素:

    @XmlSchema(
            namespace = "http://technikumwien.at/",
            elementFormDefault = XmlNsForm.QUALIFIED,
            xmlns = {
                    @XmlNs(prefix="", namespaceURI="http://technikumwien.at/")
            }
    )

    @XmlJavaTypeAdapters({
            @XmlJavaTypeAdapter(type=LocalDate.class, value=LocalDateXmlAdapter.class)
    })

    package at.technikumwien;
    import javax.xml.bind.annotation.*;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
    import java.time.LocalDate;
启动WildFly时自动生成的Wsdl文件的一部分:

@Entity
@Table(name="author")
@NamedQueries({
        @NamedQuery(name="Author.selectAll", query="SELECT a FROM Author a"),
        @NamedQuery(name="Author.checkExists", query="SELECT a FROM Author a WHERE a.firstname = :firstname AND a.lastname = :lastname AND a.birthday = :birthday")
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlAttribute(name="authorId")
    private long authorId;
    @XmlAttribute(name="firstname")
    private String firstname;
    @XmlAttribute(name="lastname")
    private String lastname;
    @XmlAttribute(name="birthday")
    @Convert(converter = LocalDatePersistenceConverter.class)
    private LocalDate birthday;
    @ManyToMany
    @XmlTransient
    private List<Book> books = new ArrayList<Book>();
服务器的Book.java

服务器的Author.java

我遇到的问题是预期行为还是遗漏了什么?默认情况下,解组器不应该使用wsimport生成的类捕获XML层次结构的所有子级吗


Sry发布了这么多的代码,但也许这对解决问题很有意义。希望任何人都能提示我正确的方向。谢谢大家!

我无法从所有这些代码中确定您是否在服务器和客户端中使用相同的类书。如果你这样做,就不会有任何问题不管怎么说,如果你控制双方:你需要包装器元素做什么?在服务器上我使用一个自编的类Book.java,它是从底部开始的第二个代码块,在客户端我使用一个由wsimport生成的Book.java。我需要使用包装器,因为我不允许更改import Books.xml的格式。是的,我试过不用包装纸,效果很好,但我正在寻找一种方法使其工作,包括包装器元素我认为最优雅的解决方案是找到一种方法wsimport-自动生成嵌套的Book.Authors类,注释为@XmlTypename=Authors,而不是@XmlTypename=,但我不知道这是否可行,@XmlElement属性名=xxxxx就解决了这个问题。您可以在使用Maven生成的过程中更改此属性。
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<books xmlns:ns2="http://technikumwien.at/">
    <book isbn="aaa" title="Aaa" subtitle="aaa" description="aaa" pages="25" language="german">
        <ns2:publisher publisherId="0" name="a" postcode="a" countrycode="a"/>
        <ns2:authors>
            <ns2:author authorId="0" firstname="a" lastname="a" birthday="1999-01-01"/>
        </ns2:authors>
    </book>
</books>
private static final List<Book> traverseLevel(TreeWalker walker, Unmarshaller unmarshaller, List<Book> bookList) throws JAXBException {
    Node parent = walker.getCurrentNode();

    if (parent.getNodeName().equals("book"))
    {
        JAXBElement<Book> bookElem = unmarshaller.unmarshal(parent, Book.class);
        Book book = bookElem.getValue();
        bookList.add(book);
    }

    if (parent.getNodeName().equals("author"))
    {
        JAXBElement<Author> authorElem = unmarshaller.unmarshal(parent, Author.class);
        Author author = authorElem.getValue();
        bookList.get(bookList.size() - 1).getAuthors().getAuthor().add(author);
    }

    for (Node n = walker.firstChild(); n != null; n = walker.nextSibling()) {
        traverseLevel(walker, unmarshaller, bookList);
    }
    walker.setCurrentNode(parent);

    return  bookList;
}
    @XmlSchema(
            namespace = "http://technikumwien.at/",
            elementFormDefault = XmlNsForm.QUALIFIED,
            xmlns = {
                    @XmlNs(prefix="", namespaceURI="http://technikumwien.at/")
            }
    )

    @XmlJavaTypeAdapters({
            @XmlJavaTypeAdapter(type=LocalDate.class, value=LocalDateXmlAdapter.class)
    })

    package at.technikumwien;
    import javax.xml.bind.annotation.*;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
    import java.time.LocalDate;
<xs:complexType name="book">
  <xs:sequence>
    <xs:element minOccurs="0" ref="publisher"></xs:element>
    <xs:element minOccurs="0" name="authors">
      <xs:complexType>
        <xs:sequence>
          <xs:element maxOccurs="unbounded" minOccurs="0" ref="author"></xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
  </xs:sequence>
  <xs:attribute name="bookId" type="xs:long"></xs:attribute>
  <xs:attribute name="isbn" type="xs:string"></xs:attribute>
  <xs:attribute name="title" type="xs:string"></xs:attribute>
  <xs:attribute name="subtitle" type="xs:string"></xs:attribute>
  <xs:attribute name="description" type="xs:string"></xs:attribute>
  <xs:attribute name="pages" type="xs:int" use="required"></xs:attribute>
  <xs:attribute name="language" type="xs:string"></xs:attribute>
</xs:complexType>
<xs:complexType name="publisher">
  <xs:sequence></xs:sequence>
  <xs:attribute name="publisherId" type="xs:long" use="required"></xs:attribute>
  <xs:attribute name="name" type="xs:string"></xs:attribute>
  <xs:attribute name="postcode" type="xs:string"></xs:attribute>
  <xs:attribute name="countrycode" type="xs:string"></xs:attribute>
</xs:complexType>
<xs:complexType name="author">
  <xs:sequence></xs:sequence>
  <xs:attribute name="authorId" type="xs:long" use="required"></xs:attribute>
  <xs:attribute name="firstname" type="xs:string"></xs:attribute>
  <xs:attribute name="lastname" type="xs:string"></xs:attribute>
  <xs:attribute name="birthday" type="xs:string"></xs:attribute>
</xs:complexType>
@Entity
@Table(name="book")
@NamedQueries({
    @NamedQuery(name="Book.selectAll", query="SELECT b FROM Book b"),
    @NamedQuery(name="Book.selectByTitle", query="SELECT b FROM Book b WHERE b.title like CONCAT('%', :title ,'%')")
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlAttribute(name="bookId")
    private Long bookId;
    @XmlAttribute(name="isbn")
    private String isbn;
    @XmlAttribute(name="title")
    private String title;
    @XmlAttribute(name="subtitle")
    private String subtitle;
    @XmlAttribute(name="description")
    private String description;
    @XmlAttribute(name="pages")
    private int pages;
    @XmlAttribute(name="language")
    private String language;
    @ManyToOne(optional = false)
    @NotNull
    @XmlElement(name="publisher")
    private Publisher publisher;
    @ManyToMany(mappedBy = "books", fetch = FetchType.EAGER)
    @NotEmpty
    @XmlElementWrapper(name="authors")
    @XmlElement(name="author")
    private List<Author> authors;
@Entity
@Table(name="author")
@NamedQueries({
        @NamedQuery(name="Author.selectAll", query="SELECT a FROM Author a"),
        @NamedQuery(name="Author.checkExists", query="SELECT a FROM Author a WHERE a.firstname = :firstname AND a.lastname = :lastname AND a.birthday = :birthday")
})
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlAttribute(name="authorId")
    private long authorId;
    @XmlAttribute(name="firstname")
    private String firstname;
    @XmlAttribute(name="lastname")
    private String lastname;
    @XmlAttribute(name="birthday")
    @Convert(converter = LocalDatePersistenceConverter.class)
    private LocalDate birthday;
    @ManyToMany
    @XmlTransient
    private List<Book> books = new ArrayList<Book>();