resteasy-spring-boot
resteasy-spring-boot copied to clipboard
The RESTeasy validation doesn't work with packaging war
Hi,
i found out some problem with this module. The RESTeasy validation doesn't work. This happens in case if we use resteasy-spring-boot in web-application (packaging war):
What we make?
- we use the sample-app
- we change to use the war ->(
war ) - deploy on tomcat
- added to the @NotEmpty > public EchoMessage echo(@NotEmpty String echoText) {
- send request with empty body and we receive the 200, but should be a 400.
If we do the same with jar it work and we receive 400.
Can you us help and say, how we can solve this problem?
Could you please share in GitHub a modified version of sample-app with bean validations that work as JAR and a modified version of sample-app with bean validations that does NOT work as WAR? Thanks.
Hi, this the sampe-app like attachment:
Case Spring-Boot standalone
This the logs if I start like standalone:
Server: 20:40:24.121 [localhost-startStop-1] INFO org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@19be589f: startup date [Thu Jul 27 20:40:24 CEST 2017]; root of context hierarchy 20:40:24.251 [background-preinit] INFO org.hibernate.validator.internal.util.Version HV000001: Hibernate Validator 5.3.5.Final 20:40:25.163 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer Finding JAX-RS Application classes 20:40:25.165 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer Property resteasy.jaxrs.app.registration has been set to property 20:40:25.165 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer Property resteasy.jaxrs.app.classes has been set to com.sample.app.JaxrsApplication 20:40:25.165 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer JAX-RS Application class found: com.sample.app.JaxrsApplication 20:40:25.377 [localhost-startStop-1] INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/] Initializing Spring embedded WebApplicationContext 20:40:25.377 [localhost-startStop-1] INFO org.springframework.web.context.ContextLoader Root WebApplicationContext: initialization completed in 1256 ms 20:40:25.823 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean Mapping servlet: 'dispatcherServlet' to [/] 20:40:25.823 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean Mapping servlet: 'com.sample.app.JaxrsApplication' to [/sample-app/*]
An this the logs for Client to standalone Spring-Boot:
[27-07 20:58:54.970][main] D o.a.h.wire:72 - >> "POST /sample-app/echo HTTP/1.1[\r][\n]" [27-07 20:58:54.971][main] D o.a.h.wire:72 - >> "Content-Type: text/plain;charset=UTF-8[\r][\n]" [27-07 20:58:54.971][main] D o.a.h.wire:72 - >> "Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==[\r][\n]" [27-07 20:58:54.971][main] D o.a.h.wire:72 - >> "Accept: application/json[\r][\n]" [27-07 20:58:54.971][main] D o.a.h.wire:72 - >> "Accept-Encoding: gzip, deflate[\r][\n]" [27-07 20:58:54.972][main] D o.a.h.wire:72 - >> "X-REQUEST-ID: ccbdbbde-5b9d-4e3e-879a-19fb6d8df19b[\r][\n]" [27-07 20:58:54.972][main] D o.a.h.wire:72 - >> "Content-Length: 0[\r][\n]" [27-07 20:58:54.972][main] D o.a.h.wire:72 - >> "Host: localhost:8080[\r][\n]" [27-07 20:58:54.972][main] D o.a.h.wire:72 - >> "Connection: Keep-Alive[\r][\n]" [27-07 20:58:54.973][main] D o.a.h.wire:72 - >> "User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_131)[\r][\n]" [27-07 20:58:54.973][main] D o.a.h.wire:72 - >> "[\r][\n]" [27-07 20:58:54.973][main] D o.a.h.headers:280 - >> POST /sample-app/echo HTTP/1.1 [27-07 20:58:54.973][main] D o.a.h.headers:283 - >> Content-Type: text/plain;charset=UTF-8 [27-07 20:58:54.973][main] D o.a.h.headers:283 - >> Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg== [27-07 20:58:54.974][main] D o.a.h.headers:283 - >> Accept: application/json [27-07 20:58:54.974][main] D o.a.h.headers:283 - >> Accept-Encoding: gzip, deflate [27-07 20:58:54.974][main] D o.a.h.headers:283 - >> X-REQUEST-ID: ccbdbbde-5b9d-4e3e-879a-19fb6d8df19b [27-07 20:58:54.974][main] D o.a.h.headers:283 - >> Content-Length: 0 [27-07 20:58:54.974][main] D o.a.h.headers:283 - >> Host: localhost:8080 [27-07 20:58:54.975][main] D o.a.h.headers:283 - >> Connection: Keep-Alive [27-07 20:58:54.975][main] D o.a.h.headers:283 - >> User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_131) [27-07 20:58:55.252][main] D o.a.h.wire:72 - << "HTTP/1.1 400 [\r][\n]" [27-07 20:58:55.254][main] D o.a.h.wire:72 - << "X-Application-Context: application[\r][\n]" [27-07 20:58:55.254][main] D o.a.h.wire:72 - << "validation-exception: true[\r][\n]" [27-07 20:58:55.255][main] D o.a.h.wire:72 - << "Content-Type: application/json[\r][\n]" [27-07 20:58:55.255][main] D o.a.h.wire:72 - << "Content-Length: 229[\r][\n]" [27-07 20:58:55.255][main] D o.a.h.wire:72 - << "Date: Thu, 27 Jul 2017 18:58:55 GMT[\r][\n]" [27-07 20:58:55.255][main] D o.a.h.wire:72 - << "Connection: close[\r][\n]" [27-07 20:58:55.256][main] D o.a.h.wire:72 - << "[\r][\n]" [27-07 20:58:55.256][main] D o.a.h.i.c.DefaultClientConnection:261 - Receiving response: HTTP/1.1 400 [27-07 20:58:55.257][main] D o.a.h.headers:264 - << HTTP/1.1 400 [27-07 20:58:55.257][main] D o.a.h.headers:267 - << X-Application-Context: application [27-07 20:58:55.257][main] D o.a.h.headers:267 - << validation-exception: true [27-07 20:58:55.257][main] D o.a.h.headers:267 - << Content-Type: application/json [27-07 20:58:55.258][main] D o.a.h.headers:267 - << Content-Length: 229 [27-07 20:58:55.258][main] D o.a.h.headers:267 - << Date: Thu, 27 Jul 2017 18:58:55 GMT [27-07 20:58:55.258][main] D o.a.h.headers:267 - << Connection: close [27-07 20:58:55.267][main] D o.a.h.wire:86 - << "{"exception":null,"fieldViolations":[],"propertyViolations":[],"classViolations":[],"parameterViolations":[{"constraintType":"PARAMETER","path":"echo.arg0","message":"darf nicht leer sein","value":""}],"returnValueViolations":[]}" [27-07 20:58:55.268][main] D o.a.h.i.c.DefaultClientConnection:182 - Connection 0.0.0.0:54337<->127.0.0.1:8080 closed [27-07 20:58:55.272][main] I c.u.p.c.h.UIHttpClient:66 - client error 400 occured by executing request Client-Info: [thread] Thread[main,5,main]
RequestHeader: POST /sample-app/echo HTTP/1.1 Host: localhost:8080 Content-Type: text/plain;charset=UTF-8 Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg== Accept: application/json Accept-Encoding: gzip, deflate X-REQUEST-ID: ccbdbbde-5b9d-4e3e-879a-19fb6d8df19b
Response: HTTP/1.1 400 X-Application-Context: application validation-exception: true Content-Type: application/json Content-Length: 229 Date: Thu, 27 Jul 2017 18:58:55 GMT Connection: close
{"exception":null,"fieldViolations":[],"propertyViolations":[],"classViolations":[],"parameterViolations":[{"constraintType":"PARAMETER","path":"echo.arg0","message":"darf nicht leer sein","value":""}],"returnValueViolations":[]}
Case Spirng-Boot web
This the logs if i starts like web:
21:03:06.148 [localhost-startStop-1] INFO org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@27df5aed: startup date [Thu Jul 27 21:03:06 CEST 2017]; root of context hierarchy 21:03:06.332 [background-preinit] INFO org.hibernate.validator.internal.util.Version HV000001: Hibernate Validator 5.3.5.Final 21:03:07.309 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer Finding JAX-RS Application classes 21:03:07.311 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer Property resteasy.jaxrs.app.registration has been set to property 21:03:07.312 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer Property resteasy.jaxrs.app.classes has been set to com.sample.app.JaxrsApplication 21:03:07.312 [localhost-startStop-1] INFO com.paypal.springboot.resteasy.ResteasyEmbeddedServletInitializer JAX-RS Application class found: com.sample.app.JaxrsApplication 21:03:07.555 [localhost-startStop-1] INFO org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/] Initializing Spring embedded WebApplicationContext 21:03:07.555 [localhost-startStop-1] INFO org.springframework.web.context.ContextLoader Root WebApplicationContext: initialization completed in 1408 ms 21:03:08.077 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean Mapping servlet: 'dispatcherServlet' to [/] 21:03:08.078 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean Mapping servlet: 'com.sample.app.JaxrsApplication' to [/sample-app/] 21:03:08.078 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.ServletRegistrationBean Servlet com.sample.app.JaxrsApplication was not registered (possibly already registered?) 21:03:08.078 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'errorPageFilter' to: [/] 21:03:08.078 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'metricsFilter' to: [/] 21:03:08.078 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'characterEncodingFilter' to: [/] 21:03:08.079 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'hiddenHttpMethodFilter' to: [/] 21:03:08.079 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'httpPutFormContentFilter' to: [/] 21:03:08.079 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'requestContextFilter' to: [/] 21:03:08.079 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'webRequestLoggingFilter' to: [/] 21:03:08.079 [localhost-startStop-1] INFO org.springframework.boot.web.servlet.FilterRegistrationBean Mapping filter: 'applicationContextIdFilter' to: [/*]
An this the logs for Client to standalone Spring-Boot:
[27-07 21:03:21.269][main] D o.a.h.i.c.DefaultClientConnection:276 - Sending request: POST /sample-app/echo HTTP/1.1 [27-07 21:03:21.269][main] D o.a.h.wire:72 - >> "POST /sample-app/echo HTTP/1.1[\r][\n]" [27-07 21:03:21.270][main] D o.a.h.wire:72 - >> "Content-Type: text/plain;charset=UTF-8[\r][\n]" [27-07 21:03:21.270][main] D o.a.h.wire:72 - >> "Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==[\r][\n]" [27-07 21:03:21.270][main] D o.a.h.wire:72 - >> "Accept: application/json[\r][\n]" [27-07 21:03:21.270][main] D o.a.h.wire:72 - >> "Accept-Encoding: gzip, deflate[\r][\n]" [27-07 21:03:21.271][main] D o.a.h.wire:72 - >> "X-REQUEST-ID: 98e3494a-7361-4db9-95d7-aa38eaea9654[\r][\n]" [27-07 21:03:21.271][main] D o.a.h.wire:72 - >> "Content-Length: 0[\r][\n]" [27-07 21:03:21.271][main] D o.a.h.wire:72 - >> "Host: localhost:8080[\r][\n]" [27-07 21:03:21.272][main] D o.a.h.wire:72 - >> "Connection: Keep-Alive[\r][\n]" [27-07 21:03:21.272][main] D o.a.h.wire:72 - >> "User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_131)[\r][\n]" [27-07 21:03:21.272][main] D o.a.h.wire:72 - >> "[\r][\n]" [27-07 21:03:21.272][main] D o.a.h.headers:280 - >> POST /sample-app/echo HTTP/1.1 [27-07 21:03:21.272][main] D o.a.h.headers:283 - >> Content-Type: text/plain;charset=UTF-8 [27-07 21:03:21.272][main] D o.a.h.headers:283 - >> Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg== [27-07 21:03:21.273][main] D o.a.h.headers:283 - >> Accept: application/json [27-07 21:03:21.273][main] D o.a.h.headers:283 - >> Accept-Encoding: gzip, deflate [27-07 21:03:21.273][main] D o.a.h.headers:283 - >> X-REQUEST-ID: 98e3494a-7361-4db9-95d7-aa38eaea9654 [27-07 21:03:21.273][main] D o.a.h.headers:283 - >> Content-Length: 0 [27-07 21:03:21.273][main] D o.a.h.headers:283 - >> Host: localhost:8080 [27-07 21:03:21.274][main] D o.a.h.headers:283 - >> Connection: Keep-Alive [27-07 21:03:21.274][main] D o.a.h.headers:283 - >> User-Agent: Apache-HttpClient/4.5.2 (Java/1.8.0_131) [27-07 21:03:21.383][main] D o.a.h.wire:72 - << "HTTP/1.1 200 OK[\r][\n]" [27-07 21:03:21.385][main] D o.a.h.wire:72 - << "Server: Apache-Coyote/1.1[\r][\n]" [27-07 21:03:21.385][main] D o.a.h.wire:72 - << "X-Application-Context: application[\r][\n]" [27-07 21:03:21.386][main] D o.a.h.wire:72 - << "Content-Type: application/json[\r][\n]" [27-07 21:03:21.386][main] D o.a.h.wire:72 - << "Transfer-Encoding: chunked[\r][\n]" [27-07 21:03:21.386][main] D o.a.h.wire:72 - << "Date: Thu, 27 Jul 2017 19:03:21 GMT[\r][\n]" [27-07 21:03:21.387][main] D o.a.h.wire:72 - << "[\r][\n]" [27-07 21:03:21.388][main] D o.a.h.i.c.DefaultClientConnection:261 - Receiving response: HTTP/1.1 200 OK [27-07 21:03:21.388][main] D o.a.h.headers:264 - << HTTP/1.1 200 OK [27-07 21:03:21.388][main] D o.a.h.headers:267 - << Server: Apache-Coyote/1.1 [27-07 21:03:21.388][main] D o.a.h.headers:267 - << X-Application-Context: application [27-07 21:03:21.388][main] D o.a.h.headers:267 - << Content-Type: application/json [27-07 21:03:21.389][main] D o.a.h.headers:267 - << Transfer-Encoding: chunked [27-07 21:03:21.389][main] D o.a.h.headers:267 - << Date: Thu, 27 Jul 2017 19:03:21 GMT [27-07 21:03:21.394][main] D o.a.h.i.c.DefaultHttpClient:511 - Connection can be kept alive indefinitely [27-07 21:03:21.442][main] D o.a.h.wire:72 - << "29[\r][\n]" [27-07 21:03:21.443][main] D o.a.h.wire:86 - << "{"timestamp":1501182201303,"echoText":""}" [27-07 21:03:21.443][main] D o.a.h.wire:72 - << "[\r][\n]" [27-07 21:03:21.443][main] D o.a.h.wire:72 - << "0[\r][\n]" [27-07 21:03:21.444][main] D o.a.h.wire:72 - << "[\r][\n]" [27-07 21:03:21.447][main] I c.u.p.m.c.r.l.EchoTest:50 - test id {"timestamp":1501182201303,"echoText":""} [27-07 21:03:21.449][main] D o.a.h.i.c.DefaultClientConnection:182 - Connection 0.0.0.0:54379<->127.0.0.1:8080 closed [27-07 21:03:21.450][main] D o.a.h.i.c.DefaultClientConnection:182 - Connection 0.0.0.0:54379<->127.0.0.1:8080 closed
end here should be a 400, but not we receive 200 regards
Hi,
i think, that the problem is, that standalone spring boot find this dependencies:
"Web spring boot" means that runs on tomcat (or other servlet container)? I made some changes on your project; execute using: sample-app-gradle.zip
$ gradle clean build $ java -jar .\build\libs\sample-app.war
POST /sample-app/echo HTTP/1.1
HOST: localhost:8080
content-length: 0
content-type: text/plain
Response 404
Hey @miguelsauza ,
What @avaysberg means by "web spring boot" is when you build your Spring Boot app as WAR and deploy it to a regular standalone servlet container, instead of running it as a Spring Boot micro-service out of its executable jar (with the container embedded to it).[
Running Spring Boot apps as WARs is documented in Spring Boot document.
Hello @avaysberg ,
Thanks for sharing a modified version of sample-app with bean validations. Based on that, I added Bean Validations to the starter sample-app and also to its integration tests (see #75). Everything is working as expected.
When it comes to a WAR version of sample-app, I assume everything works as expected as well, although I haven't tested it. I noticed that you didn't share your modified version of sample-app with bean validations as a WAR deployment. Could you share it please? Then I can test it and make sure I see the exact same behavior you are seeing. Also, make sure you follow the document below properly.
Running Spring Boot apps as WARs is documented in Spring Boot document.
I have just tested myself a WAR version of sample-app and I got the same wrong result you did, a 200 instead of a 400. I can see though resteasy-validator-provider-11 and hibernate-validator in the WEB-INF/lib folder, so I am not really sure yet what the root cause is.
This seems to be a legit bug. I have found out that the GeneralValidator implementation is not available for RESTEasy as a context resolver (resolver here should not be null, but in case of WAR deployments, it is).
I will do more investigation on it when I have time and figure out the root cause.
Feel free to investigate yourself and share your findings, or even send a PR, if you reach a solution.
Hi, so, make it working for both cases. I prepare this configuration object and prepare the ValidatorContextResolver:
package com.sample.app;
import org.jboss.resteasy.plugins.validation.ValidatorContextResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ApplicationConfiguration {
@Bean
public ValidatorContextResolver validatorContextResolver() {
return new ValidatorContextResolver();
}
}
Thank you for your help. I think, you can simple look for this class and if this not exist in class path than not create this bean for RESTEasy initialisation.
Today I spent some time and found out, that the classes with @Provider not load, but ValidatorContextResolver is annotated:
@Provider public class ValidatorContextResolver extends AbstractValidatorContextResolver implements ContextResolver<GeneralValidator> { }
Thanks @avaysberg , I am taking a look at it now.
I had to pause this for a while, too busy with work. I will come back to this as soon as possible.