See
http://stackoverflow.com/questions/8118969/jersey-path-cannot-process-question-mark
Seems you are using question mark where slash is more appropriate -
perhaps for backward compatibility reasons.
Other option to work around this is to write your resource paths like this:
@Path("{people}")
public People getPeople(@PathParam String people);
@Path("{people}/location")
public Location getLocation(@PathParam String people);
@Path("{people}/friends")
public List<People> getFriends(@PathParam String people);
And then have a request filter that replaces the question marks in the
URI by slashes - Jersey will then dispatch it properly and for future
clients you will have a clean API (as the one you have now - utilizing
query parameters where URI path segments are more appropriate is not clean).
The filter can be as simple as this:
public class QueryParamToPathSegmentFilter implements
ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
String requestUri = request.getRequestUri().toString();
requestUri = requestUri.replace('?', '/');
request.setUris(request.getBaseUri(),
UriBuilder.fromUri(requestUri).build());
return request;
}
}
Depending on how your URI's look like - you can make it more sophisticated.
Here is more on how you can register filters in your application:
http://jersey.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/container/filter/package-summary.html
Regards,
Martin
On 16.11.2011 15:20, 王子剑 wrote:
> Hi Pavel
>
> Actually the return types are totally different, example:
>
> @Path("{people}")
> public People getPeople(@PathParam String people);
>
> @Path("{people}?location")
> public Location getLocation(@PathParam String people);
>
> @Path("{people}?friends")
> public List<People> getFriends(@PathParam String people);
>
> ......
>
> Jersey dispatch incoming request base on path rather on query
> parameters, but we can encode the expected query parameter to the path
> to implement it transparently.
>
> I write a ContainerRequestFilter to do this,
>
> public class SubResourceMatchableRequestFilter implements
> ContainerRequestFilter {
>
> @Override
> public ContainerRequest filter(ContainerRequest request) {
> final String subResource = getFirstSubResource(request);
> if (subResource == null) {
> return request;
> }
> return new AdaptingContainerRequest(request) {
> @Override
> public String getPath(boolean decode) {
> return new StringBuilder(super.getPath(decode))
> .append(decode ? "?" : "%3F")
> .append(subResource)
> .toString();
> }
> };
> }
>
> private String getFirstSubResource(ContainerRequest request) {
> String query = request.getRequestUri().getQuery();
> if (query == null) {
> return null;
> }
> int indexOfFirstAnd = query.indexOf("&");
> return indexOfFirstAnd == -1 ? query : query.substring(0,
> indexOfFirstAnd);
> }
> }
>
> The requirement can be archived, but I don`t know is there some hidden
> trouble?
>
> Looking forward to your reply, thanks.
>
> Regards,
> Zijian.
>
> 在 2011年11月16日 下午6:15,Pavel Bucek <pavel.bucek_at_oracle.com
> <mailto:pavel.bucek_at_oracle.com>>写 道:
>
> Yeah, you are right.
>
> It should be achievable by using reqexes, but I've tested this:
>
> @GET
> @Path("{people}")
> public String getPeople(@PathParam("people") String people,
> @QueryParam("location") String location) {
> if(location == null) {
> return location;
> } else {
> return people;
> }
> }
>
> and looks like it does what you need. location param here can be null
> ("?location" not present) or "" (empty string), thus you are able to
> decide what to return (you are using same return data type for both
> methods in you example so that shouldn't be a problem..
>
> Let me know if this works for you.
>
> Regards,
> Pavel
>
>
> On 11/16/11 2:39 AM, 王子剑 wrote:
> > Hi Pavel
> >
> > Thank you for your kind reply.
> >
> > The code: webResource.path("test?location").get(String.class); will
> > encode character *?* to *%3F*(url encode), that means the
> request url
> > will be *http://test.com/test%3Flocation* instead of
> > *http://test.com/test?location*.
> >
> > If someone use unencoded url like *http://test.com/test?location*,
> > Jersey will return 405 'MethodNotAllowed' response.
> >
> > Best regards.
> >
> > Zijian
> >
> > 2011/11/15 Pavel Bucek <pavel.bucek_at_oracle.com
> <mailto:pavel.bucek_at_oracle.com>
> > <mailto:pavel.bucek_at_oracle.com <mailto:pavel.bucek_at_oracle.com>>>
> >
> > Hi 王子剑,
> >
> > please use users_at_jersey.java.net <mailto:users_at_jersey.java.net>
> <mailto:users_at_jersey.java.net <mailto:users_at_jersey.java.net>>
> > mailing list, this one is for mailing list administration only.
> >
> > And about your issue - it can be achieved, you need to exclude
> > requests containing question mark from first method. See following:
> >
> > @GET
> > @Path("{people:[^\\?]*}")
> > public String getPeople(@PathParam("people") String people) {
> > return people;
> >
> > }
> >
> > @GET
> > @Path("{people}?location")
> > public String getLocation(@PathParam("people") String people) {
> > return "location:" + people;
> > }
> >
> > I verified this with following requests:
> >
> > responseMsg = webResource.path("test").get(String.class); //
> > matches getPeople
> > responseMsg = webResource.path("test?location").get(String.class);
> > // matches getLocation
> >
> > Regards,
> > Pavel
> >
> >
> >
> >
> >
> > On 11/15/11 11:10 AM, 王子剑 wrote:
> >> Hello All
> >>
> >> I am handling a legacy system and I cannot process the request by
> >> Jersey gracefully.
> >>
> >> API:
> >>
> >> *GET : http://test.com/{people} <http://test.com/%7Bpeople%7D>
> >> <http://test.com/%7Bpeople%7D> * Get people information
> >>
> >> *GET : http://test.com/{people}?location
> <http://test.com/%7Bpeople%7D?location>
> >> <http://test.com/%7Bpeople%7D?location>* Get people location.
> >>
> >>
> >>
> >> Code
> >>
> >> *_at_GET*
> >> *_at_Path("{people}")*
> >> *public People getPeopleInformation(String people);*
> >> *
> >> *
> >> *_at_GET*
> >> *_at_Path("{people}?location")*
> >> *public People getPeopleLocation(String people);*
> >> *
> >> *
> >>
> >> Jersey will not invoke the second method *getPeopleLocation *when
> >> the client request url: *http://test.com/{people}?location
> <http://test.com/%7Bpeople%7D?location>
> >> <http://test.com/%7Bpeople%7D?location>*, it always dispatch the
> >> incoming request which end with '?location' to the first method
> >> '*getPeopleInformation*'.
> >>
> >> Is there some way to let Jersey to dispatch request based on
> >> query parameters like this situation?
> >> *
> >> *
> >> *
> >> *
> >
> >
>
>