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.
Related
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());
I configure the RESTFul API in JPOS from jpos-rest.pdf.
The problem is I couldn't receive data from the client, but I can send data to the client.
In Echo.java class by below code I can send data:
package org.jpos.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;
#Path("/echo")
public class Echo {
#GET
#Produces({MediaType.APPLICATION_JSON})
public Response echoGet() {
Map<String, Object> resp = new HashMap<>();
resp.put("success", "true");
resp.put("Name", "Hamid");
resp.put("Family", "Mohammadi");
Response.ResponseBuilder rb = Response.ok(resp, MediaType.APPLICATION_JSON).status(Response.Status.OK);
return rb.build();
}
}
How can I receive data from the client? There is no request parameter to find what is the request and its data;
Thanks to #Sabir Khan
I changed the code to:
#Path("/echo")
public class Echo {
#PUT
#Produces({MediaType.APPLICATION_JSON})
#Consumes(MediaType.TEXT_PLAIN)
#Path("/{name}/{family}")
public Response echoGet(
#PathParam("name") String name,
#PathParam("family") String family,
String Desc
) {
Map<String, Object> resp = new HashMap<>();
resp.put("success", "true");
resp.put("Name", name);
resp.put("Family", family);
resp.put("Desc", Desc);
Response.ResponseBuilder rb = Response.ok(resp,
MediaType.APPLICATION_JSON).status(Response.Status.OK);
return rb.build();
}
}
and send data to RESTFul API like this:
I have an API which returns APPLICATION_OCTET_STREAM as Media Type in response. I need to enhance it to also send a JSON body with some details regarding the file, say counts of right and wrong records in the file. So basically I need two kinds of response in same API. Is this doable ?
It's possible, but you will need to use a Multipart response. Keep in mind though that some clients will not be able to handle this type of response. You'll normally see this data type using in uploading files, but is not very often used as a response data type.
That being said, below is a complete example using the Jersey Test Framework. In the resource, a file and some extra data are being sent in the response, with the use of Jersey's FormDataMultiPart
#Path("test")
public static class TestResource {
#GET
#Produces(MediaType.MULTIPART_FORM_DATA)
public Response get() throws Exception {
final MultiPart multiPart = new FormDataMultiPart()
.field("json-data", new Model("Test Value"), MediaType.APPLICATION_JSON_TYPE)
.bodyPart(new FileDataBodyPart("file-data", new File("test.txt")));
return Response.ok(multiPart).build();
}
}
To make the test succeed, you should have a file called test.txt with the content "Some Test Data in File" (without quotes) on the first line of that file. This multipart response has two parts, the json-data part, which uses a Model class to model the JSON, and the file-data part which has the contents of the file.
To make the Multipart work, we need to have the MultiPartFeature register on the server and the client (for client side deserialization) and we need to have the multipart dependency in our project.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey2.version}</version>
</dependency>
On the client, to get the multipart out of the response, we should read the entity as FormDataMultiPart, then we can get individual parts by name and extract them by their data type.
Response res = target("test").request().get();
FormDataMultiPart multiPart = res.readEntity(FormDataMultiPart.class);
FormDataBodyPart jsonPart = multiPart.getField("json-data");
FormDataBodyPart filePart = multiPart.getField("file-data");
Model jsonData = jsonPart.getValueAs(Model.class);
InputStream file = filePart.getValueAs(InputStream.class);
Below is the complete test.
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataMultiPart;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import static org.assertj.core.api.Assertions.assertThat;
public class MultipartResponseTest extends JerseyTest {
public static class Model {
private String value;
public Model() {}
public Model(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
#Path("test")
public static class TestResource {
#GET
#Produces(MediaType.MULTIPART_FORM_DATA)
public Response get() throws Exception {
final MultiPart multiPart = new FormDataMultiPart()
.field("json-data", new Model("Test Value"), MediaType.APPLICATION_JSON_TYPE)
.bodyPart(new FileDataBodyPart("file-data", new File("test.txt")));
return Response.ok(multiPart).build();
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig()
.register(TestResource.class)
.register(MultiPartFeature.class);
}
#Override
public void configureClient(ClientConfig config) {
config.register(MultiPartFeature.class);
}
#Test
public void testIt() throws Exception {
final Response res = target("test")
.request().get();
FormDataMultiPart multiPart = res.readEntity(FormDataMultiPart.class);
FormDataBodyPart jsonPart = multiPart.getField("json-data");
FormDataBodyPart filePart = multiPart.getField("file-data");
Model jsonData = jsonPart.getValueAs(Model.class);
InputStream file = filePart.getValueAs(InputStream.class);
BufferedReader fileReader = new BufferedReader(new InputStreamReader(file));
String fileData = fileReader.readLine();
file.close();
fileReader.close();
System.out.println(jsonData.getValue());
System.out.println(fileData);
assertThat(jsonData.getValue()).isEqualTo("Test Value");
assertThat(fileData).isEqualTo("Some Test Data in File");
}
}
To use the test framework, you should add the following dependency
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
</dependency>
I have the following DropWizard resource which is supposed to make a Google Cloud Messaging request and return the response. I keep on getting Unauthorized 401 error.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
#Path(value="/gcm")
#Produces(MediaType.APPLICATION_JSON)
public class GcmResource {
Client client;
public GcmResource(Client client) {
this.client = client;
}
#GET
public String sendMsg() {
WebResource r = client.resource("https://android.googleapis.com/gcm/send");
r.header("Authorization", "key=MY_SERVER_API_KEY");
r.accept(MediaType.APPLICATION_JSON);
r.type(MediaType.APPLICATION_JSON);
ClientResponse res = r.post(ClientResponse.class, "{\"registration_ids\":[\"ABC\"]}");
return res.getEntity(String.class);
}
}
I am using a valid API key.
My API key is of type "Server (with IP blocking)".
I have no IPs in the block list. So, all IPs are allowed.
I also ran the above code from my web-hosting server, there too I get the same error.
What am I doing wrong?
Finally I found the bug in the above code. I actually wrote a PHP code to dump all Http request it receives - header and body. I changed the above code to send request to my PHP code instead. That is when I noticed that none of the headers I set were being sent! Then I noticed the bug.
I had assumed that lines like r.header("Authorization", "key=MY_SERVER_API_KEY") actually modify r. I was wrong. They return a new Builder object which has those changes. So, now the below modified version works.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
#Path(value="/gcm")
#Produces(MediaType.APPLICATION_JSON)
public class GcmResource {
Client client;
public GcmResource(Client client) {
this.client = client;
}
#GET
public String sendMsg() {
WebResource r = client.resource("https://android.googleapis.com/gcm/send");
ClientResponse res = r
.header("Authorization", "key=MY_SERVER_API_KEY")
.accept(MediaType.APPLICATION_JSON)
.type(MediaType.APPLICATION_JSON)
.post(ClientResponse.class, "{\"registration_ids\":[\"ABC\"]}");
return res.getEntity(String.class);
}
}
I have a simple WS that is a #PUT and takes in an object
#Path("test")
public class Test {
#PUT
#Path("{nid}"}
#Consumes("application/xml")
#Produces({"application/xml", "application/json"})
public WolResponse callWol(#PathParam("nid") WolRequest nid) {
WolResponse response = new WolResponse();
response.setResult(result);
response.setMessage(nid.getId());
return response;
}
and my client side code is...
WebResource wr = client.resource(myurl);
WolResponse resp = wr.accept("application/xml").put(WolResponse.class, wolRequest);
I am trying to pass an instance of WolRequest into the #PUT Webservice. I am constantly getting 405 errors trying to do this..
How can I pass an object from the client to the server via Jersey ? Do I use a query param or the request ?
Both my POJOs (WolRequest and WolResponse) have the XMlRootElement tag defined so i can produce and consume xml..
I think the usage of the #PathParam is not correct here. A #PathParam is can basically be a String (see its javadoc for more info).
You can
use the #PathParam as a String parameter or
don't define WolRequest as a #PathParam.
The first approach:
#Path("test")
public class Test {
#PUT
#Path("{nid}")
#Consumes("application/xml")
#Produces({"application/xml", "application/json"})
public WolResponse callWol(#PathParam("nid") String nid) {
WolResponse response = new WolResponse();
response.setResult(result);
response.setMessage(nid);
return response;
}
This will accept urls like: "text/12", 12 will then be the String nid. It doesn't look like this will help what you are trying to do.
The second approach:
#Path("test")
public class Test {
#PUT
#Consumes("application/xml")
#Produces({"application/xml", "application/json"})
public WolResponse callWol(WolRequest nid) {
WolResponse response = new WolResponse();
response.setResult(result);
response.setMessage(nid.getId());
return response;
}
Your client code can be like you specified, only the url for PUT is: "test". Perhaps you need a combination of both one #PathParam for your id and one "normal" parameter to get your request data.
Check this link https://www.vogella.com/tutorials/REST/article.html
As per the code sample of method putTodo of class TodoResource ,
your code should be like this.
#Path("test")
public class Test{
#PUT
#Consumes("application/xml")
#Produces({"application/xml", "application/json"})
public WolResponse callWol(JAXBElement<WolRequest> nid) {
WolResponse response = new WolResponse();
response.setResult(result);
response.setMessage(nid.getValue().getId());
return response;
}
}
Hope this will solve your problem.
You can try something like this
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response callWol(WolRequest nid) {
WolResponse response = new WolResponse();
response.setResult(result);
response.setMessage(nid.getValue().getId());
return Response.status(Status.OK).entity(response).build();
}
You can try #PUT instead of #Post as well. Hope this helps
I had the same problem I solved in 3 Steps with Jackson in Netbeans/Glashfish btw.
1)Requirements :
some of the Jars I used :
commons-codec-1.10.jar
commons-logging-1.2.jar
log4j-1.2.17.jar
httpcore-4.4.4.jar
jackson-jaxrs-json-provider-2.6.4.jar
avalon-logkit-2.2.1.jar
javax.servlet-api-4.0.0-b01.jar
httpclient-4.5.1.jar
jackson-jaxrs-json-provider-2.6.4.jar
jackson-databind-2.7.0-rc1.jar
jackson-annotations-2.7.0-rc1.jar
jackson-core-2.7.0-rc1.jar
If I missed any of the jar above , you can download from Maven here http://mvnrepository.com/artifact/com.fasterxml.jackson.core
2)Java Class where you send your Post.
First ,Convert with Jackson the Entity User to Json and then send it to your Rest Class.
import com.fasterxml.jackson.databind.ObjectMapper;
import ht.gouv.mtptc.siiv.model.seguridad.Usuario;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.simple.JSONObject;
public class PostRest {
public static void main(String args[]) throws UnsupportedEncodingException, IOException {
// 1. create HttpClient
DefaultHttpClient httpclient = new DefaultHttpClient();
// 2. make POST request to the given URL
HttpPost httpPost
= new HttpPost("http://localhost:8083/i360/rest/seguridad/obtenerEntidad");
String json = "";
Usuario u = new Usuario();
u.setId(99L);
// 3. build jsonObject
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", u.getId());
// 4. convert JSONObject to JSON to String
//json = jsonObject.toString();
// ** Alternative way to convert Person object to JSON string usin Jackson Lib
//ObjectMapper mapper = new ObjectMapper();
//json = mapper.writeValueAsString(person);
ObjectMapper mapper = new ObjectMapper();
json = mapper.writeValueAsString(u);
// 5. set json to StringEntity
StringEntity se = new StringEntity(json,"UTF-8");
// 6. set httpPost Entity
httpPost.setEntity(se);
// 7. Set some headers to inform server about the type of the content
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
// 8. Execute POST request to the given URL
HttpResponse httpResponse = httpclient.execute(httpPost);
// 9. receive response as inputStream
//inputStream = httpResponse.getEntity().getContent();
}
}
3)Java Class Rest where you want to receive the Entity JPA/Hibernate .
Here with your MediaType.APPLICATION_JSON you recieve the Entity in this way :
""id":99,"usuarioPadre":null,"nickname":null,"clave":null,"nombre":null,"apellidos":null,"isLoginWeb":null,"isLoginMovil":null,"estado":null,"correoElectronico":null,"imagePerfil":null,"perfil":null,"urlCambioClave":null,"telefono":null,"celular":null,"isFree":null,"proyectoUsuarioList":null,"cuentaActiva":null,"keyUser":null,"isCambiaPassword":null,"videoList":null,"idSocial":null,"tipoSocial":null,"idPlanActivo":null,"cantidadMbContratado":null,"cantidadMbConsumido":null,"cuotaMb":null,"fechaInicio":null,"fechaFin":null}"
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.apache.log4j.Logger;
#Path("/seguridad")
public class SeguridadRest implements Serializable {
#POST
#Path("obtenerEntidad")
#Consumes(MediaType.APPLICATION_JSON)
public JSONArray obtenerEntidad(Usuario u) {
JSONArray array = new JSONArray();
LOG.fatal(">>>Finally this is my entity(JPA/Hibernate) which
will print the ID 99 as showed above :" + u.toString());
return array;//this is empty
}
..
Some tips : If you have problem with running the web after using this code may be because of the #Consumes in XML ... you must set it as #Consumes(MediaType.APPLICATION_JSON)
Try this it will work
Server Side:
#PUT
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public String addRecord(CustomClass mCustomClass)
{
///
///
///
return "Added successfully : "+CustomClass.getName();
}// addRecord
Client Side:
public static void main(String[] args)
{
///
///
///
CustomClass mCustomClass = new CustomClass();
Client client = ClientBuilder.newClient();
String strResult = client.target(REST_SERVICE_URL).request(MediaType.APPLICATION_XML).put(Entity.xml(mCustomClass), String.class);
}