Jersey: Print the actual request - java

How can I view the actual request that Jersey generates and sends to the server? I am having issues with a particular request and the fellow running the webserver asked to see the full request (with headers and the such).

If you're just using Jersey Client API, LoggingFilter (client filter) should help you:
Client client = Client.create();
client.addFilter(new LoggingFilter(System.out));
WebResource webResource = client.resource("http://localhost:9998/");
ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON)
.get(ClientResponse.class);
Otherwise, you can again log both request and response on server using other LoggingFilter (container filter).

Since Jersey 2.23, there's a LoggingFeature you could use. The following is a bit simplified example, please note that you can register the feature on WebTarget as well.
Logger logger = Logger.getLogger(getClass().getName());
Feature feature = new LoggingFeature(logger, Level.INFO, null, null);
Client client = ClientBuilder.newBuilder()
.register(feature)
.build();
Response response = client.target("https://www.google.com")
.queryParam("q", "Hello, World!")
.request().get();
JavaDoc of LoggingFeature says that the request "and/or" the response is logged lol. On my machine, both are logged.

#ivan.cikic's answer is for Jersey 1.x. Here's how you do it in Jersey 2.x:
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.filter.LoggingFilter;
import org.json.JSONException;
import org.json.JSONObject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
...
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
client.register(new LoggingFilter());
This is irrelevant but I just have to complain: The new LoggingFilter is really annoying because it forces you to use Java Util Logging. It would be better if it gave me control over the logger. Seems like a step backwards in design.

All these answers are pretty close but they lack the setting to log the request and response body. At least with Jersey 2.30.1 this is how I accomplish logging the request and response including their respective bodies:
import javax.ws.rs.client.ClientBuilder;
import org.glassfish.jersey.logging.LoggingFeature;
import java.util.logging.Level;
import java.util.logging.Logger;
Logger logger = Logger.getLogger("LoggingFeature");
logger.setLevel(Level.ALL);
ClientBuilder.newClient()
.target("https://www.example.com")
.register(new LoggingFeature(
logger,
Level.ALL,
LoggingFeature.Verbosity.PAYLOAD_ANY,
8192))
.request()
.get();
Technically the Level.All and 8192 values could be null. I just provide them here to be concise.

Related

I need to send an empty Queryparam to my rest client

im using java/maven with microprofile to develop an api that will return information of a service that have #Queryparams, but the problem is that the provider of this service need that i sent an empty #Queryparam, like this emptyquery:
https://example.com/reports/server?emptyquery&report=12345
my client code is this:
package ca.com.td.woody.svc.client;
import ca.com.td.woody.svc.provider.UnknownUrlExceptionMapper;
import java.io.InputStream;
import java.net.URL;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
#RegisterRestClient()
#RegisterProvider(UnknownUrlExceptionMapper.class)
public interface IGuateFacturasClient {
#GET
#Produces("application/pdf")
InputStream getBill(
#QueryParam("emptyquery") String emptyquery,
#QueryParam("report") String report
);
}
And when i try to execute this client i use this command to do that:
InputStream inputStream = invoiceClient.getBill( null ,"12345");
But, doesnt matter what i sent, always the client says that the empty query is not empty.
What could i do?

Overwrite HTTP Header in CXF (JAX-RS)

I would like to change the value of the HTTP Header "Connection" before sending a reply from the Server to the Client.
My Use Case: I have a JAX-RS Web Service that sits behind a Load Balancer. The Web Service Client sends requests with "Connection: Keep-Alive". Result: The connection is kept open, the Load Balancer does not balance :-)
So I would like my Web Service to reply every few hundred requests with a "Connection: close" to force the Client to open a new connection.
How can I do this with CXF?
You can use a ContainerResponseFilter to add your desired header to the response sent.
An example:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.Provider;
#Provider
public class ResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.putSingle("Connection", "close");
}
}
Declare this class as a Provider in your javax.ws.rs.core.Application.

Delete rest with parameters

