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

#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

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

RESTEASY002142: Multiple resource methods match request

I am getting following for two completely different URLs and I cannot explain why:
RESTEASY002142:
Multiple resource methods match request "GET /devices/distinctValues/3".
Selecting one.
Matching methods:
[public javax.ws.rs.core.Response
mypackage.DevService.getDistinctValues(int) throws java.lang.Exception,
public javax.ws.rs.core.Response
mypackage.DevRESTService.getDevice(int,java.lang.String)
throws java.lang.Exception]
This warning should not come up, since the URLS are completely different. If anybody knows why this is happening:
URLs for both methods:
getDevice:
#GET
#Path("devices/{customerId}/{deviceIds}")
#Produces({ "application/json" })
getDistinctValues:
#GET
#Path("devices/distinctValues/{customerId}")
#Consumes("application/json")
#Produces("application/json")
The warning happens because your request string can match both path templates. The request "devices/distinctValues/3"
matches devices/distinctValues/{customerId} in that customerId = "3"
matches devices/{customerId}/{deviceIds} in that customerId = "distinctValues" and deviceIds = "3".
There is no type resolution and since your request is a String there is no way to tell customerId that it cannot accept "distinctValues".
As a workaround, you can either specify a regex as shown in the linked question, or use the RESTEasy proxy framework which is basically a shared interface that both server (your JAX-RS resource) and client use, and then you have a common language with type resolution. Note that there is a typo in the example of the docs.

Is #Consumes annotation required or optional in the DELETE method Jersey

I'm new in jersey rest service and I want to understand in this example the utility of adding #Consumes annotation to a delete method in this case this is the code it's work well (in a video ), is the #Consumes annotation optional here ? Thanks in advance
#path("activities")
public class ActivityResource {
#DELETE
#Path("{activityId}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
public Response delete(#PathParam("activityId")String activityId) {
activityRepository.delete(activityId);
return Response.ok().build() ;
}
}
Is the #Consumes annotation optional here ?
Yes, I would even say that it is not needed as you have only one parameter and it is a PathParam which means that it will be extracted from the path.
The annotation #Consumes is used to indicate the JAX-RS implementation how to dynamically parse/deserialize the body of your request in order to have it as parameter in a more convenient type.
For example:
#POST
#Consumes("application/xml")
public void registerUser(User user) {
...
}
In this example, we indicate that the body of the request is of type application/xml, the JAX-RS implementation will then parse the body's content as an XML to finally get an instance of User.
NB: The HTTP method used has no effect on whether or not #Consumes is needed, only the need to parse the body matter.
A DELETE should not be interested in anything that is in the request body. It should only identify the resource to be deleted based on the URI.
Remove the #Consumes, it is wrong here.
Also think about returning a HTTP status 204 No Content instead of 200 OK. After deleting a resource, there is nothing to return. You should also remove the #Produces because of this.

Jersey Multiple Produces

I am following the jersey tutorial here to figure out how one would produce multiple mime outputs. From their website, this is the recommended way:
#GET
#Produces({"application/xml", "application/json"})
public String doGetAsXmlOrJson() {
...
}
What I cannot figure out is how to abstract the #Produces away, so that my code is more welcoming to additional mime types it can produce. Say for example I have 500 methods that all have this annotation:
#Produces({"application/xml", "application/json"})
If I get a requirement to add kml as a mime type, editing and replacing all of those values would certainly be time consuming.
#Produces({"application/xml", "application/json", "application/kml"})
Is it possible to architect #Produces more efficiently so that I do not have this issue down the road?
Understanding the #Produces annotation
The #Produces annotation is used to specify the MIME media types of representations a resource can produce and send back to the client.
The JAX-RS runtime compares value of the Accept header of an incoming request with the value of the #Produces annotation to match the resource method that will handle such request.
In the absence of the #Produces annotation, support for any media type (*/*) is assumed. For a complete reference, check the JAX-RS specification.
What you can do
To reduce the amount of #Produces annotations in your code, you could annotate the resource classes instead of annotating the resource methods.
Tip: To reduce typographical errors you could use constant values:
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
Have a look at the MediaType class.

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.

Categories