Jersey client: How to add a list as query parameter

JavaRestJersey

Java Problem Overview


I'm creating a Jersey client for a GET service that has a List as query parameter. According to the documentation, it's possible to have a List as a query parameter (this information is also at @QueryParam javadoc), check it out:

> In general the Java type of the method parameter may: > > 1. Be a primitive type; > 2. Have a constructor that accepts a single String argument; > 3. Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String)); or > 4. Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only. > > Sometimes parameters may contain more than one value for the same name. If this is the case then types in 4) may be used to obtain all values.

However, I can't figure out how to add a List query parameter using Jersey client.

I understand alternative solutions are:

  1. Use POST instead of GET;
  2. Transform the List into a JSON string and pass it to the service.

The first one is not good, because the proper HTTP verb for the service is GET. It is a data retrieval operation.

The second will be my option if you can't help me out. :)

I'm also developing the service, so I may change it as needed.

Thanks!

Update

Client code (using json)

Client client = Client.create();

WebResource webResource = client.resource(uri.toString());

SearchWrapper sw = new SearchWrapper(termo, pagina, ordenacao, hits, SEARCH_VIEW, navegadores);

MultivaluedMap<String, String> params = new MultivaluedMapImpl();
params.add("user", user.toUpperCase()); 
params.add("searchWrapperAsJSON", (new Gson()).toJson(sw));

ClientResponse clientResponse = webResource .path("/listar")
                                            .queryParams(params)
                                            .header(HttpHeaders.AUTHORIZATION, AuthenticationHelper.getBasicAuthHeader())
                                            .get(ClientResponse.class);

SearchResultWrapper busca = clientResponse.getEntity(new GenericType<SearchResultWrapper>() {});

Java Solutions


Solution 1 - Java

@GET does support List of Strings

Setup:
Java : 1.7
Jersey version : 1.9

Resource

@Path("/v1/test")

Subresource:

// receive List of Strings
@GET
@Path("/receiveListOfStrings")
public Response receiveListOfStrings(@QueryParam("list") final List<String> list){
	log.info("receieved list of size="+list.size());
	return Response.ok().build();
}

Jersey testcase

@Test
public void testReceiveListOfStrings() throws Exception {
    WebResource webResource = resource();
    ClientResponse responseMsg = webResource.path("/v1/test/receiveListOfStrings")
    		.queryParam("list", "one")
    		.queryParam("list", "two")
    		.queryParam("list", "three")
    		.get(ClientResponse.class);
    Assert.assertEquals(200, responseMsg.getStatus());
}

Solution 2 - Java

If you are sending anything other than simple strings I would recommend using a POST with an appropriate request body, or passing the entire list as an appropriately encoded JSON string. However, with simple strings you just need to append each value to the request URL appropriately and Jersey will deserialize it for you. So given the following example endpoint:

@Path("/service/echo") public class MyServiceImpl {
    public MyServiceImpl() {
        super();
    }
 
    @GET
    @Path("/withlist")
    @Produces(MediaType.TEXT_PLAIN)
    public Response echoInputList(@QueryParam("list") final List<String> inputList) {
        return Response.ok(inputList).build();
    }
}

Your client would send a request corresponding to:

> GET http://example.com/services/echo?list=Hello&list=Stay&list=Goodbye

Which would result in inputList being deserialized to contain the values 'Hello', 'Stay' and 'Goodbye'

Solution 3 - Java

i agree with you about alternative solutions which you mentioned above

1. Use POST instead of GET;
2. Transform the List into a JSON string and pass it to the service.

and its true that you can't add List to MultiValuedMap because of its impl class MultivaluedMapImpl have capability to accept String Key and String Value. which is shown in following figure

enter image description here

still you want to do that things than try following code.

Controller Class

package net.yogesh.test;

import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import com.google.gson.Gson;

@Path("test")
public class TestController {
	   @Path("testMethod")
	   @GET
	   @Produces("application/text")
	   public String save(
			   @QueryParam("list") List<String> list) {
		   	   
		   return  new Gson().toJson(list) ;
	   }
}

Client Class

package net.yogesh.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.ws.rs.core.MultivaluedMap;

import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.core.util.MultivaluedMapImpl;

public class Client {
	public static void main(String[] args) {
		String op = doGet("http://localhost:8080/JerseyTest/rest/test/testMethod");
		System.out.println(op);
	}
	
	private static String doGet(String url){
		List<String> list = new ArrayList<String>();
		list = Arrays.asList(new String[]{"string1,string2,string3"});
		
		MultivaluedMap<String, String> params = new MultivaluedMapImpl();
		String lst = (list.toString()).substring(1, list.toString().length()-1);
		params.add("list", lst);
		
		ClientConfig config = new DefaultClientConfig();
		com.sun.jersey.api.client.Client client = com.sun.jersey.api.client.Client.create(config);
		WebResource resource = client.resource(url);
		
		ClientResponse response = resource.queryParams(params).type("application/x-www-form-urlencoded").get(ClientResponse.class);
		String en = response.getEntity(String.class);
		return en;
	}
}

hope this'll help you.

Solution 4 - Java

GET Request with JSON Query Param

package com.rest.jersey.jerseyclient;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

public class JerseyClientGET {

	public static void main(String[] args) {
		try {    			
			
			String BASE_URI="http://vaquarkhan.net:8080/khanWeb";    			
			Client client = Client.create();    
			WebResource webResource = client.resource(BASE_URI);

			ClientResponse response = webResource.accept("application/json").get(ClientResponse.class);

			/*if (response.getStatus() != 200) {
			   throw new RuntimeException("Failed : HTTP error code : "
				+ response.getStatus());
			}
*/
			String output = webResource.path("/msg/sms").queryParam("search","{\"name\":\"vaquar\",\"surname\":\"khan\",\"ext\":\"2020\",\"age\":\"34\""}").get(String.class);
			//String output = response.getEntity(String.class);

			System.out.println("Output from Server .... \n");
			System.out.println(output);    						

		} catch (Exception e) {

			e.printStackTrace();    
		}    
	}    
}

Post Request :

package com.rest.jersey.jerseyclient;

import com.rest.jersey.dto.KhanDTOInput;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;

public class JerseyClientPOST {

	public static void main(String[] args) {
		try {

			KhanDTOInput khanDTOInput = new KhanDTOInput("vaquar", "khan", "20", "E", null, "2222", "8308511500");    					

			ClientConfig clientConfig = new DefaultClientConfig();

			clientConfig.getFeatures().put(	JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

			Client client = Client.create(clientConfig);

			   // final HTTPBasicAuthFilter authFilter = new HTTPBasicAuthFilter(username, password);
			   // client.addFilter(authFilter);
			   // client.addFilter(new LoggingFilter());
			
			//
			WebResource webResource = client
					.resource("http://vaquarkhan.net:12221/khanWeb/messages/sms/api/v1/userapi");
			    
			  ClientResponse response = webResource.accept("application/json")
				.type("application/json").put(ClientResponse.class, khanDTOInput);
			    
			  
			if (response.getStatus() != 200) {
				throw new RuntimeException("Failed : HTTP error code :" + response.getStatus());
			}

			String output = response.getEntity(String.class);

			System.out.println("Server response .... \n");
			System.out.println(output);

		} catch (Exception e) {

			e.printStackTrace();

		}    
	}    
}

Solution 5 - Java

One could use the queryParam method, passing it parameter name and an array of values:

    public WebTarget queryParam(String name, Object... values);

Example (jersey-client 2.23.2):

    WebTarget target = ClientBuilder.newClient().target(URI.create("http://localhost"));
    target.path("path")
            .queryParam("param_name", Arrays.asList("paramVal1", "paramVal2").toArray())
            .request().get();

This will issue request to following URL:

    http://localhost/path?param_name=paramVal1&param_name=paramVal2

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlsborgView Question on Stackoverflow
Solution 1 - JavaDharmiView Answer on Stackoverflow
Solution 2 - JavaPerceptionView Answer on Stackoverflow
Solution 3 - JavaYogesh PrajapatiView Answer on Stackoverflow
Solution 4 - Javavaquar khanView Answer on Stackoverflow
Solution 5 - JavaAndriyView Answer on Stackoverflow