简体   繁体   中英

Jersey Client / JAX-RS and optional (not default) @QueryParam (client side)

I have a RESTful API who's document says that a certain query parameter is optional, and does not supply a default argument. So, I can either supply the value or not send it in the GET request as a parameter.

Example:

  • queryA is required
  • queryB is optional (can send GET without it)

This should work:

http://www.example.com/service/endpoint?queryA=foo&queryB=bar

This should also work:

http://www.example.com/service/endpoint?queryA=foo

How do I make an client interface for Jersey-Proxy that can do this?? I do not have the server-side code to interface with so I am using org.glassfish.jersey.client.proxy.WebResourceFactory via Jersey-Proxy to generate the client to interact with the server API.

Sample interface:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") String second);

}

I know I can make another method:

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first);

But what happens when you have multiple optional fields?? I don't want to make every possible mutation of them!

The interface was right all along

I can't believe it was this easy:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") String second);

}

Notice anything different than the questions interface?? Nope. That's because that is the answer!


Don't use @DefaultValue for optional parameters

If you want to default a parameter to a specific value, you use the @DefaultValue annotation in the parameter:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") @DefaultValue("default") String second);

}

Pass null to the @QueryParam you don't want

If you want to make the @QueryParam optional, you do not apply the @DefaultValue annotation. To pass a value with the query parameter, just pass in the value normally. If you would like the query parameter to not show up at all, just pass null !

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            // Pass null to this parameter to not put it in the GET request
            @QueryParam("queryB") String second);

}

So calling ServiceInterface.getEndpoint("firstQueryParam", "secondQueryParam"); calls:

http://targethost.com/service/endpoint?queryA=firstQueryParam&queryB=secondQueryParam

and calling ServiceInterface.getEndpoint("firstQueryParam", null); calls:

http://targethost.com/service/endpoint?queryA=firstQueryParam

And walla! No second query parameter! :)

Note on primitive values

If your API takes primitive values (like int , float , boolean , etc), then use the object wrapper class ( Autoboxing ) for that primitive (like Integer , Float , Boolean , etc). Then, you can pass null to the method:

public Response getEndpoint(@QueryParam("queryA") Boolean first);

You can inject a UriInfo instance (or something else like HttpServletRequest ) into your method, and get whatever data you want off of it.

For example

@Path("/endpoint")
@GET
public Response getEndpoint(@Context UriInfo info, @QueryParam("queryA") String queryA) {
  String queryB = info.getQueryParameters().getFirst("queryB");
  if (null != queryB) {
    // do something with it
  }
  ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM