I'm currently using Jersey as a proxy REST api to call another RESTful web service. Some of the calls will be passed to and from with minimal processing in my server.
Is there a way to do this cleanly? I was thinking of using the Jersey Client to make the REST call, then converting the ClientResponse into a Response. Is this possible or is there a better way to do this?
Some example code:
#GET
#Path("/groups/{ownerID}")
#Produces("application/xml")
public String getDomainGroups(#PathParam("ownerID") String ownerID) {
WebResource r = client.resource(URL_BASE + "/" + URL_GET_GROUPS + "/" + ownerID);
String resp = r.get(String.class);
return resp;
}
This works if the response is always a success, but if there's a 404 on the other server, I'd have to check the response code. In other words, is there clean way to just return the response I got?
There is no convenience method as far as I am aware. You can do this:
public Response getDomainGroups(#PathParam("ownerID") String ownerID) {
WebResource r = client.resource(URL_BASE + "/" + URL_GET_GROUPS + "/" + ownerID);
ClientResponse resp = r.get(ClientResponse.class);
return clientResponseToResponse(resp);
}
public static Response clientResponseToResponse(ClientResponse r) {
// copy the status code
ResponseBuilder rb = Response.status(r.getStatus());
// copy all the headers
for (Entry<String, List<String>> entry : r.getHeaders().entrySet()) {
for (String value : entry.getValue()) {
rb.header(entry.getKey(), value);
}
}
// copy the entity
rb.entity(r.getEntityInputStream());
// return the response
return rb.build();
}
for me answer from Martin throw:
JsonMappingException: No serializer found for class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream
Change from
rb.entity(r.getEntityInputStream());
to
rb.entity(r.getEntity(new GenericType<String>(){}));
helped.
Related
I recently encountered some problems with java.net.http.HttpClient that comes with JDK 11. I don't know how to use file upload. Found the ofInputStream() in java.net.http.BodyPublishers. I don't know if I using this method file upload.
Here are the examples I wrote.
public HttpResponse<String> post(String url, Supplier<? extends InputStream> streamSupplier, String... headers) throws IOException, InterruptedException {
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers(headers)
.POST(null == streamSupplier ?
HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofInputStream(streamSupplier));
HttpRequest request = builder.build();
log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(), request.uri().toString());
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
The HttpRequest type provide factory method for creating request publisher for handling body type such as file:
HttpRequest.BodyPublishers::ofFile(Path)
You can update your method:
public HttpResponse<String> post(String url, Path file, String... headers) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers(headers)
.POST(null == file ? HttpRequest.BodyPublishers.noBody() :
HttpRequest.BodyPublishers.ofFile(file))
.build();
log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(),
request.uri().toString());
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
The java.net.http.HttpClient handles bytes supplied through the BodyPublisher as raw body data, without any interpretation. Whether you use HttpRequest.BodyPublishers::ofFile(Path) or HttpRequest.BodyPublishers::ofByteArray(byte[]) is therefore semantically irrelevant: what changes is simply how the bytes that will be transmitted are obtained.
In case of file upload - your server probably expects that the request body will be formatted in certain ways. It might also expect some specific headers to be transmitted with the request (such as Content-Type etc). The HttpClient will not do that magically for you. This is something you need to implement at the caller level.
you may use the method by:
public void uploadLocalFileToRemote(String notEncodedUrlStr, String remoteFilename, String localSourceDir, String localFilename) {
Path sourcePath = Path.of(localSourceDir, localFilename);
if(!sourcePath.toFile().canRead())
{
System.err.println("please check the local file existance/readability: " + sourcePath.toAbsolutePath());
return;
}
FileInputStream ins = null;
try {
ins = new FileInputStream(sourcePath.toFile());//FileNotFoundException extends IOException
BufferedInputStream buf_ins = new BufferedInputStream(ins);
Supplier<? extends InputStream> streamSupplier = new Supplier<BufferedInputStream>() {
#Override
public BufferedInputStream get() {
return buf_ins;
}
};
//HttpResponse<String> response = post(notEncodedUrlStr, streamSupplier,
HttpResponse<String> response = post(notEncodedUrlStr, () -> buf_ins,
"User-Agent", "Java 11 HttpClient Bot", "Content-type", "application/octet-stream",
"accept", "*/*", "fileName", remoteFilename);
// print response:
System.out.println(response.version().name() + " " + response.statusCode());
// print response headers
HttpHeaders headers = response.headers();
headers.map().forEach((k, v) -> System.out.println(k + ":" + v));
// print response body
String body = response.body();
System.out.println(body);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
another consideration is how your server side is implemented. here assume the server side will using http 1.1 "chunked". and configured a directory for remoteFilename.
I am trying to do a java rest web service using "POST" method.But i am unable to access the passed parameter. Here is my client part to invoke the web service.
public static void main(String[] args) {
try {
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/wsRevDash/rest/post/testing");
Form form=new Form();
form.add("sc","pqr");
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class,form);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
And here is my java rest web service.
#POST
#Path("testing")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String createDataInJSON(#FormParam("sc") String data) {
System.out.println("Hello"+data);
JSONObject jObjDevice = new JSONObject();
jObjDevice.put("Hello",data);
return jObjDevice.toJSONString();
}
When i run on SoapUI,I am getting {"Hello":null}.
Please suggest me some way to cope with this.
Try changing form to a String:
String input = new Gson().toJson(form);
And pass in input to the response:
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class,input);
And amend your web service to something like:
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
public Response createDataInJSON(String data) {
String result = "Hello: " + data;
return Response.status(200).entity(result).build();
}
And you need to remove 'testing' from your initial path:
WebResource webResource = client.resource("http://localhost:8080/wsRevDash/rest/post/testing"); <---- here
And include a slash before it in the web service:
#Path("/testing")
I am just new to JAX-RS. When I Use query params with post request in the client it is returning null values. Here is my code.
Resource WebService Code:
#Path("/user")
public class JSONService {
#POST
#Path("/add")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public Response addUser(
#QueryParam("name") String name,
#QueryParam("age") int age) {
return Response.status(200).entity("addUser is called, name : " + name + ", age : " + age).build();
}
}
client code:
try {
Client client = Client.create();
WebResource webResource = client.resource("http://localhost:8080/simpleweb/rest/user").path("/add");
MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
queryParams.add("name", "arunkumar");
queryParams.add("age", "25");
ClientResponse response = webResource.type(MediaType.APPLICATION_FORM_URLENCODED).post(ClientResponse.class,queryParams);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
String output = response.getEntity(String.class);
System.out.println("============getCtoFResponse============");
System.out.println(output);
} catch (Exception e) {
e.printStackTrace();
}
}
The OutPut is :
============getCtoFResponse============
addUser is called, name : null, age : 0
Please Help me in this issue.Thanks
Use #FormParam instead of #QueryParam. The latter is for query string key/value pairs that go in the URL, e.g. /url?name=blah&age=2. #FormParam is for application/x-www-form-urlencoded entity data, which is what you're trying to send
I am using RestFul Webservice with JBoss Server to deploy the app to receive the JSONObject to my web service ,to test that i have created the web service and written test cases for it .Now i got hung up in passing the JSONobject from test case to web services , when i pass the json object to #post service calls it responses that Null Pointer Exception , even i have tried with passing string to it it responds null values.
I have used Annotations as follows in webservice
#consumes({Mediatype.APPLICATION_JSON})
#Consumes("application/json")
Test case As:
#Test
public void testgetmsg() {
String msg = "{\"patient\":[{\"id\":\"6\",\"title\":\"Test\"}]}";
try {
JSONObject obj = new JSONObject(new JSONTokener(msg));
WebResource resource = client.resource( "https://localhost:8443/../../resources/create");
ClientResponse response = resource.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).
entity(obj).post(ClientResponse.class,JSONObject.class);
}
}
can any body guide me to proceed further ?
Thanks in Advance
You don't need to create the json object, you can just pass the string.
you should
ClientResponse response = resource.type(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.post(ClientResponse.class, msg);
//CLIENT
public static void createStudent() {
String input = "{\"id\":12,\"firstName\":\"Fade To Black\",\"lastName\":\"Joy\"}";
ClientResponse response = service.path("class/post")
.type("application/json").post(ClientResponse.class, input);
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output);
System.out.println(response.getStatus()+ "OK");
}
Instead of using code client you can use add on firefox (POSTER) to passing value as json or formparam...
// create new student SERVER
//class
#POST
#Path("post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createStudent(Student st) {
// add new student
StudentDAO.instance.getModelStudent().put("8", st);
// response status code
return Response.status(200).entity(st).build();
}
I've created a rest api using Jersey/Jackson and it works well. I want to adjust my POST methods to receive a string token in addition to the POJO they are receiving as JSON. I've adjusted one of my methods like so:
#POST
#Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(User o, String token) {
System.out.println("token: " + token);
String password = Tools.encryptPassword(o.getPassword());
o.setPassword(password);
String response = DAL.upsert(o);
return Response.status(201).entity(response).build();
}
I want to call that method, but for whatever reason token prints to null no matter what I try. Here is the client code I've written to send the post request:
public String update() {
try {
com.sun.jersey.api.client.Client daclient = com.sun.jersey.api.client.Client
.create();
WebResource webResource = daclient
.resource("http://localhost:8080/PhizzleAPI/rest/post/user");
User c = new User(id, client, permission, reseller, type, username,
password, name, email, active, createddate,
lastmodifieddate, token, tokentimestamp);
JSONObject j = new JSONObject(c);
ObjectMapper mapper = new ObjectMapper();
String request = mapper.writeValueAsString(c) + "&{''token'':,''"
+ "dog" + "''}";
System.out.println("request:" + request);
ClientResponse response = webResource.type("application/json")
.post(ClientResponse.class, request);
if (response.getStatus() != 201) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
setId(UUID.fromString(output));
System.out.println("output:" + output);
return "" + output;
} catch (UniformInterfaceException e) {
return "failue: " + e.getMessage();
} catch (ClientHandlerException e) {
return "failue: " + e.getMessage();
} catch (Exception e) {
return "failure: " + e.getMessage();
}
}
Any help would be greatly appreciated.
This is not the way JAX-RS works. The body of your POST request will get marshaled to the first argument of your annotated resource method (in this case, into the User argument). You have a couple options to get around this:
Create a wrapper object containing both a User object and token. Send that back and forth between your client and server.
Specify the token as a query parameter on your URL and access it on the server side as a #QueryParam.
Add the token as a header parameter and access it on the server side as a #HeaderParam.
Example - Option 1
class UserTokenContainer implements Serializable {
private User user;
private String token;
// Constructors, getters/setters
}
Example - Option 2
Client:
WebResource webResource = client.
resource("http://localhost:8080/PhizzleAPI/rest/post/user?token=mytoken");
Server:
#POST
Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(#QueryParam("token") String token, User o) {
System.out.println("token: " + token);
// ...
}
Example - Option 3
Client:
ClientResponse response = webResource
.type("application/json")
.header("Token", token)
.post(ClientResponse.class, request);
Server:
#POST
Path("/user")
#Consumes(MediaType.APPLICATION_JSON)
public Response createObject(#HeaderParam("token") String token, User o) {
System.out.println("token: " + token);
// ...
}
In case you're using Jersey 1.x, best approach is to post multiple objects as #FormParam
At least two advantages:
You don't need to use a wrapper object to post multiple parameters
The parameters are sent within the body rather than in the url (as with #QueryParam and #PathParam)
Check this example:
Client: (pure Java):
public Response testPost(String param1, String param2) {
// Build the request string in this format:
// String request = "param1=1¶m2=2";
String request = "param1=" + param1+ "¶m2=" + param2;
WebClient client = WebClient.create(...);
return client.path(CONTROLLER_BASE_URI + "/test")
.post(request);
}
Server:
#Path("/test")
#POST
#Produces(MediaType.APPLICATION_JSON)
public void test(#FormParam("param1") String param1, #FormParam("param2") String param2) {
...
}