minOccurs、nillable 和限制的目的是什么?

发布于 2025-01-01 12:21:13 字数 3410 浏览 0 评论 0 原文

必需<的文档/a> 说:

如果 required()true,则 Javabean 属性映射到 XML 模式元素 使用 minOccurs="1" 进行声明。对于单值,maxOccurs"1" 属性和多值属性的“unbounded”

如果 required()false,则 Javabean 属性将映射到 XML 使用 minOccurs="0" 声明架构元素。 maxOccurs"1" 单值属性和多值属性的“无界”

nillable< 的文档/a> 说:

如果 nillable()true,则 JavaBean 属性将映射到 XML 架构 nillable 元素声明。


Code for xs:complexType:

public class WSData {
    //...

    @XmlElement(required = true, nillable = false)
    public void setMonth(XmlMonthType month) {
        this.month = month;
    }

    public void setUserLogin(String userLogin) {
        this.userLogin = userLogin;
    }
}

xs:simpleType 的代码:

@XmlType
@XmlEnum(Integer.class)
public enum XmlMonthType {
    @XmlEnumValue("1")
    JANUARY,
    @XmlEnumValue("2")
    FEBRUARY,
    @XmlEnumValue("3")
    MARCH,
    /* ... months 4 ~9 ... */
    @XmlEnumValue("10")
    OCTOBER,
    @XmlEnumValue("11")
    NOVEMBER,
    @XmlEnumValue("12")
    DECEMBER;
}

生成的 XML 架构:

<xs:complexType name="wsData">
  <xs:sequence>
    <xs:element name="month" type="xs:string"/>
    <xs:element minOccurs="0" name="userLogin" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<xs:simpleType name="xmlMonthType">
  <xs:restriction base="xs:int">
    <xs:enumeration value="1"/>
    <xs:enumeration value="2"/>
    <xs:enumeration value="3"/>
    <!-- ... months 4 ~9 ... -->
    <xs:enumeration value="10"/>
    <xs:enumeration value="11"/>
    <xs:enumeration value="12"/>
  </xs:restriction>
</xs:simpleType>


The facts:

  1. minOccurs 的默认值为 1。因此,month 是必需的(必须存在);
  2. 该月份有限制。因此,month 只能具有由 12 个定义的枚举之一定义的值;
  3. nillable 的默认值为 false。因此,月份不能有空值;
  4. XML 架构已正确生成。

问题:

  1. 它正在接受月份的 abcense(必须不存在);
  2. 它接受任何月份值,例如 13(除非无法解析为整数);
  3. 它接受空值;

我没想到会出现这些问题,我错过了什么吗?
如果该行为正确,必需可空xs:限制

Documentation for required says:

If required() is
true, then Javabean property is mapped to an XML schema element
declaration with minOccurs="1". maxOccurs is "1" for a single valued
property and "unbounded" for a multivalued property.

If required() is false, then the Javabean property is mapped to XML
Schema element declaration with minOccurs="0". maxOccurs is "1" for a
single valued property and "unbounded" for a multivalued property.

Documentation for nillable says:

If nillable() is true, then the JavaBean property is mapped to a XML
Schema nillable element declaration.


Code for xs:complexType:

public class WSData {
    //...

    @XmlElement(required = true, nillable = false)
    public void setMonth(XmlMonthType month) {
        this.month = month;
    }

    public void setUserLogin(String userLogin) {
        this.userLogin = userLogin;
    }
}

Code for xs:simpleType:

@XmlType
@XmlEnum(Integer.class)
public enum XmlMonthType {
    @XmlEnumValue("1")
    JANUARY,
    @XmlEnumValue("2")
    FEBRUARY,
    @XmlEnumValue("3")
    MARCH,
    /* ... months 4 ~9 ... */
    @XmlEnumValue("10")
    OCTOBER,
    @XmlEnumValue("11")
    NOVEMBER,
    @XmlEnumValue("12")
    DECEMBER;
}

Generated XML Schema:

<xs:complexType name="wsData">
  <xs:sequence>
    <xs:element name="month" type="xs:string"/>
    <xs:element minOccurs="0" name="userLogin" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<xs:simpleType name="xmlMonthType">
  <xs:restriction base="xs:int">
    <xs:enumeration value="1"/>
    <xs:enumeration value="2"/>
    <xs:enumeration value="3"/>
    <!-- ... months 4 ~9 ... -->
    <xs:enumeration value="10"/>
    <xs:enumeration value="11"/>
    <xs:enumeration value="12"/>
  </xs:restriction>
