Java 验证JPA/JAX-RSWeb服务中的JAXBElement

Java 验证JPA/JAX-RSWeb服务中的JAXBElement,java,validation,jaxb,jersey,eclipselink,Java,Validation,Jaxb,Jersey,Eclipselink,我有一个JAX-RSWebService(Jersey),它是JPA(EclipseLink)实体的CRUD接口。我的实体是从数据库表自动生成的,我已经用JAXB注释对它们进行了注释,以便它们可以编组/解编组到XML或从XML中编组。我的资源方法在需要时将JAXBElement对象作为参数 我没有XSD,但是,我愿意编写一个XSD来验证请求中接收到的XML。但是,我不知道如何启动验证。Jersey正在自动处理编组/解编组,我发现的任何有关验证的参考都是在该级别完成的 有人知道如何做的示例/教程吗

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

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

有人知道如何做的示例/教程吗


谢谢

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

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<Customer> {

    @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<Customer> arg0, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap<String, String> arg4, InputStream arg5)
            throws IOException, WebApplicationException {
        try {
            JAXBContext jaxbContext = null;
            ContextResolver<JAXBContext> 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);
        }
    }

}
import java.io.IOException;
导入java.io.InputStream;
导入java.lang.annotation.annotation;
导入java.lang.reflect.Type;
导入java.net.URL;
导入javax.ws.rs.Consumes;
导入javax.ws.rs.WebApplicationException;
导入javax.ws.rs.core.Context;
导入javax.ws.rs.core.MediaType;
导入javax.ws.rs.core.MultivaluedMap;
导入javax.ws.rs.ext.ContextResolver;
导入javax.ws.rs.ext.MessageBodyReader;
导入javax.ws.rs.ext.Provider;
导入javax.ws.rs.ext.Providers;
导入javax.xml.xmlstants;
导入javax.xml.bind.JAXBContext;
导入javax.xml.bind.JAXBException;
导入javax.xml.bind.Unmarshaller;
导入javax.xml.validation.Schema;
导入javax.xml.validation.SchemaFactory;
@提供者
@使用(“应用程序/xml”)
公共类ValidatingReader实现MessageBodyReader{
@上下文
受保护的提供者;
私有模式;
公共验证阅读器(){
试一试{
SchemaFactory sf=SchemaFactory.newInstance(xmlstants.W3C\u XML\u SCHEMA\u NS\u URI);
URL schemaURL=null;
schema=sf.newSchema(schemaURL);
}捕获(例外e){
抛出新的运行时异常(e);
}
}
公共布尔值可读取(类arg0,类型arg1,注释[]arg2,媒体类型arg3){
返回arg0==Customer.class;
}
公共客户读取自(类arg0,类型arg1,注释[]arg2,媒体类型arg3,多值映射arg4,输入流arg5)
抛出IOException、WebApplicationException{
试一试{
JAXBContext JAXBContext=null;
ContextResolver解析器=providers.getContextResolver(JAXBContext.class,arg3);
if(null!=解析程序){
jaxbContext=resolver.getContext(arg0);
}
if(null==jaxbContext){
jaxbContext=jaxbContext.newInstance(arg0);
}
Unmarshaller Unmarshaller=jaxbContext.createUnmarshaller();
解组器。设置模式(模式);
返回(客户)解组器。解组器(arg5);
}捕获(JAXBEException e){
抛出新的运行时异常(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<T> implements
    MessageBodyReader<T> {

@Context
protected Providers providers;

@SuppressWarnings("unchecked")
@Override
public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2,
        MediaType arg3) {

    Class<T> readableClass = (Class<T>) ((ParameterizedType) getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0];
    return arg0 == readableClass;
}

@SuppressWarnings("unchecked")
@Override
public T readFrom(Class<T> arg0, Type arg1, Annotation[] arg2,
        MediaType arg3, MultivaluedMap<String, String> arg4,
        InputStream arg5) throws IOException, WebApplicationException {

    T type = null;
    JAXBContext jaxbContext = null;
    ContextResolver<JAXBContext> 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;
}
import java.io.IOException;
导入java.io.InputStream;
导入java.lang.annotation.annotation;
导入java.lang.reflect.ParameterizedType;
导入java.lang.reflect.Type;
导入javax.ws.rs.WebApplicationException;
导入javax.ws.rs.core.Context;
导入javax.ws.rs.core.MediaType;
导入javax.ws.rs.core.MultivaluedMap;
导入javax.ws.rs.core.Response;
导入javax.ws.rs.ext.ContextResolver;
导入javax.ws.rs.ext.MessageBodyReader;
导入javax.ws.rs.ext.Providers;
导入javax.xml.bind.JAXBContext;
导入javax.xml.bind.JAXBException;
公共抽象类AbstractValidatingReader实现
MessageBodyReader{
@上下文
受保护的提供者;
@抑制警告(“未选中”)
@凌驾
公共布尔值可读取(类arg0,类型arg1,注释[]arg2,
媒体类型(arg3){
类readableClass=(类)((参数化类型)getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
返回arg0==readableClass;
}
@抑制警告(“未选中”)
@凌驾
公共T readFrom(类arg0,类型arg1,注释[]arg2,
媒体类型arg3,多值映射arg4,
InputStream arg5)引发IOException、WebApplicationException{
T type=null;
JAXBContext JAXBContext=null;
ContextResolver解析器=提供程序。getContextResolver(
JAXBContext.class,arg3);
试一试{
if(解析器!=null){
jaxbContext=resolver.getContext(arg0);
}
if(jaxbContext==null){
jaxbContext=jaxbContext.newInstance(arg0);
}
type=(T)jaxbContext.createUnmarshaller().unmarshal(arg5);
验证(类型);
}捕获(JAXBEException e){
抛出新的WebApplicationException(
响应、状态、内部服务器错误);
}
返回类型;
}
受保护的抽象无效验证(T arg0)引发WebApplicationException;
}

重写validate方法并用@Provider注释子类,我们就完成了。

最后,我不需要根据架构进行验证,但如果我将来需要,这是一个很好的参考信息。您好,谢谢。你能在这里回答一个相关的问题吗:我一定错过了什么-这个类实际上没有做任何验证吗?@Deejay这是很久以前的事了,我甚至不再在同一个地方工作了。但实际上,抽象类不进行验证。它只创建类型,并在子类中完成验证。显然现在来看,我可以想象调整抽象超类来设置模式,并使用它进行解组。这完全取决于你的需要。