get content of http request in REST web service using java - java

Anyone know how to get content of httprequest in REST webservice using java?
thanks

You can inject context about the individual requests. As an example, the code snippet below shows how the HTTP request headers can be injected.
#GET
#Produces{"text/plain"}
public String listHeaderNames(#Context HttpHeaders headers) {
StringBuilder buf = new StringBuilder();
for (String header: headers.getRequestHeaders().keySet()) {
buf.append(header);
buf.append("\n");
}
return buf.toString();
}
See the relevant part of the JAX-RS 1.1 specification for more information.

Look at Restlet
// Create the client resource
ClientResource resource = new ClientResource("http://www.restlet.org");
// Write the response entity on the console
resource.get().write(System.out);

Related

Jersey server, rest api : How to remove the code and type from the response body?

I'm trying to create a Rest Api using Jax-rs Jersey from a base code generated by swagger.
The specifications are for exemple for a specific Request :
Code : 200
Description : User token for login
Schema : String
My problem is that the generated code use the class :javax.ws.rs.core.Response that should not be extended according to the documentation.
I'm using this kind of code to build the response :
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK,apiToken)).build();
The response generated looks like that :
{"code":4,"type":"ok","message":"uHN2cE7REfZz1pD17ITa"}
When i only want to have :"uHN2cE7REfZz1pD17ITa" in the body. Is that possible using Jersey ? Or is this format part of the jax-rs specifications ?
Thank you.
ApiResponseMessage from Swagger does not extend Response from JAX-RS. Check the code and you will see that ApiResponseMessage is just a POJO. That is, the piece of code you posted in your question is just fine.
If you only need the token, you can use:
return Response.ok(apiToken).build();
The following gives you the same result:
return Response.ok().entity(apiToken).build();
Since your resource method will produce just a piece of text (not a valid JSON unless the piece of text is wrapped into quotes), the most suitable media type for the response would be text/plain. It could be achieved by either annotating the resource method with #Produces(MediaType.TEXT_PLAIN) or setting the media type in the response, as following:
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response getToken() {
String apiToken = ...
return Response.ok(apiToken).build();
}
#GET
public Response getToken() {
String apiToken = ...
return Response.ok(apiToken, MediaType.TEXT_PLAIN).build();
}
Alternatively you also could make your method return just a String:
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getToken() {
String apiToken = ...
return apiToken;
}
JAX-RS does not require Request or Response in specific format for text,json, xml, or html fallowing a schema . But They all have to be well formated in according to their specifications.
You can send text response like this in jersey
like this
return Response.ok().entity("uHN2cE7REfZz1pD17ITa").build();
I am new to swagger myself So i don't know if the Response in question can be changed or not . But There is no restriction from jersey side

Produce and Consume data in Java RESTful with Jersey and JSON

Folks,
I am newbie to Java RESTful,
I need to pass the data from my java application to the RESTful service. I am able to add the RESTful to my application but not able to send any data back to the service.
I used #GET and #Consumes at service. Please help me to get connect and data exchange between the same
As RESTful acts as server in my application
RESTful defined
#GET
#Consumes("application/json")
#Path("{strID}")
public String getJson(#PathParam("strID")String strID){
return strID;
}
Imported RESTful method
public String getJson(String strID) throws UniformInterfaceException {
WebResource resource = webResource;
resource = resource.path(java.text.MessageFormat.format("{0}", new Object[]{strID}));
return resource.get(String.class);
}
inside the java application
static RESTful objRFIDService = new RESTful();
objRFIDService.getJson("RESTfultest");
What you are trying to achieve is not really clear. However, to consume a REST webservice, you can use the JAX-RS Client API, which is part of the JAX-RS 2.0 specification and the reference implementation is Jersey.
For instance, to perform a GET request to a resource available in http://example.com/api/foo/{id}, you can use the following code:
String id = ...
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://example.com").path("api").path("foo").path(id);
String result = target.request(MediaType.APPLICATION_JSON_TYPE).get(String.class);
For more details, have a look at the Jersey Client API documentation.

Non-standard HTTP methods and Apache Http Components

I'm writing an HTTP server using the HttpCore library of Apache HTTPComponents 4.3 (Java). My server must be able to receive requests that have non-standard HTTP methods (methods other than GET, POST, DELETE, etc).
But when my server receives such a request, it returns a "method not supported" response. Is there a way to force HTTPComponents to accept non-standard HTTP methods?
Background: I'm working on implementing a WebDAV server, which uses non-standard methods (like MKCOL and PROPFIND).
I found the solution, so I will answer my own question. xD
You have to create your own HttpRequestFactory implementation, and pass it up the chain.
HttpRequestFactory reqFact = new HttpRequestFactory() {
public HttpRequest newHttpRequest(final RequestLine requestline) throws MethodNotSupportedException {
return new BasicHttpEntityEnclosingRequest(requestline);
}
public HttpRequest newHttpRequest(final String method, final String uri) throws MethodNotSupportedException {
return new BasicHttpEntityEnclosingRequest(method, uri);
}
};
HttpMessageParserFactory<HttpRequest> parserFact = new DefaultHttpRequestParserFactory(null, reqFact);
HttpConnectionFactory<DefaultBHttpServerConnection> connFact = new DefaultBHttpServerConnectionFactory(null, parserFact, null)
The implementation that HttpComponents uses by default throws a MethodNotSupportedException if a non-standard HTTP method is found. The source code for the default implementation can be found here:
http://hc.apache.org/httpcomponents-core-4.3.x/httpcore/xref/org/apache/http/impl/DefaultHttpRequestFactory.html

jax-rs Response entity class

I'm trying to create a jax-rs client which posts an xml as object and receives an xml on the response body from the server. The code is as below:
import org.apache.cxf.jaxrs.client.WebClient;
..
TravelRequest tr = ...
..
WebClient client = WebClient.create(url);
client.type(javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE).accept(javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE);
javax.ws.rs.core.Response r = client.post(tr);
Object response = r.getEntity();
The java type of the response object is sun.net.www.protocol.http.HttpURLConnection$HttpInputStream
Is it possible to get an object of TravelRequest type instead of reading the xml from input stream? Someone knows any example of it? I can also use spring to configure my client.
Any help would be appreciated.
This is how it is done.
TravelRequest travelRequest = client.post(tr, TravelRequest.class);
Hope this will help someone.
You are using the WebClient the wrong way. Methods like accept and type dont' alter the WebClient but return the updated Client
So the correct usage is:
WebClient client = WebClient.create(url);
Response response = client.type(...).accept(...).post(tr);
The Response.getEntity() can then be used to extract the response.
CXF supports various forms of data binding that you can use to map the response body to your classes.

Unable to override a response header using a Jersey client filter

I am trying to use the Jersey client API to consume a third-party REST service. I plan to use the automatic POJO deserialisation to go from JSON responses to Java objects.
Unfortunately, the third party service returns the responses using the content type "text/javascript". My Jersey client fails to understand that this should be considered as a JSON object and fails to deserialise the object.
I wrote a simple Jersey server application to verify that by changing the content type from "text/javascript" to "application/json" that the deserialisation works.
Armed with this information, I set about to use a Jersey client filter to modify the response headers. The code comes from a comment by the author of this question. In fact, the question appears to be exactly the same as mine - however the answerer mis-answered the question and shows how to modify the request headers (rather than the response headers). The original author was able to use the answer to create his solution, but, it seems his stated solution fails to work.
The filter code is:
client.addFilter(new ClientFilter() {
#Override public ClientResponse handle(ClientRequest cr)
throws ClientHandlerException {
ClientResponse response = getNext().handle(cr);
response.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
return response;
}
});
When executed however, an UnsupportedOperationException is raised:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.clear(Collections.java:1035)
at com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap.putSingle(StringKeyIgnoreCaseMultivaluedMap.java:78)
at com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap.putSingle(StringKeyIgnoreCaseMultivaluedMap.java:56)
at App$1.handle(App.java:49)
at com.sun.jersey.api.client.Client.handle(Client.java:648)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
at App.main(App.java:63)
The returned headers appear to be wrapped in an unmodifiable collection.
I then attempted to copy all of the headers to a new collection, but there is no way that I can see to set a map of headers back into the response.
Finally, I thought perhaps I can create a new ClientResponse containing my amended headers. However, the constructor for ClientResponse has this signature:
public ClientResponse(int status,
InBoundHeaders headers,
InputStream entity,
MessageBodyWorkers workers)
It is trivial to copy the status, headers and entity variables from the original. However, I can see no way of getting a reference to the workers field.
How can I use a Jersey client filter to modify the response header from "text/javascript" to "application/json" so that my POJO deserialisation will work?
In Jersey 2, register an implementation of a ClientResponseFilter with the ClientConfig in order to manipulate the HTTP headers of incoming responses.
For example, this seems to work well with Jersey 2.3.1 for manipulating HTTP header:
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.client.ClientRequestContext;
import org.glassfish.jersey.client.ClientConfig;
/* Ensure that there is an "application/xml" Content-Type header on
* successful responses without a content type header. */
#Provider
public static class EnsureXmlContentTypeFilter implements ClientResponseFilter {
#Override
public void filter(ClientRequestContext requestContext,
ClientResponseContext responseContext) {
if (200 == responseContext.getStatus() &&
null == responseContext.getHeaderString(HttpHeaders.CONTENT_TYPE)) {
responseContext.getHeaders().add(
HttpHeaders.CONTENT_TYPE, "application/xml"
);
}
}
}
private final ClientConfig config = new ClientConfig()
// Registering this filter adds a "Content-Type: application/xml"
// header to each response that lacks Content-Type headers.
.register(EnsureXmlContentTypeFilter.class)
;
private final Client client = ClientBuilder.newClient(config);
The Jersey documentation on Filters and Interceptors isn't perfect, but it does have some links to the javadocs for the relevant classes: https://jersey.java.net/documentation/latest/filters-and-interceptors.html
I am getting XML responses from a service which responds with XML content, but lacks a "Content-Type: application/xml" header. Probably a better approach would be to register MessageBodyReaders, but the above approach works while I'm playing around with that service's API.
I don't have an answer to your real question, but I think I see how you can get that workers instance if you want to try to create a new response in your filter.
The "workers" object that you need appears to be a singleton. If you can get hold of your com.sun.jersey.api.client.Client instance, you can retrieve the workers object. In my case, the Jersey client code is in a unit test which subclassed JerseyTest. JerseyTest defines a method "client()" which returns the Client object. I added the following test code (well not exactly but close):
MessageBodyWorkers workers = client().getMessageBodyWorkers();
Then I set a breakpoint in the constructor of ClientResponse (this is the original ClientResponse returned by Jersey. I have not attempted to clone it because I don't need to for my test). The workers passed to the constructor was the same instance. So, even though you can not get the workers object from the response object, you should be able to get it elsewhere.
Guido's answer provides the insight required to create a new ClientResponse object and return it instead. For reasons that I've not yet bothered to track down, creating a new InboundHeaders, adding all the existing headers to it, and then modifying the single header in question still fails with an UnsupportedOperationException. As such, to re-write the headers, we iterate over the original headers and build the correct set iteratively:
final Client client = Client.create(clientConfig);
client.addFilter(new ClientFilter()
{
#Override
public ClientResponse handle(ClientRequest cr) throws ClientHandlerException
{
final ClientResponse response = getNext().handle(cr);
final InBoundHeaders headers = new InBoundHeaders();
for (String header : response.getHeaders().keySet())
{
if (header.equals(HttpHeaders.CONTENT_TYPE))
{
headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
else
{
headers.put(header, headers.get(header));
}
}
return new ClientResponse(response.getStatus(),
headers,
response.getEntityInputStream(),
client.getMessageBodyWorkers());
}
}
In Jersey 2, you should use a ClientResponseFilter. Then you can just call responseContext.getHeaders().putSingle(...).
Under Java 8 you can do it with a lambda:
client.register((ClientResponseFilter) (requestContext, responseContext) ->
responseContext.getHeaders().putSingle("Content-Type", "application/json"));
If you want to re-use an existing filter instance, just register it on the Client instead of on the ClientConfig.
Old way (Jersey-1.9):
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
Client client = new Client();
client.addFilter(new HTTPBasicAuthFilter(username, password));
New way (Jersey-2.3):
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import org.glassfish.jersey.client.filter.HttpBasicAuthFilter;
Client client = ClientBuilder.newClient();
client.register(new HttpBasicAuthFilter(username, password));
That's not the best solution, but it may help you to migrate.

Categories