Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何向使用XmlAdapter的JAXB注释类注册处理程序,以便向REST资源客户端发送错误消息?_Java_Jaxb_Jax Rs - Fatal编程技术网

Java 如何向使用XmlAdapter的JAXB注释类注册处理程序,以便向REST资源客户端发送错误消息?

Java 如何向使用XmlAdapter的JAXB注释类注册处理程序,以便向REST资源客户端发送错误消息?,java,jaxb,jax-rs,Java,Jaxb,Jax Rs,我在调查 默认情况下,会抛出异常,但没有处理程序在侦听它。结果,这样的请求到达JAR-RS方法,但提交的thad字段值“不正确”,设置为NULL 我在JAVADOC中读到,必须设置一个处理程序,以便在这种情况发生时可以做一些事情。但我找不到有关如何设置此类处理程序的信息 我的端点类似于: @Path("/path") public class MyResource { @POST @Path("something") public Response postSometh

我在调查

默认情况下,会抛出异常,但没有处理程序在侦听它。结果,这样的请求到达JAR-RS方法,但提交的thad字段值“不正确”,设置为NULL

我在JAVADOC中读到,必须设置一个处理程序,以便在这种情况发生时可以做一些事情。但我找不到有关如何设置此类处理程序的信息

我的端点类似于:

@Path("/path")
public class MyResource {

    @POST
    @Path("something")
    public Response postSomething(JaxbAnnotatedRequest request) {
        //processing....
    }
}

我看不出有什么真正优雅的方式来处理这件事。但要回答你的问题

“我在中读到,必须设置处理程序,以便在发生这种情况时可以执行某些操作。但我找不到有关如何设置此类处理程序的信息。”

解组将在一段时间内完成。应向注册,该注册是为每个请求创建的。因此,我们需要以某种方式利用当前使用的
MessageBodyReader
,我不确定该怎么做,或者以这种方式添加处理程序是否是可配置的。如果是,我相信它是特定于实现的

一种方法是编写自己的
MessageBodyReader
来处理此特定类型。比如说

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Consumes;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;

@Provider
@Consumes(MediaType.APPLICATION_XML)
public class JaxbAnnotatedRequestMessageBodyReader
        implements MessageBodyReader<JaxbAnnotatedRequest> {

    JAXBContext context;

    public JaxbAnnotatedRequestMessageBodyReader() {
        try {
            context = JAXBContext.newInstance(JaxbAnnotatedRequest.class);
        } catch (JAXBException ex) {
            throw new InternalServerErrorException();
        }
    }

    @Override
    public boolean isReadable(Class<?> type, Type type1,
            Annotation[] antns, MediaType mt) {
        return JaxbAnnotatedRequest.class == type;
    }

    @Override
    public JaxbAnnotatedRequest readFrom(Class<JaxbAnnotatedRequest> type, Type type1,
            Annotation[] antns, MediaType mt, MultivaluedMap<String, String> mm,
            InputStream in) throws IOException, WebApplicationException {

        try {
            Unmarshaller unmarshaller = context.createUnmarshaller();
            unmarshaller.setEventHandler(new ValidationEventHandler() {

                @Override
                public boolean handleEvent(ValidationEvent event) {
                    String nfe = NumberFormatException.class.getCanonicalName();
                    if (nfe.equals(event.getMessage())) {
                        throw new WebApplicationException(Response.status(400)
                                .entity("Bad Number Formatting").build());
                    }
                    System.out.println(event.getMessage());
                    return false;
                }

            });
            JaxbAnnotatedRequest request
                    = (JaxbAnnotatedRequest) unmarshaller.unmarshal(in);
            return request;

        } catch (JAXBException ex) {
            throw new WebApplicationException(Response.status(400).entity(
                    "Caught JAXBEception: " + ex.toString()).build());
        }
    }
}
import java.io.IOException;
导入java.io.InputStream;
导入java.lang.annotation.annotation;
导入java.lang.reflect.Type;
导入javax.ws.rs.Consumes;
导入javax.ws.rs.InternalServerErrorException;
导入javax.ws.rs.WebApplicationException;
导入javax.ws.rs.core.MediaType;
导入javax.ws.rs.core.MultivaluedMap;
导入javax.ws.rs.core.Response;
导入javax.ws.rs.ext.MessageBodyReader;
导入javax.ws.rs.ext.Provider;
导入javax.xml.bind.JAXBContext;
导入javax.xml.bind.JAXBException;
导入javax.xml.bind.Unmarshaller;
导入javax.xml.bind.ValidationEvent;
导入javax.xml.bind.ValidationEventHandler;
@提供者
@使用(MediaType.APPLICATION_XML)
公共类JaxbAnnotatedRequestMessageBodyReader
实现MessageBodyReader{
JAXBContext上下文;
public JaxbAnnotatedRequestMessageBodyReader(){
试一试{
context=JAXBContext.newInstance(JaxbAnnotatedRequest.class);
}捕获(JAXBEException-ex){
抛出新的InternalServerErrorException();
}
}
@凌驾
公共布尔值可读取(类类型,类型1,
注释[]ANTS,MediaType mt){
返回JaxbAnnotatedRequest.class==type;
}
@凌驾
公共JAXBannotatedRequestReadFrom(类类型,类型1,
注释[]antns,MediaType mt,多值地图mm,
InputStream in)引发IOException、WebApplicationException{
试一试{
Unmarshaller Unmarshaller=context.createUnmarshaller();
unmarshaller.setEventHandler(新的ValidationEventHandler(){
@凌驾
公共布尔handleEvent(ValidationEvent事件){
字符串nfe=NumberFormatException.class.getCanonicalName();
if(nfe.equals(event.getMessage())){
抛出新的WebApplicationException(Response.status(400)
.entity(“错误的数字格式”).build();
}
System.out.println(event.getMessage());
返回false;
}
});
JaxbAnnotatedRequest请求
=(JaxbAnnotatedRequest)解组器。解组器(in);
返回请求;
}捕获(JAXBEException-ex){
抛出新的WebApplicationException(Response.status(400.entity(
捕获JAXBEception:“+ex.toString()).build());
}
}
}
ValidationEventHandler
是在
readFrom
方法中的
Unmarshaller
上设置的


另一个选项(尽管也有限制)是使用,这是JAX-RS 2.0规范的一部分。如果您想使用此功能,您可能需要查看实现的文档。唯一的问题是假设您要使用
@NotNull
注释,您将知道请求值是否实际为null,或者JAXB是否将其设置为null,因此您需要发送一些通用消息。

在我看来,您遇到的问题是验证问题。如今,输入验证是开发人员不可避免的责任。对于JSON或XML之类的数据文件,这可以通过使用
模式验证
轻松完成。此验证需要集成到数据转换过程中,建议在编组和解编组中使用。如果出现
null
值或任何其他不适当的输入,如to short post code等,则会抛出
jaxbeexception
,然后将其包装成更具表现力的异常。最后,您必须声明一个
ExceptionMapper
,它将捕获异常并向调用者发送相应的消息。下面是一个例子


实体类地址.java

@XmlRootElement(name = "address", namespace = DataEntity.NSP)
public class Address implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 2508433924387468026L;

    private Integer id;
    private String street;
    private String number;
    private Short zipCode;
    private String city;

    protected Address() {

    }

    public Address(final Integer id, final String street, final String number,
            final Short zipCode, final String city) {
        setId(id);
        setStreet(street);
        setNumber(number);
        setZipCode(zipCode);
        setCity(city);
    }

    @XmlAttribute
    public Integer getId() {
        return id;
    }

    private void setId(Integer id) {
        ValidationHelper.validateId(id);

        this.id = id;
    }

    @XmlElement(namespace = DataEntity.NSP)
    public String getStreet() {
        return street;
    }

    private void setStreet(String street) {
        ValidationHelper.validateAddressStreet(street);

        this.street = street;
    }

    @XmlElement(namespace = DataEntity.NSP)
    public String getNumber() {
        return number;
    }

    private void setNumber(String number) {
        ValidationHelper.validateAddressNumber(number);

        this.number = number;
    }

    @XmlElement(namespace = DataEntity.NSP)
    public Short getZipCode() {
        return zipCode;
    }

    private void setZipCode(Short zipCode) {
        ValidationHelper.validateAddressZipCode(zipCode);

        this.zipCode = zipCode;
    }

    @XmlElement(namespace = DataEntity.NSP)
    public String getCity() {
        return city;
    }

    private void setCity(String city) {
        ValidationHelper.validateAddressCity(city);

        this.city = city;
    }
}

架构验证文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns="https://localhost/JAX-RS_BookStore_Service/xsd/" targetNamespace="https://localhost/JAX-RS_BookStore_Service/xsd/"
    elementFormDefault="qualified" xmlns:pref="https://localhost/JAX-RS_BookStore_Service/xsd/">
    <xs:include schemaLocation="Types.xsd" />
    <xs:element name="address" type="addressType" />
</xs:schema>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns="https://localhost/JAX-RS_BookStore_Service/xsd/"
    targetNamespace="https://localhost/JAX-RS_BookStore_Service/xsd/"
    elementFormDefault="qualified" xmlns:pref="https://localhost/JAX-RS_BookStore_Service/xsd/">

    <xs:simpleType name="unsignedInteger">
        <xs:restriction base="xs:integer">
            <xs:minInclusive value="1" />
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="addressStreet">
        <xs:restriction base="xs:string">
            <xs:pattern value="[a-zA-ZöäüÖÄÜß -]{2,32}" />
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="addressNumber">
        <xs:restriction base="xs:string">
            <xs:pattern value="[0-9]{1}[0-9a-z/\\ -]{0,7}" />
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="addressCity">
        <xs:restriction base="xs:string">
            <xs:pattern value="[a-zA-ZöäüÖÄÜß -]{2,32}" />
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="zipCodeMoreThan4Digits">
        <xs:restriction base="xs:short">
            <xs:minInclusive value="1000"></xs:minInclusive>
            <xs:maxInclusive value="9999"></xs:maxInclusive>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="addressType">
        <xs:sequence>
            <xs:element name="city" type="addressCity" />
            <xs:element name="number" type="addressNumber" />
            <xs:element name="street" type="addressStreet" />
            <xs:element name="zipCode" type="zipCodeMoreThan4Digits" />
        </xs:sequence>
        <xs:attribute name="id" type="unsignedInteger" use="required">
        </xs:attribute>
    </xs:complexType>
</xs:schema>
concreate
MeassagBodyReader
实现,它提供特定的XSD文件。

    public abstract class AbstractXmlValidationReader<T> implements
        MessageBodyReader<T> {

    private final Providers providers;
    private final Schema schema;

    /**
     * Instantiates the XML validation class (MessageBodyReader)
     * 
     * @param providers
     * @param servletContext
     * @param xsdFileName
     */
    public AbstractXmlValidationReader(final Providers providers,
            final ServletContext servletContext, final String xsdFileName) {
        this.providers = providers;

        try {
            SchemaFactory sf = SchemaFactory
                    .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            File xsd = new File(servletContext.getRealPath(xsdFileName));
            schema = sf.newSchema(xsd);
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to create XSD validation schema", e);
        }
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {

        @SuppressWarnings("unchecked")
        Class<T> readableClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];

        if (type == readableClass
                && type.isAnnotationPresent(XmlRootElement.class)) {
            return true;
        }
        return false;
    }

    /**
     * Source adapted from: <a href=
     * "http://stackoverflow.com/questions/3428273/validate-jaxbelement-in-jpa-jax-rs-web-service"
     * >stackoverflow.com</a>
     */
    @Override
    public T readFrom(Class<T> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException, WebApplicationException {

        try {
            JAXBContext jaxbContext = null;
            ContextResolver<JAXBContext> resolver = providers
                    .getContextResolver(JAXBContext.class, mediaType);
            if (null != resolver) {
                jaxbContext = resolver.getContext(type);
            }
            if (null == jaxbContext) {
                jaxbContext = JAXBContext.newInstance(type);
            }
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            unmarshaller.setSchema(schema);

            @SuppressWarnings("unchecked")
            T entity = (T) unmarshaller.unmarshal(entityStream);
            return entity;
        } catch (JAXBException e) {
            throw new MessageBodyReaderValidationException(
                    "Failure while performing xml validation or xml marhalling!",
                    e);
        }
    }
}
@Provider
@Consumes(MediaType.APPLICATION_XML)
public class AddressXmlValidationReader extends
        AbstractXmlValidationReader<Address> {

    private final static String xsdFileName = "/xsd/Address.xsd";

    public AddressXmlValidationReader(@Context Providers providers,
            @Context ServletContext servletContext) {
        super(providers, servletContext, xsdFileName);
    }
}

使用Firefox RESTClient插件发出POST请求的结果。

请注意,
标记的内容为空,
NULL

@Provider
public class MessageBodyReaderValidationExceptionMapper implements
        ExceptionMapper<MessageBodyReaderValidationException> {

    @Override
    public Response toResponse(MessageBodyReaderValidationException e) {
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(e.getMessage()).type(MediaType.TEXT_PLAIN).build();
    }
}