Jersey REST with List<> as a query parameter

4,560 views
Skip to first unread message

Ryan Chazen

unread,
Jan 4, 2013, 10:20:30 AM1/4/13
to google-a...@googlegroups.com
In JAX-RS, the following is valid:

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/test")
    public Response getTest(@QueryParam("ids") List<String> ids)

To call this, you could use /test?ids=1&ids=2&ids=3

This works correctly on the AppEngine dev server (jetty), but when deployed to AppEngine itself, the query fails when specifying the same parameter (ids) more than once.

I'm assuming this is a bug on the AppEngine server, as this JAX-RS / Jersey service works fine on all other servers I have tested it with.

Ryan Chazen

unread,
Jan 4, 2013, 10:22:07 AM1/4/13
to google-a...@googlegroups.com
The stack trace from AppEngine is as follows:

com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.NullPointerException
	at org.mortbay.io.Portable.getBytes(Portable.java:46)
	at org.mortbay.io.ByteArrayBuffer.<init>(ByteArrayBuffer.java:73)
	at org.mortbay.io.ByteArrayBuffer$CaseInsensitive.<init>(ByteArrayBuffer.java:414)
	at org.mortbay.io.BufferCache$CachedBuffer.<init>(BufferCache.java:120)
	at org.mortbay.io.BufferCache.lookup(BufferCache.java:93)
	at org.mortbay.jetty.HttpFields.add(HttpFields.java:612)
	at org.mortbay.jetty.Response.addHeader(Response.java:502)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:43)
	at com.google.appengine.tools.appstats.AppstatsFilter.call(AppstatsFilter.java:231)
	at com.google.appengine.tools.appstats.AppstatsFilter.access$000(AppstatsFilter.java:48)
	at com.google.appengine.tools.appstats.AppstatsFilter$1.invoke(AppstatsFilter.java:137)
	at $Proxy12.addHeader(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:43)
	at com.sun.jersey.server.impl.ThreadLocalInvoker.invoke(ThreadLocalInvoker.java:96)
	at $Proxy12.addHeader(Unknown Source)
	at com.rc.gloopsh.rest.server.resources.WorldmapEntityResource.getWorldmapEntities(WorldmapEntityResource.java:55)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:43)
	at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
	at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185)
	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:302)
	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:1480)
	at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1411)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1350)
	at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
	at com.google.appengine.tools.appstats.AppstatsFilter.doFilter(AppstatsFilter.java:141)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:454)
	at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:461)
	at com.google.tracing.TraceContext.runInContext(TraceContext.java:703)
	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:338)
	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:330)
	at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:458)
	at java.lang.Thread.run(Thread.java:679)

Ryan Chazen

unread,
Jan 4, 2013, 10:51:45 AM1/4/13
to google-a...@googlegroups.com
Is there any way to run unit tests on appengine directly instead of running them only on the dev server?

At any rate, the error is not from the multiple query parameters, but rather (found from a Google search), that the addHeader method on AppEngine live does not accept nulls while the dev server does.

The javadocs don't specify if it can or can't accept nulls, so I'm not sure what the correct behavior is.
http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpServletResponse.html#addHeader%28java.lang.String,%20java.lang.String%29

However, the live and dev server really should both function the same way - either the dev server should disallow nulls or the live should allow them.
It makes testing difficult if live and dev server behave differently.

ludovic Champenois

unread,
Jan 4, 2013, 1:00:55 PM1/4/13
to google-a...@googlegroups.com
I agree. Please file a bug and will take care of it. My preference is to
fix it at the SDK level.

Ludo
>
> --
> You received this message because you are subscribed to the Google
> Groups "Google App Engine" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/google-appengine/-/1dGUFsY7JDsJ.
> To post to this group, send email to google-a...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-appengi...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/google-appengine?hl=en.

Ryan Chazen

unread,
Jan 4, 2013, 1:06:41 PM1/4/13
to google-a...@googlegroups.com
I'll file a bug for it.

I hit into a similar issue as well:

HTTP DELETE requests can have a body defined when calling the dev server, but when calling the live server you get a 400 bad request with zero info on the admin logs that the request even occurred - it does not show in errors or anywhere else!

This is actually an existing issue from 2008 (!!!)
http://code.google.com/p/googleappengine/issues/detail?id=601

If the dev server sdk could be updated to match this behavior at least it would be a pretty big improvement considering RestyGWT and similar clients do send a method body by default if you use the standard @Attribute methods.

On Fri, Jan 4, 2013 at 8:00 PM, ludovic Champenois <lu...@google.com> wrote:
On 1/4/13 7:51 AM, Ryan Chazen wrote:
Is there any way to run unit tests on appengine directly instead of running them only on the dev server?

At any rate, the error is not from the multiple query parameters, but rather (found from a Google search), that the addHeader method on AppEngine live does not accept nulls while the dev server does.

The javadocs don't specify if it can or can't accept nulls, so I'm not sure what the correct behavior is.
http://docs.oracle.com/javaee/5/api/javax/servlet/http/HttpServletResponse.html#addHeader%28java.lang.String,%20java.lang.String%29

However, the live and dev server really should both function the same way - either the dev server should disallow nulls or the live should allow them.
It makes testing difficult if live and dev server behave differently.

I agree. Please file a bug and will take care of it. My preference is to fix it at the SDK level.

Ludo

--
You received this message because you are subscribed to the Google Groups "Google App Engine" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-appengine/-/1dGUFsY7JDsJ.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to google-appengine+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/google-appengine?hl=en.
--
You received this message because you are subscribed to the Google Groups "Google App Engine" group.
To post to this group, send email to google-appengine@googlegroups.com.
To unsubscribe from this group, send email to google-appengine+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages