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

LaR*_*RRy 5 java jax-rs jaxb

我正在研究在 JAXB 编组中使用 BigDecimal

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

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

我的端点是这样的:

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

    @POST
    @Path("something")
    public Response postSomething(JaxbAnnotatedRequest request) {
        //processing....
    }
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*tha 5

我没有看到任何真正优雅的方法来处理这个问题。但要回答你的问题

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

解组将在 a 中完成MessageBodyReader。应ValidationEventHandler使用Unmarshaller为每个请求创建的 进行注册。因此,我们需要以某种方式利用当前使用的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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

是在方法中ValidationEventHandler设置的。UnmarshallerreadFrom

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