Getting Conflicting URI templates errors when trying to add resource class - rest

I have a restfull implementation using Jersey and Tomcat7. I have 3 resources called RegionService, ClientService and NoteService defined in my campher.rest package.
When I try to add another resource called TestResource, and Tomcat starts, it gives me the following error below. I don't understand how /{notes} conflicts with /{test}??
Please help, my hair will thank you.
Aug 22, 2012 2:23:39 AM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class campher.rest.NoteService
class campher.rest.ClientService
class campher.rest.TestResource
class campher.rest.RegionService
Aug 22, 2012 2:23:39 AM com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
Aug 22, 2012 2:23:40 AM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
INFO: Initiating Jersey application, version 'Jersey: 1.12 02/15/2012 04:51 PM'
Aug 22, 2012 2:23:40 AM com.sun.jersey.spi.inject.Errors processErrorMessages
SEVERE: The following errors and warnings have been detected with resource and/or provider classes:
SEVERE: Conflicting URI templates. The URI template /{test} for root resource class campher.rest.TestResource and the URI template /{notes} transform to the same regular expression /([^/]+?)(/.*)?
Aug 22, 2012 2:23:40 AM org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
Here are the skeleton implementations of those 4 services.
package campher.rest;
#Path("regions")
public class RegionService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response regions() {}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Region addRegion(Region region){}
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public Region updateRegion(Region region){}
#GET #Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getRegion(#PathParam("id") long id) {}
#DELETE #Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response deleteRegion(#PathParam("id") long id) {}
#GET #Path("{id}/clients")
#Produces(MediaType.APPLICATION_JSON)
public Response getClients(#PathParam("id") long id) {}
}
package campher.rest;
#Path("clients")
public class ClientService {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response clients() {}
#GET #Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getClient(#PathParam("id") long id) {}
#GET #Path("{id}/notes")
#Produces(MediaType.APPLICATION_JSON)
public Response getNotes(#PathParam("id") long id) {}
#GET #Path("{id}/alerts")
#Produces(MediaType.APPLICATION_JSON)
public Response getAlerts(#PathParam("id") long id) {}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Client addClient(Client client){}
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public Client updateClient(Client client){}
#DELETE #Path("{id}")
#Consumes(MediaType.APPLICATION_JSON)
public Response deleteClient(#PathParam("id") long id){}
}
package campher.rest;
#Path("{notes}")
public class NoteService {
#GET #Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getNote(#PathParam("id") long id) {}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Note addNote(Note note){}
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public Note updateNote(Note note){}
#DELETE #Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response deleteNote(#PathParam("id") long id) {}
}
package campher.rest;
import javax.ws.rs.Path;
#Path("{test}")
public class TestResource {
}

#Path("test")
will match <web-root>/test
#Path("{test}")
will match <web-root>/foo and <web-root>/bar. The word test here is merely the path-param map key to associate foo and bar values.
Notice the presence and absence of {} around the names. They completely change the meaning of the expression. Their presence indicates that you want to extract that out and put it in an instance variable annotated with #PathParam("name-between-brackets").
Your #Path("{test}") and #Path("{notes}") both are essentially asking Jersey to look for root URLs of the form http://<host:port>/<webapp>/{capture-text} and copy the capture-text into test and notes path variables respectively. This is ambiguous.

Related

REST JAX RS : Jersey : How to read pathparam of root resource in sub resource?

I am trying to read the root resource path param in a sub resource file, but I am getting an error. Please Help me.
The way I am following is :
Root resource Service:
#Path("/{messageId}/comments")
public CommentResource getCommentResources(){
return new CommentResource();
}
Sub resource code:
#Path("/")
public class CommentResource {
private CommentDAOImpl commentDaoObject = new CommentDAOImpl();
#GET
#Produces(MediaType.APPLICATION_JSON)
public ArrayList<Comment> getAllCommentsForAMessage(#PathParam("messageId") long messageId){
return commentDaoObject.getAllCommentsForMessage(messageId);
}
#Path("/{commentId}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Comment getCommentForAMessage(#PathParam("commentId") long commentId, #PathParam("messageId") long messageId){
return commentDaoObject.getCommentForMessage(messageId, commentId);
}
}
While reading the "messageId" path param in sub resource I am getting the error:
Error: #PathParam value 'messageId' does not match any #Path annotation template parameters of the java method 'getCommentForAMessage' and its enclosing java type
'org.ramesh.jrs.Messenger.resources.CommentResource'.
Can anyone help me resolve the issue?
If you want pass a parameter to a resource class you must use the ResourceContext.initResource method.
This is how to modify your code:
Root resource Service
#Path("/{messageId}/comments")
public CommentResource getCommentResources(#PathParam("messageId") long messageId, #Context ResourceContext resourceContext){
return resourceContext.initResource(new CommentResource(messageId));
}
Sub resource code:
public class CommentResource {
private CommentDAOImpl commentDaoObject = new CommentDAOImpl();
private long messageId;
public CommentResource(long messageId) {
this.messageId = messageId;
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public ArrayList<Comment> getAllCommentsForAMessage(){
return commentDaoObject.getAllCommentsForMessage(messageId);
}
#GET
#Path("/{commentId}")
#Produces(MediaType.APPLICATION_JSON)
public Comment getCommentForAMessage(#PathParam("commentId") long commentId){
return commentDaoObject.getCommentForMessage(messageId, commentId);
}
}

org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/plain; charset=ISO-8859-1

I am trying to call rest service using restassured framework - getting this exception.
org.glassfish.jersey.server.ServerRuntime$Responder mapException
WARNING: WebApplicationException cause:
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/plain; charset=ISO-8859-1, type=class com.digicel.selfcare.service.services.beans.request.FacebookNewsFeedRequest, genericType=class com.digicel.selfcare.service.services.beans.request.FacebookNewsFeedRequest.
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:207)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:139)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:72)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:139)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1109)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:851)
at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:253)
at org.glassfish.jersey.server.internal.inject.EntityParamValueFactoryProvider$EntityValueFactory.provide(EntityParamValueFactoryProvider.java:96)
at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:81)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInv
#Path("social/")
public class MyService{
#POST
#Path("facebook/feeds")
#Produces(MediaType.APPLICATION_JSON)
public List<FacebookNewsFeedResult>getFacebookNewsFeed(FacebookNewsFeedRequest request, #Context HttpServletRequest httpReq)
}
This my jUnit : using restassured
#Test
public void getFacebookNewsFeedTest() throws Exception
{
final String resource = "social/facebook/feeds";
String jsonContent = "{\"feedId\": \"100\",\"pull\": \"true\"}";
expect().spec(okResponse).with().headers(this.authorizedHeaders).content(ContentType.JSON).content(jsonContent).post(selfCareServiceTest.buildURLForResource(resource));
}

Rest Api Design with dependent resources

I am new to REST API currently i am working on a project where I have 2 resources:
Project
Client
Now for this did I need to create 2 resource class as given below or a single resource class.
#Path("/v1/projects")
public interface ProjectResource {
#POST
public Respone add(Project project)
#DELETE
public Respone delete(Project project)
#PUT
public Respone update(Project project)
}
#Path("/v1/projects/{projectId}/client")
public interface ClientResource {
#POST
public Respone add(Client client)
#DELETE
public Respone delete(Client client)
#PUT
public Respone update(Client client)
}
Or a single resource class with all methods
#Path("/v1/projects")
public interface ProjectResource {
#POST
public Respone add(Project project)
#DELETE
public Respone delete(Project project)
#PUT
public Respone update(Project project)
#Path("/{projectId}/client")
#POST
public Respone add(Client client)
#Path("/{projectId}/client")
#DELETE
public Respone delete(Client client)
#Path("/{projectId}/client")
#PUT
public Respone update(Client client)
}
It's up to you, but taking SRP into consideration it's better to split the implementation into two classes. Remember that classes should be atomic and focus only on delivering single piece of functionality.

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();
}