首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java XSD -使用自定义集合类型

Java XSD -使用自定义集合类型
EN

Stack Overflow用户
提问于 2021-06-22 13:14:15
回答 2查看 126关注 0票数 0

我的问题

我正在使用XSD插件将我的jaxb2定义的对象转换成Java类。我的目标是将XSD中的一个列表类型元素(比如xs:choice unbound)设置为LinkedList,而不是使用默认的ArrayList类型。我使用的是jaxb-xew-plugin版本1.10。下面是我的相关代码:

XSD:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema jaxb:version="2.0"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
           xmlns:xew="http://github.com/jaxb-xew-plugin"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           jaxb:extensionBindingPrefixes="xew"
           elementFormDefault="qualified">

    <xs:element name="TEST">
        <xs:complexType>
            <xs:annotation>
                <xs:appinfo>
                    <xew:xew collection="java.util.LinkedList"
                             collectionInterface="java.util.List"
                             instantiate="lazy"
                             plural="true"/>
                </xs:appinfo>
            </xs:annotation>
            <xs:choice>
                <xs:element name="action" type="xs:token" minOccurs="0" maxOccurs="unbounded">
                </xs:element>
            </xs:choice>
        </xs:complexType>
    </xs:element>

</xs:schema>

POM:

代码语言:javascript
复制
    <build>
        <resources>
            <resource>
                <directory>src/main/xsd</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>2.5.0</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                        <configuration>
                            <sources>src/main/xsd</sources>
                            <packageName>com.tug.data.model.gen</packageName>
                            <verbose>true</verbose>
                            <clearOutputDir>false</clearOutputDir>
                            <extension>true</extension>
                            <arguments>
                                <argument>-Xsetters</argument>
                                <argument>-Xxew</argument>
                                <argument>-Xfluent-api</argument>
                                <argument>-Xjaxbindex</argument>
                                <argument>-Xequals</argument>
                                <argument>-XhashCode</argument>
                                <argument>-XtoString</argument>
                                <argument>-Xcopyable</argument>
                                <argument>-Xmergeable</argument>
                            </arguments>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>com.github.jaxb-xew-plugin</groupId>
                        <artifactId>jaxb-xew-plugin</artifactId>
                        <version>1.10</version>
                    </dependency>
                    <dependency>
                        <groupId>net.java.dev.jaxb2-commons</groupId>
                        <artifactId>jaxb-fluent-api</artifactId>
                        <version>2.1.8</version>
                    </dependency>
                    <dependency>
                        <groupId>org.jvnet.jaxb2_commons</groupId>
                        <artifactId>jaxb2-basics</artifactId>
                        <version>0.12.0</version>
                    </dependency>
                </dependencies>
            </plugin>

生成的结果Java代码

代码语言:javascript
复制
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "action"
})
@XmlRootElement(name = "TEST")
public class TEST implements Cloneable, CopyTo2, Equals2, HashCode2, MergeFrom2, ToString2
{

    @XmlElement(required = true)
    protected List<Action> action;