I need to write this REST request in java using Httpdelete or any other library.
curl -X DELETE -d '{"ruleid":"1" }' http://192.168.1.1:8080/wm/acl/rules/json
I couldn't find a way to parse the Json data !
Thanks for your help !
Like others said, it is unusual that a DELETE request contains a body. But it is not strictly impossible as long as the server supports it.
There are many ways to build a REST Client in Java (see https://stackoverflow.com/a/5024571/1018443). A common way is to use Jersey 2.
In Jersey 2, the .delete() method does not contain a parameter for the body entity. But you can use .build to create a DELETE request with a body. Here is an example:
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
public class RestClient {
public static void main(String[] args) {
Model model = new Model();
ClientConfig config = new ClientConfig();
config.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://192.168.1.1:8080/");
String response = target
.path("wm/acl/rules/json")
.request(MediaType.APPLICATION_JSON)
.build("DELETE", Entity.entity(model, MediaType.APPLICATION_JSON))
.invoke(String.class);
System.out.println(response);
}
private static class Model {
public int ruleid = 1;
}
}
Note that you need to configure the client with Property ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION = true. Otherwise you get an Exception: Entity must be null for http method DELETE.
You will find many examples on how to build a Java REST client with Jersey. For example: https://howtodoinjava.com/jersey/jersey-restful-client-examples/
You have to use POST request instead of DELETE, because body of DELETE request is ignored.
From spec:
The DELETE method requests that the origin server delete the resource identified by the Request-URI
reference link

Upgrading from Jersey Client 1.x to Jersey Client 2.x

I am using jersey-client-1.9. sample code:
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
Client client = Client.create();
webResource = client.resource("http://localhost:8047/storage/hive.json");
String input = //rest request
ClientResponse response = webResource.type("application/json").post(ClientResponse.class, input);
String queryRespose = response.getEntity(String.class);
As this project has changed from com.sun.jersey.api.client to org.glassfish.jersey.client. How to achieve this in jersey-client-2.8 ?
Edit:
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8047/query.json");
String input =//rest request
Response response = target.request().post(Entity.json(input));
String queryRespose = response.readEntity(String.class);
This worked...:)
With Jersey 2.x, you can build the Client with ClientBuilder
Client client = ClientBuilder.newClient();
In Jersey 2.x WebTarget is analogous to Jersey 1.x WebResource, and instead of calling client.resource() to get the WebResource, you call client.target() to get the WebTarget
WebTarget target = client.target(url);
Then you need to call request() on the WebTarget to get an Invocation.Builder, which will allow you to chain other calls
Invocation.Builder invocation = target.request();
To send an entity, we need to pass an Entity to one of the Invocation.Builder's request method. For instance
Response response = builder.post(Entity.json(input);
To read the response, use response.readEntity(String.class). So altogether, you can do
Client client = ClientBuilder.newClient();
WebTarget target = client.target(url);
Response response = target.request().post(Entity.json(input));
String entity = response.readEntity(String.class);
See Also:
how to send json object from REST client using javax.ws.rs.client.WebTarget
Client API documentation
UPDATE
You may also need the following dependency for JSON/POJO support
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
Then register the JacksonFeature with the client. This is so input (if you want to use a POJO instead of String) can be serialized to JSON
client.register(JacksonFeature.class);

How do I get the Source IP of a SOAP requesting client machine?

how do you get source ip, username, password, etc... of the client machine that sends a soap request? is there any of these details that one can pull for logging purposes?
I am using Java to handle the incoming SOAP requests. The service simply adds 2 numbers and is working, but I just need to get some client details.
Thanks, Lavanya
If you're using JAX-WS, inject a WebServiceContext like so:
import javax.annotation.Resource
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
#WebService()
public class Test
{
#Resource WebServiceContext context;
#WebMethod(operationName = "getInfo")
public String getInfo()
{
HttpServletRequest request = (HttpServletRequest)context.getMessageContext().get(MessageContext.SERVLET_REQUEST);
return "IP: "+request.getRemoteAddr()+", Port: "+request.getRemotePort()+", Host: "+request.getRemoteHost();
}
}
Will return something like:
IP: 127.0.0.1, Port: 2636, Host: localhost
Look at the API for the rest of the methods. Basically, once you have your HttpServletRequest object, the rest is pretty easy.
I have figured the solution like below -
#Endpoint
public class DataEndpoints {
....
....
private HttpServletRequest httpServletRequest;
#Autowired
public void setRequest(HttpServletRequest request) {
this.httpServletRequest = request;
}
#PayloadRoot(namespace = employeeNS, localPart = "syncRelation")
#ResponsePayload
public SyncRelationResponse dataSync(#RequestPayload SyncOrderRelation request) {
String incoming = "IP Address -> " + this.httpServletRequest.getRemoteAddr();
}
}
By using the following method, I can directly access HttpServletRequest. And then I can access all data i need.
I hope it will help someone in this context.
I am not surte I fully understand your idea of getting username and password of client machine.
In general with Soap look at Soap Header, they are supposed to carry the authentication information (which could be username, password or some kind of security toke).
For the IP, your Soap is coming over Http and therefore when you receive your request you can try and look at your Http headers to see what information it gives you. Though I have never tried to get the IP of the client from it, but it might be there in the HTTP header
What soap stack are u using. If u deployed it as a war file using axis it is pretty easy to do it. u need to get hold of the httprequestobject and call the HTTPServletRequest.getRemoteAddr() method on it.

Categories