</xs:simpleType>


The facts:

  1. The default value for minOccurs is 1. So, month is required (must exist);
  2. The month has a restriction. So, month can only have a value defined by one of the 12 defined enumerations;
  3. The default value for nillable is false. So, month can't have empty values;
  4. The XML Schema is generated correctly.

The problems:

  1. It is accepting month's abcense (mustn't exist);
  2. It is accepting any values for month, like 13 (except when isn't parseable to Integer);
  3. It is accepting empty values;

I wasn't expecting these problems, am I missing something?
If that behavior is correct, what is the purpose of required, nillable and xs:restriction?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

灯角 2025-01-08 12:21:13

Nillable 允许空值。例如,如果您有一个 Integer 或 Date,如果它可以为空,则 XML 标记可以为空。如果它不是可为空但不是必需的,则 XML 元素要么必须以有效内容存在,要么根本不存在;空标签无效。

Nillable allows empty values. For example, if you have an Integer or a Date, if it's nillable, the XML tag could be empty. If it's not nillable but not required, the XML element would either have to exist with a valid content, or not exist at all; an empty tag wouldn't be valid.

贪恋 2025-01-08 12:21:13

将 minOccurs 设置为 1,以设置月份;

minOccurs 的默认值为 1,因此 month 元素是必需的。请注意如何将 minOccurs="0" 添加到 userLogin 中以使其成为可选。

<xs:complexType name="wsData">
  <xs:sequence>
    <xs:element name="month" type="xs:string"/>
    <xs:element minOccurs="0" name="userLogin" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

使用生成的限制验证月份(不使用 XmlAdapter)。

您可以在 Unmarshaller 上设置 Schema 实例来验证输入:

演示

以下代码可用于生成 XML 模式:

package forum9111936;

import java.io.IOException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(WSData.class);
        SchemaOutputResolver sor = new SchemaOutputResolver() {

            @Override
            public Result createOutput(String namespaceUri,
                    String suggestedFileName) throws IOException {
                StreamResult result = new StreamResult(System.out);
                result.setSystemId(suggestedFileName);
                return result;
            }

        };
        jc.generateSchema(sor);
        System.out.println();
    }

}

UPDATE

JAXB RI 通常会因转换问题引发严重性为 1 的 ValidationEvent。默认的 ValidationEventHandler 会忽略严重性小于 2 的所有问题。这通常会导致该值设置为 null。您可以按如下方式重写 ValidationEventHandler

    unmarshaller.setEventHandler(new ValidationEventHandler() {
        @Override
        public boolean handleEvent(ValidationEvent event) {
            System.out.println(event);
            return event.getSeverity() < ValidationEvent.ERROR;
        }
    });

但是,JAXB RI 似乎不会抛出与转换枚举值相关的事件(可能是错误)。如果您碰巧使用 EclipseLink JAXB (MOXy) 作为 JAXB 提供程序,那么您将收到如下异常:

Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-116] (Eclipse Persistence Services - 2.4.0.qualifier): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: No conversion value provided for the value [13] in field [month/text()].
Mapping: org.eclipse.persistence.oxm.mappings.XMLDirectMapping[month-->month/text()]
Descriptor: XMLDescriptor(forum9111936.WSData --> [])
    at org.eclipse.persistence.exceptions.DescriptorException.noFieldValueConversionToAttributeValueProvided(DescriptorException.java:1052)
    at org.eclipse.persistence.mappings.converters.ObjectTypeConverter.convertDataValueToObjectValue(ObjectTypeConverter.java:140)
    at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getAttributeValue(XMLDirectMapping.java:287)
    at org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.endElement(XMLDirectMappingNodeValue.java:190)
    at org.eclipse.persistence.oxm.record.UnmarshalRecord.endElement(UnmarshalRecord.java:910)
    at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parseEvent(XMLStreamReaderReader.java:133)
    at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parse(XMLStreamReaderReader.java:83)
    at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parse(XMLStreamReaderReader.java:72)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:838)
    at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:626)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:472)
    at forum9111936.Demo2.main(Demo2.java:30)

了解更多信息

Make minOccurs 1, to make month required;

The default value for minOccurs is one, so the month element is required. Note how minOccurs="0" had to be added to userLogin to make it optional.

<xs:complexType name="wsData">
  <xs:sequence>
    <xs:element name="month" type="xs:string"/>
    <xs:element minOccurs="0" name="userLogin" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

Validate month with its generated restriction (without a XmlAdapter).

You can set an instance of Schema on the Unmarshaller to have the input validated:

Demo

The following code can be used to generate the XML schema:

package forum9111936;

import java.io.IOException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(WSData.class);
        SchemaOutputResolver sor = new SchemaOutputResolver() {

            @Override
            public Result createOutput(String namespaceUri,
                    String suggestedFileName) throws IOException {
                StreamResult result = new StreamResult(System.out);
                result.setSystemId(suggestedFileName);
                return result;
            }

        };
        jc.generateSchema(sor);
        System.out.println();
    }

}

UPDATE

The JAXB RI normally throws a ValidationEvent of severity 1 for conversion issues. The default ValidationEventHandler ignores all issues of severity less than 2. This normally results in the value being set to null. You can override the ValidationEventHandler as follows:

    unmarshaller.setEventHandler(new ValidationEventHandler() {
        @Override
        public boolean handleEvent(ValidationEvent event) {
            System.out.println(event);
            return event.getSeverity() < ValidationEvent.ERROR;
        }
    });

However the JAXB RI does not appear to throw events related to converting enum values (possible bug). If you happen to be using EclipseLink JAXB (MOXy) as your JAXB provider then you will get an exception like:

Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-116] (Eclipse Persistence Services - 2.4.0.qualifier): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: No conversion value provided for the value [13] in field [month/text()].
Mapping: org.eclipse.persistence.oxm.mappings.XMLDirectMapping[month-->month/text()]
Descriptor: XMLDescriptor(forum9111936.WSData --> [])
    at org.eclipse.persistence.exceptions.DescriptorException.noFieldValueConversionToAttributeValueProvided(DescriptorException.java:1052)
    at org.eclipse.persistence.mappings.converters.ObjectTypeConverter.convertDataValueToObjectValue(ObjectTypeConverter.java:140)
    at org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getAttributeValue(XMLDirectMapping.java:287)
    at org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.endElement(XMLDirectMappingNodeValue.java:190)
    at org.eclipse.persistence.oxm.record.UnmarshalRecord.endElement(UnmarshalRecord.java:910)
    at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parseEvent(XMLStreamReaderReader.java:133)
    at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parse(XMLStreamReaderReader.java:83)
    at org.eclipse.persistence.internal.oxm.record.XMLStreamReaderReader.parse(XMLStreamReaderReader.java:72)
    at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:838)
    at org.eclipse.persistence.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:626)
    at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:472)
    at forum9111936.Demo2.main(Demo2.java:30)

For More Information

北渚 2025-01-08 12:21:13

requiredminOccurs 的目的并没有误导,问题是未启用架构验证。只需启用SchemaValidationWebService定义顺序XmlType 的映射如下:

Web Service:

@javax.jws.WebService
@org.jboss.ws.annotation.SchemaValidation(enabled = true)
public class WebServiceClass {

    @javax.jws.WebMethod
    public WSResponseData webServiceMethod() {
        //...
    }
}

XmlType:

@javax.xml.bind.annotation.XmlType(propOrder = {"field1", "field2", "field3"})
public class WSData {
    //...

    private String field1;

    private Long field2;

    private XmlMonthType field3;

    //...
}

The purposes of required and minOccurs aren't mislead, the problem is that the schema validation is not enabled. Just enable SchemaValidation to the WebService and define the order of the XmlType's mapping as follows:

Web Service:

@javax.jws.WebService
@org.jboss.ws.annotation.SchemaValidation(enabled = true)
public class WebServiceClass {

    @javax.jws.WebMethod
    public WSResponseData webServiceMethod() {
        //...
    }
}

XmlType:

@javax.xml.bind.annotation.XmlType(propOrder = {"field1", "field2", "field3"})
public class WSData {
    //...

    private String field1;

    private Long field2;

    private XmlMonthType field3;

    //...
}
苍白女子 2025-01-08 12:21:13

事实上,SOAP 信封似乎没有在 WSDL 上进行验证,无论是在服务器还是客户端上。

我认为这样最好。验证消耗资源和时间。对于大多数 WebServices,我们所需要的 WSDL 就是向客户端提供能够与 WebService 通信的定义,而不是设置诸如属性是否可以为 null 之类的限制。

当服务器和客户端位于同一台 PC 上时,Axis2 与内部调用相比会增加 3-5 毫秒的开销。不必要的验证只会增加开销。我最好让操作抛出异常并手动验证真正需要的内容。

Indeed it seems that SOAP envelopes aren't validated upon WSDL, neither on server or client.

And I think it's best this way. Validation consumes resources and time. For most WebServices, all we need with WSDL is to provide to client the definitions to be able to talk to WebService, and not set restrictions like if a property can or not be null.

When server and client are on same PC, Axis2 add 3-5 milisecs of overhead compared to internal calls. Unecessary validation would only increase overhead. I's better to make operations throw an exception and manually validate what's really needed.

萌梦深 2025-01-08 12:21:13

我查看了您发布的 XSD 结构 - 发现您没有使用为该月定义的复杂类型,在 Java 代码上处理它的 Insteqad 您可以在 XSD 中提及所有内容,以及月份的 minOccur -您的复杂类型中缺少元素。请使用任何标准的XSD to java生成器,它将为您完成所有java文件生成任务

The convention are as follow - 

MinOccur = 0 --> the element can be abscent in input , and can be present

MinOccur = 1 --> the element must be there in input
(but if you use it, then your java generated member will be of list type - list of ENUM for Int )

If you don't write MinOccur in attributes - then it makes the element mandatory , ( then you java generated member will be of simply ENUM for int )


MaxOccur = 1 --> minimum one element can be there in input 
(but if you use it, then your java generated member will be of list type - list of ENUM for Int )


MaxOccur = unbound --> only one element can be there in input 
(if you use it, then your java generated member will be of list type - list of ENUM for Int )

   <xs:complexType name="wsData">
  <xs:sequence>
    <xs:element name="month" type="xmlMonthType" minOccurs="1" nillable="false" />
    <xs:element name="userLogin" type="xs:string" minOccurs="0" />
  </xs:sequence>
</xs:complexType>

<xs:simpleType name="xmlMonthType">
  <xs:restriction base="xs:int">
    <xs:enumeration value="1"/>
    <xs:enumeration value="2"/>
    <xs:enumeration value="3"/>
    <!-- ... months 4 ~9 ... -->
    <xs:enumeration value="10"/>
    <xs:enumeration value="11"/>
    <xs:enumeration value="12"/>
  </xs:restriction>
</xs:simpleType>

I looked into the XSD structure that you have posted - and find that you have not used complex type that you have defined for the month , Insteqad of handling it on java code you can mention that all in XSD , and also the minOccur on month - element in your complex type is missing . Please use any standered XSD to java generator , it will do all the java file generation task for you

The convention are as follow - 

MinOccur = 0 --> the element can be abscent in input , and can be present

MinOccur = 1 --> the element must be there in input
(but if you use it, then your java generated member will be of list type - list of ENUM for Int )

If you don't write MinOccur in attributes - then it makes the element mandatory , ( then you java generated member will be of simply ENUM for int )


MaxOccur = 1 --> minimum one element can be there in input 
(but if you use it, then your java generated member will be of list type - list of ENUM for Int )


MaxOccur = unbound --> only one element can be there in input 
(if you use it, then your java generated member will be of list type - list of ENUM for Int )

   <xs:complexType name="wsData">
  <xs:sequence>
    <xs:element name="month" type="xmlMonthType" minOccurs="1" nillable="false" />
    <xs:element name="userLogin" type="xs:string" minOccurs="0" />
  </xs:sequence>
</xs:complexType>

<xs:simpleType name="xmlMonthType">
  <xs:restriction base="xs:int">
    <xs:enumeration value="1"/>
    <xs:enumeration value="2"/>
    <xs:enumeration value="3"/>
    <!-- ... months 4 ~9 ... -->
    <xs:enumeration value="10"/>
    <xs:enumeration value="11"/>
    <xs:enumeration value="12"/>
  </xs:restriction>
</xs:simpleType>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文