Какова цель minOccurs, nillable и ограничения?
Документация для необходимых говорит:
Если
required()
являетсяtrue
затем свойство Javabean отображается в объявление элемента схемы XML сminOccurs="1"
,maxOccurs
является"1"
для однозначного имущества и"unbounded"
для многозначного свойства.Если
required()
являетсяfalse
затем свойство Javabean отображается в объявление элемента схемы XML с помощьюminOccurs="0"
,maxOccurs
является"1"
для однозначного имущества и"unbounded"
для многозначного свойства.
Документация для nillable гласит:
Если
nillable()
являетсяtrue
тогда свойство JavaBean сопоставляется со схемой XMLnillable
объявление элемента.
Код для
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>
Факты:
- Значение по умолчанию для minOccurs равно 1. Таким образом, требуется месяц (должен существовать);
- Месяц имеет ограничение. Таким образом, месяц может иметь значение, определенное только одним из 12 определенных перечислений;
- Значением по умолчанию для nillable является false. Таким образом, месяц не может иметь пустых значений;
- Схема XML сгенерирована правильно.
Проблемы:
- Принимает месяц отсутствия (не должно существовать);
- Он принимает любые значения за месяц, например 13 (кроме случаев, когда он не разбирается в Integer);
- Он принимает пустые значения;
Я не ожидал этих проблем, я что-то упустил?
Если это поведение правильное, какова цель требуемого, нулевого и ограничения xs :?
5 ответов
Nillable допускает пустые значения. Например, если у вас есть целочисленное значение или дата, если она пустая, тег XML может быть пустым. Если это не nillable, но не требуется, элемент XML должен либо существовать с допустимым содержимым, либо вообще не существовать; пустой тег не будет действительным.
Сделать minOccurs 1, чтобы сделать месяц требуется;
Значение по умолчанию для minOccurs
один, так что 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).
Вы можете установить экземпляр Schema
на Unmarshaller, чтобы подтвердить ввод:
демонстрация
Следующий код может быть использован для генерации схемы 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();
}
}
ОБНОВИТЬ
JAXB RI обычно бросает ValidationEvent
серьезности 1 для вопросов конверсии. По умолчанию ValidationEventHandler
игнорирует все проблемы с серьезностью меньше 2. Это обычно приводит к тому, что значение устанавливается равным нулю. Вы можете переопределить 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)
Для дополнительной информации
Цели required
а также minOccurs
не вводят в заблуждение, проблема в том, что проверка схемы не включена. Просто включите SchemaValidation
к WebService
и определить порядок XmlType
сопоставляем следующим образом:
Веб-сервис:
@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;
//...
}
Я посмотрел на структуру XSD, которую вы опубликовали - и обнаружил, что вы не использовали сложный тип, который вы определили для месяца. В Insteqad для обработки его с помощью кода Java вы можете упомянуть, что все в XSD, а также minOccur в месяце - элемент в вашем сложном типе отсутствует. Пожалуйста, используйте любой стандартный XSD для генератора 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>
Действительно, кажется, что конверты SOAP не проверяются на WSDL, ни на сервере, ни на клиенте.
И я думаю, что так лучше. Валидация требует ресурсов и времени. Для большинства WebServices все, что нам нужно с WSDL, - это предоставить клиенту определения, чтобы иметь возможность общаться с WebService, а не устанавливать ограничения, например, если свойство может быть или не быть нулевым.
Когда сервер и клиент находятся на одном компьютере, Axis2 добавляет 3-5 миллисекунд накладных расходов по сравнению с внутренними вызовами. Излишняя проверка только увеличит накладные расходы. Лучше, чтобы операции генерировали исключение и вручную проверяли, что действительно нужно.