Skip to content
This repository has been archived by the owner on Jun 14, 2018. It is now read-only.

The RESTeasy validation doesn't work with packaging war #75

Open
avaysberg opened this issue Jul 27, 2017 · 12 comments
Open

The RESTeasy validation doesn't work with packaging war #75

avaysberg opened this issue Jul 27, 2017 · 12 comments
Assignees
Labels

Comments

@avaysberg
Copy link

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?

  1. we use the sample-app
  2. we change to use the war ->(war)
  3. deploy on tomcat
  4. added to the @notempty > public EchoMessage echo(@notempty String echoText) {
  5. 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?

@fabiocarvalho777
Copy link
Member

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.

@avaysberg
Copy link
Author

avaysberg commented Jul 27, 2017

Hi,
this the sampe-app like attachment:

sample-app.zip

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

@avaysberg
Copy link
Author

Hi,
i think, that the problem is, that standalone spring boot find this dependencies:

org.jboss.resteasy
resteasy-validator-provider-11
3.1.3.Final

but the web spring boot doesn't find it. The question is why? RESTEasy (https://docs.jboss.org/resteasy/docs/3.1.3.Final/userguide/html/Validation.html)

@msauza
Copy link

msauza commented Jul 28, 2017

"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

@fabiocarvalho777
Copy link
Member

fabiocarvalho777 commented Jul 29, 2017

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.

@fabiocarvalho777
Copy link
Member

fabiocarvalho777 commented Jul 29, 2017

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.

@fabiocarvalho777
Copy link
Member

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.

@fabiocarvalho777
Copy link
Member

fabiocarvalho777 commented Jul 29, 2017

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.

@avaysberg
Copy link
Author

avaysberg commented Jul 30, 2017

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.

@avaysberg
Copy link
Author

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> { }

@fabiocarvalho777
Copy link
Member

Thanks @avaysberg , I am taking a look at it now.

@fabiocarvalho777 fabiocarvalho777 self-assigned this Aug 1, 2017
@fabiocarvalho777
Copy link
Member

I had to pause this for a while, too busy with work. I will come back to this as soon as possible.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants