mehandih / grails-jaxrs

Automatically exported from code.google.com/p/grails-jaxrs
0 stars 0 forks source link

Cannot use grails-jaxrs 0.6 with servlet 2.5 (it needs servlet api 3.0) #66

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1. create a grails app using the servelt api 2.5 (as per grails.servlet.version 
property in BuildConfig.groovy)
2. install grails-jaxrs 0.6
3. add a resource that uses a json reader to convert incoming http requests
4. Send a request to that resource

What is the expected output? What do you see instead?
Json data from request should be converted to a map (and then to a domain 
object).

I obtain the following error message 

Caused by: java.lang.ClassNotFoundException: javax.servlet.http.Part
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
        at java.lang.Class.getDeclaredMethods(Class.java:1791)
        at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46)
        at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33)
        at org.grails.jaxrs.support.ConverterUtils.jsonToMap(ConverterUtils.groovy:94)
        at org.grails.jaxrs.support.DomainObjectReaderSupport.readFromJson(DomainObjectReaderSupport.groovy:124)
        at org.grails.jaxrs.support.DomainObjectReaderSupport.readFrom(DomainObjectReaderSupport.groovy:93)
        at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:474)

What version of the product are you using? On what operating system?
grails 2.0.4, grails-jaxrs 0.6 on debian linux 6.0 (jre 1.6.0_31)

Please provide any additional information below.
The problem is triggered by ConverterUtils.jsonToMap(), that uses 
RequestStreamAdapter which in turn has been adapted to support servlet api 3.0 
in a way that actually requires the servlet api version 3.0 on the classpath.

Original issue reported on code.google.com by davide.cavestro on 22 Jun 2012 at 8:10

GoogleCodeExporter commented 8 years ago

I don't know the purpose of current ConverterUtils.jsonToMap() implementation, 
however I've seen that in order to extract a map with the request parameters 
the following would be enough for me.

static Map jsonToMap(InputStream input, String encoding) {
    def slurper = new groovy.json.JsonSlurper()
    return slurper.parse(new InputStreamReader (input, encoding));

// original implementation          
//      def adapter = new RequestStreamAdapter(input)
//      adapter.characterEncoding = encoding
//      adapter.setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, 'json')
//        
//      def params = new GrailsParameterMap(adapter)
//      jsonListener.paramsCreated(params)
//      params.iterator().next().value 
}

Original comment by davide.cavestro on 22 Jun 2012 at 1:06

GoogleCodeExporter commented 8 years ago
Hi Davide,

The purpose of the current jsonToMap()/xmlToMap() implementation is to reuse 
how Grails binds JSON/XML to domain objects. This is done via 

- 
https://github.com/grails/grails-core/blob/v2.0.4/grails-plugin-converters/src/m
ain/groovy/org/codehaus/groovy/grails/web/converters/JSONParsingParameterCreatio
nListener.groovy and 
- 
https://github.com/grails/grails-core/blob/v2.0.4/grails-plugin-converters/src/m
ain/groovy/org/codehaus/groovy/grails/web/converters/XMLParsingParameterCreation
Listener.groovy

and used in ConverterUtils of grails-jaxrs

https://github.com/krasserm/grails-jaxrs/blob/jaxrs-0.6/src/groovy/org/grails/ja
xrs/support/ConverterUtils.groovy#L45

Although I can confirm that your alternative proposal works for the existing 
JUnit tests, I can also see that the Grails built-in mechanism is doing more 
than your proposed solution (e.g. flatten keys and so on ...). So, I'm hesitant 
to implement a proprietary mechanism for JSON/XML to domain object conversion.

This however doesn't solve the Servlet 2.5/3.0 problem. I hope to find some 
time during the next days to provide a fix. Should you have further proposals 
how to address this issue, I'd highly appreciate.

Thanks,
Martin

Original comment by krass...@googlemail.com on 25 Jun 2012 at 6:31

GoogleCodeExporter commented 8 years ago
Hi Martin,
I wasn't aware at all about the purpose of ParsingParameterCreationListener. 
I'll take a look. The root of the problem seems the usage of mock request... 
btw 
http://grails.1312388.n4.nabble.com/Support-Servlet-3-0-and-2-5-in-the-same-plug
in-td4498930.html could give some useful ideas.

Cheers
Davide

Original comment by davide.cavestro on 25 Jun 2012 at 8:01

GoogleCodeExporter commented 8 years ago
Somewhat following Burt's advice I've tried an hybrid approach: proxying the 
MockHttpServletRequest instance instead of obtaining it trough inheritance. 
This way we should avoid hard dependencies on servlet api 3.0 and still be able 
to use springs' mock implementation of HttpServletRequest.

Something like
    static Map jsonToMap(InputStream input, String encoding) {
//        def adapter = new RequestStreamAdapter(input)
//        adapter.characterEncoding = encoding
//        adapter.setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, 
'json')
        def adapter = newRequestStreamAdapter(input, encoding, 'json')

        def params = new GrailsParameterMap(adapter)
        jsonListener.paramsCreated(params)
        params.iterator().next().value 
    }

where newRequestStreamAdapter is implemented as follows

    static def newRequestStreamAdapter (InputStream stream, String characterEncoding, String format) {

        final MockHttpServletRequest req = new MockHttpServletRequest ();

        req.characterEncoding = characterEncoding
        req.setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, format)

        return (HttpServletRequest)Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(),
        [HttpServletRequest.class] as Class[], new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) {

                String methodName = method.getName();

                if ("getFormat".equals(methodName)) {
                    return req.getAttribute(GrailsApplicationAttributes.CONTENT_FORMAT);
                }

                if ("getInputStream".equals(methodName)) {
                    if (stream instanceof ServletInputStream) {
                        return stream
                    } else if (stream) {
                        return new DelegatingServletInputStream(stream)
                    } else {
                        return req.getInputStream()
                    }
                }                
                return req.getClass().getMethod(
                    method.getName(), method.getParameterTypes()).invoke(req, args);

            }

        });
    }

Of course the same apply to xml requests.

PS: it should still be adapted with the addition of ad-hoc management for 
servlet 3.0 new methods, such as "getParts" and so on... something like 

if ("startAsync".equals(methodName)) {
    throw new UnsupportedOperationException();
}

that would be the counterpart of actual RequestStreamAdapter implementation.

I'm going to patch the jaxrs plugin locally and give it a try.

Cheers
Davide

Original comment by davide.cavestro on 25 Jun 2012 at 1:18

GoogleCodeExporter commented 8 years ago
Great, please create a pull request if it works. Thanks for your feedback, help 
and contributions. Cheers, Martin

Original comment by krass...@googlemail.com on 25 Jun 2012 at 2:27

GoogleCodeExporter commented 8 years ago
Just merged you pull request to master. Thanks for awesome work!

Original comment by krass...@googlemail.com on 9 Jul 2012 at 10:56

GoogleCodeExporter commented 8 years ago
I use tomcat 6, java version "1.6.0_24" and tried the version with this fix 
from git,
but I get following error:

Stacktrace follows:
org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionExcepti
on: Executing action [handle] of controller [org.grails.jaxrs.JaxrsController] 
in plugin [jaxrs] caused exception: Runtime error executing action
        at org.grails.jaxrs.web.JaxrsFilter.doFilterInternal(JaxrsFilter.java:46)
        at com.googlecode.psiprobe.Tomcat60AgentValve.invoke(Tomcat60AgentValve.java:30)
        at java.lang.Thread.run(Thread.java:679)
Caused by: 
org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionExcepti
on: Runtime error executing action
        ... 3 more
Caused by: java.lang.reflect.InvocationTargetException
        ... 3 more
