2017-06-25 3 views
2

Ich hatte eine RESTFUL-API für ein bestimmtes Objekt erstellt und javax.validation.Constraints für die Validierung verwendet, wenn ich die App wie erwartet ausgeführt und ExceptionMapper Klasse wurde ordnungsgemäß ausgeführt, aber wenn ich versuche, Tests mit zu automatisieren JerseyFramework der ExceptionMapper wird nicht ausgeführt oder bearbeitet. Es funktioniert also in der App, aber nicht, wenn ich es teste.ExceptionMapper funktioniert nicht in JerseyTest Framework

Hauptklasse, die App

package com.carlos.zerga.server; 
public class App { 
    public static void main(String[] args) throws Exception { 

     AppResourceConfig config = new AppResourceConfig(); 
     ServletHolder jerseyServlet 
       = new ServletHolder(new ServletContainer(config)); 

     Server server = new Server(8081); 
     ServletContextHandler context 
       = new ServletContextHandler(server, "/"); 

     context.addServlet(jerseyServlet, "/*"); 

     server.start(); 
     server.join(); 
    } 
} 

ResourceConfig für App

package com.carlos.zerga.server; 
public class AppResourceConfig extends ResourceConfig{ 

    public AppResourceConfig() { 
     register(new PropertiesBinder()); 
     register(EntityValidationExceptionMapper.class); 
     packages(true,"com.carlos.zerga.properties"); 
    } 
} 
starten

ExceptionMapper für ValidationExceptions

package com.carlos.zerga.properties.presentation.handler; 
@Provider 
public class EntityValidationExceptionMapper implements  
ExceptionMapper<BeanValidationException> { 

    public Response toResponse(BeanValidationException e) { 

     return Response.status(200). 
       type(MediaType.APPLICATION_JSON_TYPE). 
       entity(buildResponse((ConstraintViolationException) e.getInternalException())). 
       build(); 
    } 
    private ExceptionResponse buildResponse(ConstraintViolationException e) 
    { 
     ArrayList<String> messages = new ArrayList<String>(); 
     for(ConstraintViolation constraintViolation:e.getConstraintViolations()) 
     { 
      messages.add(constraintViolation.getMessage()); 
     } 
     return new ExceptionResponse(200, messages,e.getClass().getSimpleName()); 
    } 

} 

Resouce Klasse

package com.carlos.zerga.properties.presentation; 
@Path("property") 
public class PropertiesApiResource { 

    @POST 
    @Path("new") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public Property createProperty(Property property) 
    { 
     return property; 
    } 
    //LOT OF OTHER ROUTES 
    ...... 
} 

Test Case

package com.carlos.zerga.test.properties.presentation; 

@RunWith(DataProviderRunner.class) 
public class PropertiesApiResourceTest extends JerseyTest { 

    @Override 
    protected Application configure() { 

     return new ResourceConfig() 
      .register(new PropertiesBinder()) 
      .register(new EntityValidationExceptionMapper()) 
      .register(new ConstraintValidationException()) 
      .packages(true,"com.carlos.zerga.properties"); 
    } 
    //Here comes the error 
    @Test 
    @UseDataProvider("provideInvalidPropertiesPSR_PA") 
    public void testInValidPropertyCreation(Property property) 
    { 
     Response response=target("property/new").request(MediaType.APPLICATION_JSON).method("POST",Entity.json(property)); 
     assertEquals(response.getMediaType(),MediaType.APPLICATION_JSON_TYPE); 
     String exceptionResponse=response.readEntity(String.class); 
     System.out.print(exceptionResponse); 
    } 

pom.xml

<dependency> 
     <groupId>javax.servlet</groupId> 
     <artifactId>javax.servlet-api</artifactId> 
     <version>3.1.0</version> 
    </dependency> 

