Get resource class name by request URL/path - java

Lets say this is my JAX-RS resource class
#Path("/books")
class Book {
#GET
#PATH("{id}")
public Book get() {
}
}
So, when i make a request for "{context}/books/123", its gets to my Book.get() method.
Now, I have a Servlet where I want the resource class name (and method) by the URL? Is there a way to query JAX-RS for the class name that handles a specific resource?

Related

Access path params from outside the main controller with Quarkus and Resteasy

I'm using Resteasy with Quarkus (io.quarkus.quarkus-resteasy).
I have a path with params declared on a controller.
#RequestScoped
#Path("/v1/domain/{domain}/resource")
public class MyRestController {
#POST
#Consumes(APPLICATION_JSON)
public Response create(Entity entity) {
// here I create a new entity...
}
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response get(#PathParam("id") String id) {
// get and return the entity...
}
}
I would like to retrieve the domain path param from outside this controller, in a provider marked with #Dependent for example, or in any interceptor that process the incoming request.
#Dependent
public class DomainProvider {
#Produces
#RequestScoped
public Domain domain() {
// retrieve the path param here !
}
}
I didn't find a way to do that, nor documentation about this.
I tried both:
injecting io.vertx.ext.web.RoutingContext with #Inject and access routingContext.pathParams()
using ResteasyProviderFactor to recover the request context data
In both case, there is no path parameter : the request path is resolved as a simple string, containing the actual URL the client used to contact my web service.
Edit:
As a workaround, in my DomainProvider class, I used the routingContext to retrieve the called URL and a regular expression to parse it and extract the domain.
There is no standard way to do this.
You need to pass the param from the JAX-RS resource on down to whatever piece of code needs it

Can I use #GET annotations in two methods in same class?

#GET
#Produces(MediaType.APPLICATION_JSON)
public String getRscSubTypes(){
return AddResourceMysql.getRscSubType();
}
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getDbTypes() {
return AddResourceMysql.getDbType();
}
This is returning the following exception:
org.glassfish.jersey.server.model.ModelValidationException:
Validation of the application resource model has failed during application initialization.
Can you please help me?
How request matching works
Definitely, you can have more than one method annotated with #GET in the same class. However, your current definition is ambiguous.
For more clarification, have a look at the JAX-RS 2.0 specification:
3.7.2 Request Matching
A request is matched to the corresponding resource method or sub-resource method by comparing the normalized request URI, the media type of any request entity, and the requested response entity format to the metadata annotations on the resource classes and their methods. [...]
How to fix it
You need change your method annotations to ensure you have no ambiguity. To do it, you can play with the following annotations:
HTTP method: #GET, #POST, #PUT, #DELETE, #HEAD and #OPTIONS
Request URI: #Path
Media type of any request entity: #Consumes
Requested response entity format: #Produces
To fix it, for example, you can just add a #Path annotation with different values to each method.
If you want to define multiple resource methods, which handle GET requests for the same MIME type, within the same class, you have to specify a different subpath for the methods:
#Path("rcsubtypes")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String getRscSubTypes()
{
return AddResourceMysql.getRscSubType();
}
#Path("dbtypes")
#GET
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getDbTypes()
{
return AddResourceMysql.getDbType();
}
The path, specified in the #Path annotation of this method, is a subpath of the path specified in the #Path annotation of the class, which is a subpath of the path you defined for your application.
To explain your behaviour, that always the second method is called, if there is no #Consumes annotation present on the first method: #Consumes defines which media type (set in the Content-Type header of the request) can be accepted by the method. Without a #Consumes annotation all requests are accepted, but i think, if a method specifies an accepted media-type, it will be preferred.
The matching section in the jersey documentation: 3.1. Root Resource Classes

How to design paths for sub-resource within sub-resource in JAX-RS?

