rest - 为什么 JerseyTest 抛出 ConstraintViolationException 而不是返回 400 Bad Request?

标签 rest jersey jax-rs grizzly jersey-test-framework

我正在使用 Jersey 2.23.2 版,但我无法弄清楚如何使用 JerseyTest 来测试验证失败时的响应。出于某种原因,下面的测试抛出一个 ConstraintViolationException,它被包裹在一个 ProcessingException 中,而不是返回 400 错误请求。我可以修改测试以检查是否抛出了 ProcessingException,但我真的想测试响应。当我在没有 JerseyTest 的情况下在 Grizzly 中运行 HelloResource 时,我得到了相应的 400 Bad Request 响应。关于如何修复下面的 badRequestResponse() 测试有什么想法吗?

package example;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

import static org.junit.Assert.assertEquals;

public class BadRequestTest extends JerseyTest {
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Hello {
        @NotNull(message = "Name is a required field.")
        private final String name;

        private Hello() {
            this(null);
        }

        public Hello(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    @Path("hello")
    public static class HelloResource {
        @POST
        public String sayHelloToMe(@Valid Hello hello) {
            return "Hello " + hello.getName() + "!";
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloResource.class).property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    }

    /** Test OK Response. This Works!*/
    @Test
    public void okResponse() {
        Response response = target("hello")
                .request(MediaType.TEXT_PLAIN)
                .post(Entity.json(new Hello("Tiny Tim")));

        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
        assertEquals("Hello Tiny Tim!", response.readEntity(String.class));
    }

    /** Test Bad Request Response.  This Fails! */
    @Test
    public void badRequestResponse() {
        Response response = target("hello")
                .request(MediaType.TEXT_PLAIN)
                .post(Entity.json(new Hello(null)));

        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus());
    }
}

这是我遇到的异常:

javax.ws.rs.ProcessingException: 
Exception Description: Constraints violated on marshalled bean:
example.BadRequestTest$Hello@456abb66
-->Violated constraint on property name: "Name is a required field.".
Internal Exception: javax.validation.ConstraintViolationException

    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:261)
    at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
    at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:343)
    at example.BadRequestTest.badRequestResponse(BadRequestTest.java:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: Exception [EclipseLink-7510] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.BeanValidationException
Exception Description: Constraints violated on marshalled bean:
example.BadRequestTest$Hello@456abb66
-->Violated constraint on property name: "Name is a required field.".
Internal Exception: javax.validation.ConstraintViolationException
    at org.eclipse.persistence.exceptions.BeanValidationException.constraintViolation(BeanValidationException.java:53)
    at org.eclipse.persistence.jaxb.JAXBBeanValidator.buildConstraintViolationException(JAXBBeanValidator.java:385)
    at org.eclipse.persistence.jaxb.JAXBBeanValidator.validate(JAXBBeanValidator.java:273)
    at org.eclipse.persistence.jaxb.JAXBMarshaller.validateAndTransformIfNeeded(JAXBMarshaller.java:588)
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:481)
    at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.writeTo(MOXyJsonProvider.java:949)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:265)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:250)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1130)
    at org.glassfish.jersey.client.ClientRequest.doWriteEntity(ClientRequest.java:517)
    at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:499)
    at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:388)
    at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:252)
    ... 39 more
Caused by: javax.validation.ConstraintViolationException
    at org.eclipse.persistence.jaxb.JAXBBeanValidator.buildConstraintViolationException(JAXBBeanValidator.java:383)
    ... 52 more

最佳答案

这是一个客户端问题。正如您所发现的,MOXy 默认启用了 bean 验证。所以你正在客户端上进行 bean 验证。因此,由于客户端发生错误,请求甚至没有通过。你可以通过发送一个字符串来测试这个

Entity.json("{}")

这应该可以消除错误。但是如果你想使用这个 bean,正如你在评论中提到的,你应该使用 MOXy 在客户端上禁用 bean 验证

@Override 
protected void configureClient(final ClientConfig config) {  
    super.configureClient(config);
    config.register(new MoxyJsonConfig() 
            .property(MarshallerProperties.BEAN_VALIDATION_MODE,
                      BeanValidationMode.NONE).resolver());
}

关于rest - 为什么 JerseyTest 抛出 ConstraintViolationException 而不是返回 400 Bad Request?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40094341/

相关文章:

java - CXF Rest 服务的 Jersey 客户端问题

json - Jersey 2.0 和 Moxy 内部服务器错误但没有服务器日志

java - 使用 javax.ws.rs api 执行不带返回类型的查询

swift - 在 Swift 中使用参数获取

java - 使用 Jersey Client 将输出流获取到请求主体?

javascript - 交互式测试 RESTful 服务的最简单方法?

servlets - 过滤静态内容 Jersey

oracle - 如何使用 Oracle Rest 数据服务发布 JSON

json - Spring 靴泽西 jackson

java - 在同一方法上使用 Jax-Rs @Get @Post