Combining verbs in Apache CXF JAX-RS - rest

We would usually define POST and PUT verbs as different service APIs.
#POST
#Path("/getbook")
#Produces({"application/xml","application/json"})
#Consumes({"application/xml","application/json","application/x-www-form-urlencoded"})
public Response getBucket() {
... }
#PUT
#Path("/getbook/{name}")
#Produces({"application/xml","application/json"})
#Consumes({"application/xml","application/json","application/x-www-form-urlencoded"})
public Response getBucket(#PathParam("name") String name) {
... }
Would there be a way to combine these verbs into a single method - and then drive different logic based on the type of the verb ?
Hypothetically
#POST
#PUT
#Path("/getbook/{name}")
#Produces({"application/xml","application/json"})
#Consumes({"application/xml","application/json","application/x-www-form-urlencoded"})
public Response getBucket(#PathParam("name") String name) {
if(verb=POST){
... }
else{
}
}

You may try like this using MessageContext. You need the context injected into the service method like below for updateCustomer method and then you can check for the method type as you like (here I am checking for PUT):
#Path("/customer")
public class CustomerService {
#Context
private org.apache.cxf.jaxrs.ext.MessageContext mc;
#PUT
public Response updateCustomer(#Context MessageContext context, Customer c) {
HttpServletRequest request = context.getHttpServletRequest();
boolean isPut = "PUT".equals(request.getMethod());
}
}

Related

How to get the url of called method resteasy

I making one Rest Service with Restaeasy (java) that have to return the same URL that was called but with one new string
Example Call service:
Post => mybase/myservice/somewrite with some JSON
| Reponse => mybase/myservice/somewrite/123456
So i want to make the mybase/myservice/somewrite url with one generic logic, because if i put String returnURL="mybase/myservice/somewrite"; and i change for example the name of mybase the reponse will not be good
I want somthing like this
someLogicService(JSON);
id=getId();
URL=getContextCallURL();
return URL+\/+id;
But i dont know if this is possible to do it, and less how to do it
You could also inject an instance of type UriInfo using the annotation Context within your resource, as described below:
#Context
private UriInfo uriInfo;
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
public Response makeContact(Contact contact) {
String requestUri = uriInfo.getRequestUri();
(...)
}
Hope it helps you,
Thierry
I found the answer to my problem, i put inject with #context the httpRequest to my function and call absolutPath :
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
public Response makeContact(Contact contact, #Context HttpRequest request) {
return Response.ok().header("location", request.getUri().getAbsolutePath().getPath() + contactService.makeContact(contactJSON)).build();
}

JEE6 REST Service #AroundInvoke Interceptor is injecting a null HttpServletRequest object

I have an #AroundInvoke REST Web Service interceptor that I would like to use for logging common data such as the class and method, the remote IP address and the response time.
Getting the class and method name is simple using the InvocationContext, and the remote IP is available via the HttpServletRequest, as long as the Rest Service being intercepted includes a #Context HttpServletRequest in its parameter list.
However some REST methods do not have a HttpServletRequest in their parameters, and I can not figure out how to get a HttpServletRequest object in these cases.
For example, the following REST web service does not have the #Context HttpServletRequest parameter
#Inject
#Default
private MemberManager memberManager;
#POST
#Path("/add")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Member add(NewMember member) throws MemberInvalidException {
return memberManager.add(member);
}
I have tried injecting it directly into my Interceptor, but (on JBoss 6.1) it is always null...
public class RestLoggedInterceptorImpl implements Serializable {
#Context
HttpServletRequest req;
#AroundInvoke
public Object aroundInvoke(InvocationContext ic) throws Exception {
logger.info(req.getRemoteAddr()); // <- this throws NPE as req is always null
...
return ic.proceed();
I would like advice of a reliable way to access the HttpServletRequest object - or even just the Http Headers ... regardless of whether a REST service includes the parameter.
After researching the Interceptor Lifecycle in the Javadoc http://docs.oracle.com/javaee/6/api/javax/interceptor/package-summary.html I don't think its possible to access any servlet context information other than that in InvocationContext (which is defined by the parameters in the underlying REST definition.) This is because the Interceptor instance has the same lifecycle as the underlying bean, and the Servlet Request #Context must be injected into a method rather than the instance. However the Interceptor containing #AroundInvoke will not deploy if there is anything other than InvocationContext in the method signature; it does not accept additional #Context parameters.
So the only answer I can come up with to allow an Interceptor to obtain the HttpServletRequest is to modify the underlying REST method definitons to include a #Context HttpServletRequest parameter (and HttpServletResponse if required).
#Inject
#Default
private MemberManager memberManager;
#POST
#Path("/add")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Member add(NewMember member, #Context HttpServletRequest request, #Context HttpServletResponse response) throws MemberInvalidException {
...
}
The interceptor can then iterate through the parameters in the InvocationContext to obtain the HttpServletRequest
#AroundInvoke
public Object aroundInvoke(InvocationContext ic) throws Exception {
HttpServletRequest req = getHttpServletRequest(ic);
...
return ic.proceed();
}
private HttpServletRequest getHttpServletRequest(InvocationContext ic) {
for (Object parameter : ic.getParameters()) {
if (parameter instanceof HttpServletRequest) {
return (HttpServletRequest) parameter;
}
}
// ... handle no HttpRequest object.. e.g. log an error, throw an Exception or whatever
Another work around to avoid creating additional parameters in every REST method is creating a super class for all REST services that use that kind of interceptors:
public abstract class RestService {
#Context
private HttpServletRequest httpRequest;
// Add here any other #Context fields & associated getters
public HttpServletRequest getHttpRequest() {
return httpRequest;
}
}
So the original REST service can extend it without alter any method signature:
public class AddService extends RestService{
#POST
#Path("/add")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Member add(NewMember member) throws MemberInvalidException {
return memberManager.add(member);
}
...
}
And finally in the interceptor to recover the httpRequest:
public class RestLoggedInterceptorImpl implements Serializable {
#AroundInvoke
public Object aroundInvoke(InvocationContext ic) throws Exception {
// Recover the context field(s) from superclass:
HttpServletRequest req = ((RestService) ctx.getTarget()).getHttpRequest();
logger.info(req.getRemoteAddr()); // <- this will work now
...
return ic.proceed();
}
...
}
I'm using Glassfish 3.1.2.2 Jersey
For http header this works for me:
#Inject
#HeaderParam("Accept")
private String acceptHeader;
To get UriInfo you can do this:
#Inject
#Context
private UriInfo uriInfo;

Jaxb in Restful webservices

I have worked on Web services using Jaxb earlier. I geneated Java from xsd, and then I used to post the xml request to the specified URL using HTTP post. Recently I heard about this Restful web services, on reading I felt that what I had been doing earlier is the restful web service only. But, I am not sure about it if its the same thing.
Can anyone explain please.
It sounds like you have been creating the same types of RESTful services. You may be referring to is JAX-RS with is a standard that defines an easier way of creating RESTful services where JAXB is the standard binding layer for the application/xml media type. Below is an example service:
package org.example;
import java.util.List;
import javax.ejb.*;
import javax.persistence.*;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
#Stateless
#LocalBean
#Path("/customers")
public class CustomerService {
#PersistenceContext(unitName="CustomerService",
type=PersistenceContextType.TRANSACTION)
EntityManager entityManager;
#POST
#Consumes(MediaType.APPLICATION_XML)
public void create(Customer customer) {
entityManager.persist(customer);
}
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("{id}")
public Customer read(#PathParam("id") long id) {
return entityManager.find(Customer.class, id);
}
#PUT
#Consumes(MediaType.APPLICATION_XML)
public void update(Customer customer) {
entityManager.merge(customer);
}
#DELETE
#Path("{id}")
public void delete(#PathParam("id") long id) {
Customer customer = read(id);
if(null != customer) {
entityManager.remove(customer);
}
}
}
For More Information
http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-45.html
When it comes to say 'RESTful', it's just an convention of HTTP methods and url patterns.
CRUD METHOD URL RESPONSE DESCRIPTION
----------------------------------------------------------------
CREATE POST http://www.doma.in/people 202 Creates a new person with given entity body
READ GET http://www.doma.in/people 200
READ GET http://www.doma.in/people/1 200 404 Reads a single person
UPDATE PUT http://www.doma.in/people/2 204 Updates a single person with given entity body
DELETE DELETE http://www.doma.in/people/1 204 Deletes a person mapped to given id(1)
You can even implement those kind of contracts with Sevlets. Actually I had done with Sevlets before the era of JAX-RS.
And your life will be much more easier when you use JAX-RS.
Here comes a slightly modified version of Mr. Blaise Doughan's.
Nothing's wrong with Mr. Blaise Doughan's code.
I just want to add more for above url patterns.
One of great things that JAX-RS can offer is that you can serve XMLs and JSONs as clients want if you have those fine JAXB classes. See #Producess and #Consumess for those two formats in same method.
When client want to receive as XML with Accept: application/xml, they just get the XML.
When client want to receive as JSON with Accept: application/json, they just get the JSON.
#Path("/customers");
public class CustomersResource {
/**
* Reads all person units.
*/
#POST
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response read() {
final List<Customer> listed = customerBean.list();
final Customers wrapped = Customers.newInstance(listed);
return Response.ok(wrapped).build();
}
#POST
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response createCustomer(final Customer customer) {
entityManager.persist(customer);
return Response.created("/" + customer.getId()).build();
}
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/{id: \\d+}")
public Response read(#PathParam("id") final long id) {
final Customer customer = entityManager.find(Customer.class, id);
if (customer == null) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok(customer).build();
}
#PUT
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public void updateCustomer(final Customer customer) {
entityManager.merge(customer);
}
#DELETE
#Path("/{id: \\d+}")
public void deleteCustomer(#PathParam("id") final long id) {
final Customer customer = entityManager.find(Customer.class, id);
if (customer != null) {
entityManager.remove(customer);
}
return Response.status(Status.NO_CONTENT).build();
}
}
Say you want to serve some images?
#GET
#Path("/{id: \\d+}")
#Produces({"image/png", "image/jpeg"})
public Response readImage(
#HeaderParam("Accept") String accept,
#PathParam("id") final long id,
#QueryParam("width") #DefaultValue("160") final int width,
#QueryParam("height") #DefaultValue("160") final int height) {
// get the image
// resize the image
// make a BufferedImage for accept(MIME type)
// rewrite it to an byte[]
return Response.ok(bytes).build();
// you can event send as a streaming outout
return Response.ok(new StreamingOutput(){...}).build();
}

How to access multiple resources in a single request : Jersey Rest

I am trying to a find a good design for the following scenario.
I have a POST rest service which will be given an array of services as data. And which should in turn be calling them one by one to aggregate results on the server and send them back to the client.
#Path("/resource1")
#Path("/resource2")
#Path("/collection")
Post data to /collection
{["serviceName": "resource1", "data":"test1"], ["serviceName":"resource2","data":"test2"]}
The reason i need the resource1 and resource2 are, because those services can be called standalone also. I want to reuse the same setup if possible.
Is there any way to do this.
I am using jersey with spring.
Not sure what these resources have in common. If the post method has the same signature for all of them, you could have an abstract class or interface they implement defining the post method and can try using ResourceContext.matchResource to do this. E.g. something like this:
public abstract class AbstractResource {
public abstract String post(Object data);
}
#Path("/resource1")
public class Resource1 extends AbstractResource {
#POST
public String post(String data) {
// do something
}
}
#Path("/collection")
public class CollectionResource {
#Context
private ResourceContext rc;
#POST
#Consumes("application/json")
public String post(List<PostRequest> postRequests) {
StringBuilder result = new StringBuilder();
for (PostRequest pr : postRequests) {
// should wrap this in try-catch
AbstractResource ar = rc.matchResource(pr.resource,
AbstractResource.class);
sb.append(ar.post(pr.data));
}
return result.toString();
}
}
#XmlRootElement
public class PostRequest {
public String resource;
public String data;
}
Hopefully you got the idea and will be able to play with it and tweak it to fit your needs.

How do I access the HTTP request?

Say normally I have a REST method in Java
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(#FormParam("username") String userName) {
:
:
:
}
which is fine. However, I'm wondering is there a way I can access the full HTTP request with Jersey such as
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(#FormParam("username") String userName,#XXXXXX String httpRequest) {
:
:
:
}
where some annotation would give me the full HTTP request to store in a variable. I have tried using #POST but it doesn't seem to work. Any suggestions?
You can use the #Context annotation:
#POST
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
public String showTime(
#FormParam("username") String userName,
#Context HttpServletRequest httpRequest
) {
// The method body
}
If you want to get the request body, you could use the tip lined out in this post: How to get full REST request body using Jersey?
If you need to know more about the request itself, you could try the #Context annotation as mentioned by sdorra.
I wrote a helper function to address this. Simply extracts request headers and places them in a map.
private Map<String, String> extractHeaders(HttpServletRequest httpServletRequest) {
Map<String, String> map = new HashMap<>();
Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
map.put(header, httpServletRequest.getHeader(header));
}
return map;
}