#rest #jersey #jax-rs #grizzly #jersey-test-framework
#rest #джерси #jax-rs #grizzly #jersey-test-framework
Вопрос:
Я использую версию Jersey 2.23.2 и не могу понять, как использовать JerseyTest
для проверки ответов, когда проверка завершается неудачно. По какой-то причине приведенный ниже тест выдает a ConstraintViolationException
, который завернут в a ProcessingException
вместо возврата 400
неверного запроса. Я мог бы изменить тест, чтобы проверить, что ProcessingException
выбрасывается, но я действительно хочу проверить ответ. Когда я запускаю HelloResource
Grizzly без JerseyTest
, я получаю соответствующий 400
ответ на неверный запрос. Есть идеи о том, как исправить 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
Комментарии:
1. Я не могу воспроизвести проблему. Тест завершается неудачей, да, но только потому, что вы забыли
@Valid
аннотацию к параметру метода. Таким образом, вы получаете 200, когда ожидаете 400. Кроме этого, тест работает. Я использую Jersey 2.23. Какую версию вы используете?2. Я обновил сообщение, включив в него более подробную информацию. Я использую Jersey 2.23.2. Вы правы, что я забыл
@Valid
аннотацию (хороший улов!). Тем не менее, я добавил его в свой тест и все еще сталкиваюсь с той же проблемой. Я также добавил копию исключения в сообщение.3. Похоже на ошибку на стороне клиента, а не сервера. Запрос даже не выполняется. Это будет работать, если вы не используете компонент. Просто используйте строку.
Entity.json(new ObjectMapper().writeValueAsString(new Hello(null)));
4. Возможно, messagebodywriter имеет какое-то отношение к проверке. Однако я не смог воспроизвести эту ошибку. Возможно, конфигурация моего проекта была немного другой
5. Похоже, у MOXy по умолчанию включена проверка. Итак, он правильно генерирует исключение для клиента, поскольку JSON, который я пытаюсь создать, не проверяется. Добавив этот метод в тест, я могу отключить проверку:
@Override protected void configureClient(final ClientConfig config) { super.configureClient(config); config.register(new MoxyJsonConfig() .property(MarshallerProperties.BEAN_VALIDATION_MODE, BeanValidationMode.NONE) .resolver()); }
Ответ №1:
Это проблема на стороне клиента. Как вы обнаружили, у MOXy по умолчанию включена проверка компонента. Итак, вы получаете проверку компонента на клиенте. Таким образом, запрос даже не выполняется, поскольку ошибка возникает на клиенте. Вы можете проверить это, просто отправив строку
Entity.json("{}")
Это должно устранить ошибку. Но если вы хотите использовать компонент, как вы упомянули в комментарии, вам следует отключить проверку компонента на клиенте с помощью MOXy
@Override
protected void configureClient(final ClientConfig config) {
super.configureClient(config);
config.register(new MoxyJsonConfig()
.property(MarshallerProperties.BEAN_VALIDATION_MODE,
BeanValidationMode.NONE).resolver());
}