users@jersey.java.net

[Jersey] Re: How Jersey dispatch request based on query parameter rather than path?

From: 王子剑 <nerther_at_gmail.com>
Date: Thu, 17 Nov 2011 09:59:00 +0800

Thanks for your solution, but I need a more graceful solution, because
there are more than 40+ question mark style API, that means the if...else
will be a big horrible. : )

Regards.

Zijian.

在 2011年11月16日 下午11:06,Pavel Bucek <pavel.bucek_at_oracle.com>写道:

> Ok. Then the solution is slightly uglier:
>
> public class PersonResource {
> private final String person;
> private PersonResource(String person) {
> this.person = person;
> }
> @GET
> public String get() {
> return "person";
> }
> }
> public class LocationResource {
> private final String person;
> private LocationResource(String person) {
> this.person = person;
> }
> @GET
> public String get() {
> return "location";
> }
> }
> public class FriendsResource {
> private final String person;
> private FriendsResource(String person) {
> this.person = person;
> }
> @GET
> public String get() {
> return "friends";
> }
> }
> @Path("{person}")
> public Object getPpl(@PathParam("person") String person,
> @QueryParam("location") String location,
> @QueryParam("friends") String friends) {
> // you might want to handle location != null && friends != null
> // if that state can occur.
> if(location != null) {
> return new LocationResource(person);
> } else if (friends != null) {
> return new FriendsResource(person);
> } else {
> return new PersonResource(person);
> }
> }
>
> tested with following client calls:
>
> WebResource webResource = resource();
>
> webResource.addFilter(new LoggingFilter());
>
> webResource.path("helloworld").path("person").get(String.class);
>
>
> webResource.path("helloworld").path("person").queryParam("location",
> "").get(String.class);
>
>
> webResource.path("helloworld").path("person").queryParam("friends",
> "").get(String.class);
>
>
> hope it helps..
>
>
>
> Pavel
>
>
> On 11/16/11 3:20 PM, 王子剑 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>写 道:
>
>> 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>>
>> >
>> > Hi 王子剑,
>> >
>> > please use 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> * Get people information
>> >>
>> >> *GET : http://test.com/{people}?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>*, 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?
>> >> *
>> >> *
>> >> *
>> >> *
>> >
>> >
>>
>>
>
>