我有一些类型的XSD Schema,让我们把它命名为A.
然后我尝试使用XSD Schema验证编写MessageBodyReader - 如果我在那里传递单个对象,它会起作用。但是如何管理它来阅读这些类型的集合呢?
我稍后使用该阅读器获取REST服务的输入参数,我在javax.ws.rs.core.Application中注册它。
@Provider
@Produces(MediaType.APPLICATION_XML)
public class AReader implements MessageBodyReader < A >
{
private static final String XSD = "/a.xsd";
@Override
public boolean isReadable(Class < ? > type, Type genericType, Annotation[] arg2, MediaType mediaType)
{
return MediaType.APPLICATION_XML_TYPE.equals(mediaType) && A.class.isAssignableFrom(type);
}
@Override
public AreadFrom(Class < A> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap < String, String > httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException
{
try
{
JAXBContext jaxbContext = JAXBContext.newInstance(A.class);
try
{
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(getSchema());
try
{
return (A) unmarshaller.unmarshal(entityStream);
}
catch (JAXBException e)
{
throw new RuntimeException(e);
}
}
catch (SAXException e)
{
throw new RuntimeException(e);
}
}
catch (JAXBException e)
{
throw new RuntimeException(e);
}
}
private Schema getSchema() throws SAXException
{
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(A.class.getResource(XSD));
return schema;
}
答案 0 :(得分:1)
所以这就是事情。 XML文档必须具有根元素,因此您无法发送类似
的内容<domain></domain>
<domain></domain>
您需要将其包装在另一个根元素中,例如
<domains>
<domain></domain>
<domain></domain>
</domains>
话虽如此,xsd架构还需要反映其他根元素。您无法定义<domain>
元素,并希望针对<domains>
进行验证。
在你的xsd中有了这个,比如
<xsd:element name="domains">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="domain" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="domain">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:int"/>
<xsd:element name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
然后我们可以创建一个Domains
包装类,以及Domain
类
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Domain {
@XmlElement
private int id;
@XmlElement
private String name;
// Getters and Setters
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Domains {
@XmlElementRef(name = "domain")
private List<Domain> domains;
// Getter and Setters
}
然后,我们可以创建MessageBodyReader
以接受Domains
或Domain
类型。像
@Provider
@Consumes(MediaType.APPLICATION_XML)
public class DomainMessageBodyReader implements MessageBodyReader {
private static final String XSD_PATH = "path/to/domains.xsd";
@Context
private Providers providers;
private Schema schema;
public DomainMessageBodyReader() {
try {
initSchema();
} catch (Exception ex) {
Logger.getLogger(DomainMessageBodyReader.class.getName())
.log(Level.SEVERE, null, ex);
throw new InternalServerErrorException();
}
}
private void initSchema() throws Exception {
SchemaFactory factory
= SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
schema = factory.newSchema(new File(XSD_PATH));
}
@Override
public boolean isReadable(Class type, Type type1,
Annotation[] antns, MediaType mt) {
return type == Domain.class || type == Domains.class;
}
@Override
public Object readFrom(Class type, Type type1, Annotation[] antns,
MediaType mt, MultivaluedMap mm, InputStream in)
throws IOException, WebApplicationException {
try {
JAXBContext context = JAXBContext.newInstance(Domains.class,
Domain.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setSchema(schema);
return unmarshaller.unmarshal(in);
} catch (JAXBException ex) {
throw new InternalServerErrorException();
}
}
}
注意Providers
我没有使用它,但您可能想要在跳转到创建新的Providers
之前检查已存在的上下文。如果没有,那么您可以创建一个新的。
因此,对于此MessageBodyReader
,您的JAX-RS资源方法是否接受Domains
(<domains>
)或Domain
(<domain>
),它将通过这个阅读器,并将其发送到正确的资源方法。