在JPA / JAX-RS Web服务中validationJAXBElement

我有一个JAX-RS webservice(Jersey),它是JPA(EclipseLink)实体的CRUD接口。 我的实体是从数据库表中自动生成的,我用JAXB注释对它们进行了注释,以便它们可以编组/解组到XML。 我的资源方法将JAXBElement对象作为必需的参数。

我没有XSD,但是,我愿意写一个来validation请求中收到的XML。 但是,我不知道如何启动validation。 Jersey自动处理编组/解组,我发现的有关validation的任何参考都是在该级别完成的。

有人知道一个示例/教程,说明如何做到这一点?

谢谢!

您可以通过创建自定义MessageBodyReader来处理此问题。 以下示例基于Customer模型:

import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.net.URL; import javax.ws.rs.Consumes; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.Providers; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; @Provider @Consumes("application/xml") public class ValidatingReader implements MessageBodyReader { @Context protected Providers providers; private Schema schema; public ValidatingReader() { try { SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); URL schemaURL = null; schema = sf.newSchema(schemaURL); } catch(Exception e) { throw new RuntimeException(e); } } public boolean isReadable(Class arg0, Type arg1, Annotation[] arg2, MediaType arg3) { return arg0 == Customer.class; } public Customer readFrom(Class arg0, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap arg4, InputStream arg5) throws IOException, WebApplicationException { try { JAXBContext jaxbContext = null; ContextResolver resolver = providers.getContextResolver(JAXBContext.class, arg3); if(null != resolver) { jaxbContext = resolver.getContext(arg0); } if(null == jaxbContext) { jaxbContext = JAXBContext.newInstance(arg0); } Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); unmarshaller.setSchema(schema); return (Customer) unmarshaller.unmarshal(arg5); } catch(JAXBException e) { throw new RuntimeException(e); } } } 

我们可以更进一步,创建一个通用的(抽象的)ValidatingReader,它可以在需要时进行细分。 这就是我所做的,感谢Blaise的想法:

 import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.Providers; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; public abstract class AbstractValidatingReader implements MessageBodyReader { @Context protected Providers providers; @SuppressWarnings("unchecked") @Override public boolean isReadable(Class arg0, Type arg1, Annotation[] arg2, MediaType arg3) { Class readableClass = (Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; return arg0 == readableClass; } @SuppressWarnings("unchecked") @Override public T readFrom(Class arg0, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap arg4, InputStream arg5) throws IOException, WebApplicationException { T type = null; JAXBContext jaxbContext = null; ContextResolver resolver = providers.getContextResolver( JAXBContext.class, arg3); try { if (resolver != null) { jaxbContext = resolver.getContext(arg0); } if (jaxbContext == null) { jaxbContext = JAXBContext.newInstance(arg0); } type = (T) jaxbContext.createUnmarshaller().unmarshal(arg5); validate(type); } catch (JAXBException e) { throw new WebApplicationException( Response.Status.INTERNAL_SERVER_ERROR); } return type; } protected abstract void validate(T arg0) throws WebApplicationException; } 

覆盖validate方法并使用@Provider注释子类,我们就完成了。