    public List<Action> getAction() {
        if (action == null) {
            action = new ArrayList<Action>(); // <--- **This should have been LinkedList**
        }
        return this.action;
    }

正如您所看到的,ArrayList类型仍然会取代LinkedList。实际上,xew参数和命令似乎被完全忽略了……我没有收到任何错误

我已经尝试了很多不同的方法,我把xs:annotation格式回复信息复制和粘贴到了我能想到的所有位置的组合中。我得到的唯一错误是:

代码语言:javascript
复制
    <xs:element name="TEST">
        <xs:complexType>
            <xs:choice>
                <xs:element name="action" type="xs:token" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                        <xs:appinfo>
                            <xew:xew collection="java.util.LinkedList"
                                     collectionInterface="java.util.List"
                                     instantiate="lazy"
                                     plural="true"/>
                        </xs:appinfo>
                    </xs:annotation>
                </xs:element>
            </xs:choice>
        </xs:complexType>
    </xs:element>

这个组合的结果是:com.sun.istack.SAXParseException2: compiler was unable to honor this xew customization. It is attached to a wrong place, or its inconsistent with other bindings.

你有没有看到任何会导致我的自定义集合覆盖不被拾取的缺失步骤?

我附加了maven debug输出,它有很多东西要看,而且我没有从中获得任何提示。mvn-debug.log

或者..。

在从XSD生成Java对象时,有没有其他方法可以使用自定义列表类型?

(PS。我在github部分提交了jaxb-xew- cross-posted this,但是我意识到上一次提交是在2年前,所以它可能是一个休眠的项目。在这里发布SOF社区的帮助)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-06-28 06:51:02

在您提供的XSD范围内,自定义是有意义的。你需要理解Xew插件的作用:如果类型A有一些像我们例子中的类型测试这样复杂的字段,那么我们有一个"matroska“A→测试→列表,在这种情况下,插件试图从模型中删除类型测试。现在你在你的例子中只提供了测试,这只是故事的一半,在这种情况下插件不会做任何事情。您还需要提供另一个使用TEST的类型A,例如:

代码语言:javascript
复制
<xs:element name="A">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="TEST">
                <xs:annotation>
                    <xs:appinfo>
                        <xew:xew collection="java.util.LinkedList"
                                 collectionInterface="java.util.List"
                                 instantiate="lazy"
                                 plural="true"/>
                    </xs:appinfo>
                </xs:annotation>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:element name="TEST">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="action" type="xs:token" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

这就是插件启动的地方。您将在输出中看到:

代码语言:javascript
复制
[INFO] Modifications:
[INFO]     Replacing field [TEST com.tug.data.model.gen.A#test]
[INFO]     1 modification(s) to original code.
[INFO]
[INFO] Deletions:
[INFO]     Removing class com.tug.data.model.gen.TEST from package com.tug.data.model.gen
[INFO]     Removing factory method [com.tug.data.model.gen.TEST#createTEST()] from com.tug.data.model.gen.ObjectFactory
[INFO]     2 deletion(s) from original code.

生成的类将是(我删除了不相关的人员):

代码语言:javascript
复制
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "tests"
})
@XmlRootElement(name = "A")
public class A implements Cloneable, CopyTo2, Equals2, HashCode2, MergeFrom2, ToString2
{

    @XmlElementWrapper(name = "TEST", required = true)
    @XmlElement(name = "action")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    protected List<String> tests;

    public List<String> getTESTS() {
        if (tests == null) {
            tests = new LinkedList<String>();
        }
        return tests;
    }

    public void setTESTS(List<String> tests) {
        this.tests = tests;
    }

    public A withTESTS(String... values) {
        if (values!= null) {
            for (String value: values) {
                getTESTS().add(value);
            }
        }
        return this;
    }

    public A withTESTS(Collection<String> values) {
        if (values!= null) {
            getTESTS().addAll(values);
        }
        return this;
    }

    public A withTESTS(List<String> tests) {
        setTESTS(tests);
        return this;
    }

    ...
}

这就是LinkedList出现的地方。

所以插件不会修改测试类型。基本上,政策将是“要么删除它,要么不管它”。如果要自己自定义类型测试,则需要使用本机JAXB customization collectionType

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema jaxb:version="2.0"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">

    <xs:element name="TEST">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="action" type="xs:token" minOccurs="0" maxOccurs="unbounded">
                    <xs:annotation>
                        <xs:appinfo>
                            <jaxb:property collectionType="java.util.LinkedList" />
                        </xs:appinfo>
                    </xs:annotation>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
票数 1
EN

Stack Overflow用户

发布于 2021-06-27 08:36:25

您必须定制JAXB绑定。因此,在项目的一个目录中,比如src/main/xjb,创建一个类似这样的文件(注意collectionType):

代码语言:javascript
复制
<bindings version="2.0" xmlns="http://java.sun.com/xml/ns/jaxb">
 <globalBindings collectionType="java.util.Linkedlist"/>
</bindings>

这将全局定制Java类型(针对所有模式中的所有元素)。

如果您只想为特定元素进行自定义,例如本例中的action元素,请改为指定模式位置和元素的XPath (例如,假设xsd为src/main/xsd文件夹):

代码语言:javascript
复制
<bindings version="2.0" xmlns="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <bindings schemaLocation="../xsd/schema.xsd" node="//xs:element[@name='action']">
  <property collectionType="java.util.LinkedList" />
 </bindings>
</bindings>

然后在POM中的jaxb2 maven插件配置中使用它:

代码语言:javascript
复制
...
<configuration>
 <sources>src/main/xsd</sources>
 <xjbSources>
  <xjbSource>src/main/xjb</xjbSource>
 </xjbSources>
...
</configuration>
...

XML模式不会被修改,并且保持与平台/语言无关。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68077880

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档