I want to fetch a jakarta.json.JsonObject in the HttpResponse itself using the Jakarta JSONP API. Right now, I have to fetch it as a String, feed the body into a reader and then get the JsonObject like the code below.
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
JsonReader jsonReader = Json.createReader(new StringReader(response.body()));
JsonObject object = jsonReader.readObject();
jsonReader.close();
How do I get the response as HttpResponse<JsonObject> response directly? I don't want to use any external libraries other than the Jakarta JSONP one.
Edit: As an example, one could write their own BodyHandler like this:
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodySubscriber;
import java.net.http.HttpResponse.BodySubscribers;
import java.net.http.HttpResponse.ResponseInfo;
import jakarta.json.JsonObject;
public class JsonObjectBodyHandler implements HttpResponse.BodyHandler<JsonObject> {
#Override
public BodySubscriber<JsonObject> apply(ResponseInfo responseInfo) {
// How to implement this
}
}
and then use it in the function like this:
HttpResponse<JsonObject> response = httpClient.send(request, new JsonObjectBodyHandler());
Jersey webmethod receives json and return json, i created a client to post the json with gzip encoding, i have no idea it is the right way to encode the the json to post, i want to confirm the request body is really compressed or not?
This is the jersey webmethod
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/getgzip")
public RPGZIP postDocument(RGZIP gzip){
RPGZIP _response = new RPGZIP();
_response.rpid = gzip.docid;
_response.rpdata = gzip.docdata;
return _response;
}
This is the client class to consume jersey
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import com.gzip.RGZIP;
import org.glassfish.jersey.message.GZipEncoder;
public class rclient {
public static void main(String[] args){
String REST_URI =
"http://localhost:8084/TestGZip/webresources/gzip/getgzip";
Client client = ClientBuilder.newClient();
client.register(GZipEncoder.class);
RGZIP rzip = new RGZIP();
rzip.docid = 1234;
rzip.docdata = "Working..";
Response r =
client.target(REST_URI).request(MediaType.APPLICATION_JSON)
.post(Entity.entity(rzip, MediaType.APPLICATION_JSON));
System.out.println(r.readEntity(String.class));
}
}
To know that your request is compressed, there must be a request header like Content-Encoding: gzip sent to server for server to know that they have to decompress the payload
What you did is correct in your code.
Environment: WildFly 8.1.
I deploy 2 applications on one server. One is connecting with other and trying to run POST method on rest service.
In service project I added:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/rest")
public class RsActivator extends Application {
}
As far as I understand the user's guide for wildfly and jax-rs, this should be enough to run service listed below:
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import pl.patom.en.rest.model.LoginData;
import pl.patom.en.security.model.User;
import pl.patom.en.services.UserService;
#Path("services")
public class RestService {
#Inject
private UserService userService;
#PermitAll
#POST
#Consumes(MediaType.APPLICATION_JSON + ";charset=UTF-8")
#Path("/login")
public Response login(LoginData ld) {
User checkedUser = userService.findByLogin(ld.getUsername());
if (checkedUser == null || !checkedUser.getPassword().equals(ld.getPassword())) {
return Response.serverError().build();
}
return Response.ok().build();
}
}
In project where I call service I have this method:
public String login() {
try {
HttpClient client = HttpClientBuilder.create().build();
HttpPost postRequest = new HttpPost("http://localhost:8080/en/rest/services/login/");
LoginData ld = new LoginData(username, password);
Gson gson = new Gson();
String json = gson.toJson(ld);
StringEntity input = new StringEntity(json);
input.setContentType("application/json");
postRequest.setEntity(input);
postRequest.setHeader("Authorization", "Basic cm9vdDpyb290");
HttpResponse response = client.execute(postRequest);
if (response.getStatusLine().getStatusCode() == 200) {
loggedIn = true;
return "/secured/index.xhtml?faces-redirect=true";
} else {
loggedIn = false;
}
} catch (Exception e) {
loggedIn = false;
}
return null;
}
Why do I always get 200 OK response? It doesn't matter if I use #GET or #POST annotation = always OK. Secondly, ther is no debugger activity in method (application never stops on any breakpoint within this method):
public Response login(LoginData ld)
(It works when I use RESTClient in Firefox).
Oo, and there is another curious thing... In return with this 200 OK status I always get jsf login form.
Problem solved by adding: /rest/* to non-secured section of web-resource-collection.
I'm using Jersey resourse in my project, like:
#Path("/api")
public class MyResource {
#Path("/create")
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response handle(final String xml, #Context final HttpServletRequest request) {
.....
}
and I'm trying to test it:
public class MobipayResourceTest extends JerseyTest {
private MockHttpServletRequest servletRequest;
#Override
#Before
public void setUp() throws Exception {
servletRequest = new MockHttpServletRequest();
servletRequest.setMethod("POST");
}
public MobipayResourceTest() throws TestContainerException {
super("ua.privatbank.mobipay.api.resource");
}
#Test
public void testRes(){
WebResource webResource = resource();
webResource.path("/api/create").post(???); // I need to pass 2 parameters in the request - xml (in the body of post) and HttpServletRequest
}
How can I pass 2 my parameters (String xml and HttpServletRequest) to the resourse in test?
You don't need to pass the HttpServletRequest, I believe.
As to the xml parameter, I think you should have a parameter
of some other class there, not just of type String. For example
Item, Customer, Order, i.e. any business object (bean, POJO).
The way you've done it now, you'd better declare
#Consumes(MediaType.TEXT_PLAIN) because you declare that
you expect just a String in your method. Normally when
you expect XML, this XML value is unmarshalled into
an object of some type (usually a bean, POJO, etc). You
get this on the fly and you can just work with the object.
Here is some sample code of a sample Java client.
package com.company.api.test;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import com.google.gson.Gson;
import com.sun.jersey.api.client.Client;
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.client.filter.LoggingFilter;
import com.company.common.DateUtil;
import com.company.api.input.ItemOperation;
import com.company.api.input.ItemOperationData;
import com.company.api.result.ItemResult;
public class JavaClientREST {
public static void main(String[] args) throws Exception {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
client.addFilter(new LoggingFilter());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
WebResource service = client.resource(getBaseURI());
ItemOperation op1 = new ItemOperation();
op1.setItemID("447");
Date d1 = DateUtil.getDate(2013, Calendar.DECEMBER, 20);
System.out.println("DT1 = " + sdf.format(d1));
op1.setDate(d1);
op1.setOperation("pause");
String res = service.path("Item")
.entity(op1, MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_JSON)
.post(String.class);
Gson gson = new Gson();
ItemResult result = gson.fromJson(res, ItemResult.class);
System.out.println("ID = [" + result.getId() + "]");
System.out.println("Error = [" + result.getError() + "]");
System.out.println("DONE!");
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/api/service").build();
}
}
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:
Be a primitive type;
Have a constructor that accepts a single String argument;
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
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:
Use POST instead of GET;
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>() {});
#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());
}
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'
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
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.
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¶m_name=paramVal2
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();
}
}
}