    <dependency> 
     <groupId>org.glassfish.jersey.core</groupId> 
     <artifactId>jersey-server</artifactId> 
     <version>${jersey.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.glassfish.jersey.containers</groupId> 
     <artifactId>jersey-container-servlet-core</artifactId> 
     <version>${jersey.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.eclipse.jetty</groupId> 
     <artifactId>jetty-server</artifactId> 
     <version>${jetty.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.eclipse.jetty</groupId> 
     <artifactId>jetty-servlet</artifactId> 
     <version>${jetty.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>org.glassfish.jersey.media</groupId> 
     <artifactId>jersey-media-moxy</artifactId> 
     <version>${jersey.version}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.glassfish.hk2</groupId> 
     <artifactId>hk2-metadata-generator</artifactId> 
     <version>2.4.0</version> 
    </dependency> 
    <dependency> 
     <groupId>com.tngtech.java</groupId> 
     <artifactId>junit-dataprovider</artifactId> 
     <version>1.12.0</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>junit</groupId> 
     <artifactId>junit</artifactId> 
     <version>4.12</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.glassfish.jersey.test-framework</groupId> 
     <artifactId>jersey-test-framework-core</artifactId> 
     <version>${jersey.version}</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
     <artifactId>jersey-test-framework-provider-jetty</artifactId> 
     <version>${jersey.version}</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.glassfish.jersey.ext</groupId> 
     <artifactId>jersey-bean-validation</artifactId> 
     <version>${jersey.version}</version> 
    </dependency> 
    <dependency> 
     <groupId>org.glassfish.jersey.connectors</groupId> 
     <artifactId>jersey-jetty-connector</artifactId> 
     <version>${jersey.version}</version> 
     <scope>test</scope> 
    </dependency> 


</dependencies> 
<properties> 
    <jersey.version>2.26-b03</jersey.version> 
    <jetty.version>9.2.14.v20151106</jetty.version> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
</properties> 

Als ich von Postbote schicken es gibt mir, was ich will:

{"errorCode":200,"errors":["Bathroom : Amount bathrooms can't be empty"],"errorDescription":"ConstraintViolationException"} 

Aber wenn ich die Tests gibt mir laufen:

javax.ws.rs.ProcessingException: 
    Exception Description: Constraints violated on marshalled bean: 
    [email protected] 
    -->Violated constraint on property bathRooms: "Bathroom : Minimun amout of bathrooms is 3". 
    -->Violated constraint on property bedRooms: "Bathroom : Minimun amout of bathrooms is 3". 
    Internal Exception: javax.validation.ConstraintViolationException 

    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:262) 
    at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:759) 
    at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:756) 
    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:407) 
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:756) 
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:443) 
    at com.carlos.zerga.test.properties.presentation.PropertiesApiResourceTest.testInValidPropertyCreation(PropertiesApiResourceTest.java:93) 
    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 com.tngtech.java.junit.dataprovider.DataProviderFrameworkMethod.invokeExplosively(DataProviderFrameworkMethod.java:77) 
    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:68) 
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 
    Caused by: Exception [EclipseLink-7510] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.BeanValidationException 
    Exception Description: Constraints violated on marshalled bean: 
    [email protected] 
    -->Violated constraint on property bathRooms: "Bathroom : Minimun amout of bathrooms is 3". 
    -->Violated constraint on property bedRooms: "Bathroom : Minimun amout of bathrooms is 3". 
    Internal Exception: javax.validation.ConstraintViolationException 
    at org.eclipse.persistence.exceptions.BeanValidationException.constraintViolation(BeanValidationException.java:53) 
    at org.eclipse.persistence.jaxb.JAXBBeanValidator.buildConstraintViolationException(JAXBBeanValidator.java:391) 
    at org.eclipse.persistence.jaxb.JAXBBeanValidator.validate(JAXBBeanValidator.java:275) 
    at org.eclipse.persistence.jaxb.JAXBMarshaller.validateAndTransformIfNeeded(JAXBMarshaller.java:604) 
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:494) 
    at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.writeTo(MOXyJsonProvider.java:957) 
    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:1126) 
    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:393) 
    at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285) 
    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:253) 
    ... 34 more 
    Caused by: javax.validation.ConstraintViolationException 
    at org.eclipse.persistence.jaxb.JAXBBeanValidator.buildConstraintViolationException(JAXBBeanValidator.java:389) 
    ... 47 more 

Antwort

1

Wenn Sie sorgfältig auf die Stacktrace anschauen, werden Sie sehen, dass Dieser Fehler tritt tatsächlich auf der Clientseite auf, noch bevor die Anforderung an den Server gelangt. Der Grund dafür ist, dass Sie MOXy verwenden, das JAXB verwendet, und die JAXB-Bean-Validierung standardmäßig aktiviert ist. Sie können im Stacktrace sehen, dass der JAXBBeanValidator aufgerufen wird, und dass dies auf dem Client-Marshalling der Entität geschieht.

Es gibt ein paar Lösungen:

  • konfigurieren moxy bean Validierung
  • deaktivieren nicht moxy

konfigurieren moxy Verwenden Sie bean Validierung

So konfigurieren deaktivieren MOXy, können Sie eine MoxyJsonConfig verwenden. Sie sollten dies auch auf der Serverseite tun, damit Sie keine doppelte Validierung auf dem Server erhalten. Die Bean-Validierung von Jersey unterscheidet sich von MOXy.

In Test.java

@Override 
public void configureClient(ClientConfig config) { 
    config.register(new MoxyJsonConfig().setFormattedOutput(true) 
      .property(MarshallerProperties.BEAN_VALIDATION_MODE, BeanValidationMode.NONE) 
      .resolver()); 
} 

Die configureClient ist ein Verfahren, bei dem JerseyTest, dass Sie die Client konfigurieren überschreiben können. Sie können das gleiche MoxyJsonConfig mit dem ResourceConfig auch für die Serverseite registrieren.

Sie moxy nicht

Meine Lösung von moxy zu bekommen wäre benutzen Sie einfach los, und Jackson stattdessen verwenden. Nur die folgende Abhängigkeit auf den Jackson ändern darunter

<!-- remove this --> 
<dependency> 
    <groupId>org.glassfish.jersey.media</groupId> 
    <artifactId>jersey-media-moxy</artifactId> 
    <version>${jersey.version}</version> 
</dependency> 
<!-- use this --> 
<dependency> 
    <groupId>org.glassfish.jersey.media</groupId> 
    <artifactId>jersey-media-json-jackson</artifactId> 
    <version>${jersey.version}</version> 
</dependency> 

Und auch @Valid Tag hinzuzufügen:

Resource.java

...... MORE ROUTES 
@POST 
@Path("new") 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
public Property createProperty(@Valid Property property){ 
    return property; 
} 
...... MORE ROUTES 

Sie werden nicht habe dieses Problem mit Jackson, da Jackson keine Bean-Validierung durchführt. Abgesehen von diesem Problem ist meine persönliche Meinung, dass Jackson sowieso eine viel bessere Gesamtbibliothek für JSON ist.

Hinweis: Wenn Sie die moxy Validierung (entweder durch Konfiguration oder von Jackson verwenden) deaktivieren, die Sie nicht mehr würden versuchen, ein BeanValidationException zu fangen Klasse (die eine moxy ist), sondern stattdessen direkt ConstraintViolationException fangen .

Verwandte Themen