Caused by: java.lang.NoClassDefFoundError: 
org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletRequest
        at org.grails.jaxrs.support.ConverterUtils.newRequestStreamAdapter(ConverterUtils.groovy:152)
        at org.grails.jaxrs.support.ConverterUtils.jsonToMap(ConverterUtils.groovy:101)
        at org.grails.jaxrs.provider.JSONReader.readFrom(JSONReader.java:88)
        at org.grails.jaxrs.provider.JSONReader.readFrom(JSONReader.java:61)
        at org.grails.jaxrs.support.MessageBodyReaderSupport.readFrom(MessageBodyReaderSupport.java:55)
        at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:474)
        at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:123)
        at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46)
        at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
        at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203)
        at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
        at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
        at com.sun.jersey.server.impl.uri.rules.SubLocatorRule.accept(SubLocatorRule.java:134)
        at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
        at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
        at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
        at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
        at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1483)
        at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1414)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1363)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1353)
        at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
        at org.grails.jaxrs.web.JaxrsContext$JaxrsServiceImpl.process(JaxrsContext.java:192)
        at org.grails.jaxrs.JaxrsController$_closure1.doCall(JaxrsController.groovy:48)

thanks for your help,
cahya.

Original comment by cahya.wi...@gmail.com on 26 Jul 2012 at 8:59

GoogleCodeExporter commented 8 years ago
Hi cahya,
the plugin should still have a compile-time dependency on spring test (as
per
https://github.com/krasserm/grails-jaxrs/blob/master/grails-app/conf/BuildConfig
.groovy#L45
 and http://code.google.com/p/grails-jaxrs/issues/detail?id=39)... I just
wonder how that library could have been excluded from your runtime
classpath: did you explicitly excluded it? If so removing the exclusion
should do the trick...

Original comment by davide.cavestro on 30 Jul 2012 at 8:40

GoogleCodeExporter commented 8 years ago
@cahya
Sorry, I was wrong on my previous comment... I introduced a dependency on 
GrailsMockHttpServletRequest from grails-test. That's normally available only 
at test time. I'm going to see if it can be replaced with 
org.springframework.mock.web.MockHttpServletRequest (for which applies what I 
said on my previous post). IN the meantime you could add a compile or runtime 
dependency on grails-test.

Cheers
Davide

Original comment by davide.cavestro on 1 Aug 2012 at 7:32

GoogleCodeExporter commented 8 years ago
@cahya
could you please check the further fix I merged into master branch yesterday?
It works for me both with run-app and deploying the war for a servlet 2.5 
grails 2.0.4 app on tomcat 6 and 7.

Original comment by davide.cavestro on 2 Aug 2012 at 7:10

GoogleCodeExporter commented 8 years ago
I have tried it and it works now on tomcat6 without any problem. 
Thanks

Original comment by cahya.wi...@gmail.com on 6 Aug 2012 at 5:21

GoogleCodeExporter commented 8 years ago
Is there a plan to do a release with this fix incorporated? 

Original comment by m...@tristanburch.com on 7 Jan 2013 at 10:51

GoogleCodeExporter commented 8 years ago
I've published a binary for release 0.7 at 
http://code.google.com/p/grails-jaxrs/downloads/detail?name=grails-jaxrs-0.7.zip
&can=2&q=

could you please give it a try downloading the zip and installing from 
filesystem?

Cheers
Davide

Original comment by davide.cavestro on 9 Jan 2013 at 5:31

GoogleCodeExporter commented 8 years ago
Thanks for providing 0.7.  It, and Burt's advice on the dependency issue, 
solved the ClassNotFoundException for javax.servlet.http.Part when submitting 
XML with Tomcat 6 and grails 2.1.1.  (It only occurred in production on 
Tomcat6, not in development in GGTS).

I downloaded and installed it from the filesystem.  When will it be available 
through the normal 'install-plugin' mechanism?

Original comment by wis...@gmail.com on 17 Jan 2013 at 5:47

GoogleCodeExporter commented 8 years ago
We'll upload it to the central repo soon. When done we'll post a message on the 
grails-jaxrs-discuss mailing list.

Original comment by krass...@googlemail.com on 18 Jan 2013 at 7:28

GoogleCodeExporter commented 8 years ago
Hi, 
when will the new version 0.7 being available?
The workaround in the above download link failed?

Can you fix it soon, please?

Cheers 
Hardy

Original comment by Hardy....@gmail.com on 20 Mar 2013 at 10:14