I am a complete beginner who is learning to build a RESTful web service. I would like to know how to set the path for sub resource within sub resource in JAX-RS.
I have three resources: profile, message and comment.
I would like my URLs to be as follows.
For profiles
/profiles
For Messages
/profiles/{profileName}/messages
For Comments
/profiles/{profileName}/messages/{messageId}/comments
My resources have paths as follows.
Profile Resource
#Path("/profiles")
public class ProfileResource {
#Path("/{profileName}/messages")
public MessageResource getMessageResource() {
return new MessageResource();
}
}
Message Resource
#Path("/")
public class MessageResource {
#Path("/{messageId}/comments")
public CommentResource getCommentResource() {
return new CommentResource();
}
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Message addMessage(#PathParam("profileName") String profileName, Message message){
return messageService.addMessage(profileName, message);
}
}
Comment Resource
#Path("/")
public class CommentResource {
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Comment postComment(#PathParam("messageId") long messageId, Comment comment) {
return commentService.addComment(messageId, comment);
}
}
But I get the following error,
SEVERE: Servlet [Jersey Web Application] in web application [/messenger] threw
load() exception org.glassfish.jersey.server.model.ModelValidationException:
Validation of the application resource model has failed during application
initialization.
[[FATAL] A resource model has ambiguous (sub-)resource method for HTTP method POST
and input mime-types as defined by"#Consumes" and "#Produces" annotations at
Java methods public sokkalingam.restapi.messenger.model.Message
sokkalingam.restapi.messenger.resources.MessageResource.addMessage(java.lang.Strin
g,sokkalingam.restapi.messenger.model.Message) and public
sokkalingam.restapi.messenger.model.Comment
sokkalingam.restapi.messenger.resources.CommentResource.postComment(long,sokkaling
am.restapi.messenger.model.Comment) at matching regular expression /. These two
methods produces and consumes exactly the same mime-types and therefore their
invocation as a resource methods will always fail.;
Questions:
How should I set my paths for my sub resources?
What is a better way to do sub resource within sub resource? Is it
common to do sub-resource within sub-resource?
How should I set my paths for my sub resources?
Get rid of the #Path on the Sub-resource classes. When the class is annotated with path, it is being added as root resource to the Jersey app. So you have a bunch of resources mapped to /, which is giving the error, as there are multiple #POST (with same #Consumes and #Produces) mapped to the same path
With sub-resource classes, you don't need the #Path. It will be ignored, as far as the sub-resource path is concerned.
What is a better way to do sub resource within sub resource? Is it common to do sub-resource within sub-resource?
I don't see any problem with what you are doing.

Adding POST Method within Jersey Class

Let's say I have a Jersey JAX-RS api end-point for handling http://<some_path>/foo. Ignore the ....
#Path("foo")
public class FooResource
#GET
#Produces("application/json")
public response getMethod(...)
I want to create POST end-point for foo/{id}/bar, where id is a path parameter and there's a body associated with the HTTP POST.
Example: HTTP POST foo/1/bar with body: { data : "...." }.
How can I add this POST method within the FooResource class? I tried an inner class, but it didn't work when I tested with Postman.
#POST
#Path("{id}/bar")
#Produces("application/json")
public response myPostMethod(...)
You can have path at method level. This will have your post method accessible via /foo/{id}/bar

How to avoid class level #path in web service to handle all web service calls

I am writing a web service like
#Path("/pathName")
public class LoginServiceComponent {
#GET
#Path("/methodPathName/{param}")
#Produces(MediaType.TEXT_HTML)
public String getVoterByVoterId( #PathParam("param") String param)
{
.................
}
}
Here my url to access web service is http://www.abc.com/pathName/methodPathName/1
Here i have 10 methods.Is there any possibility to remove class level #Path means i have only one web service class in my project.So i dont want to use class level #Param repeatedly.
Thanks in advance...
If you want to avoid the #Path on the class so your URL's don't have the "pathName" in the path, I don't think you can remove the #Path on the class entirely. But I have used the #Path class annotation of #Path("/") and was able to get just URL to be just http://www.abc.com/methodPathName/1 (if that's what you're trying to do).

Categories