What does this strange Jersey warning mean? - java

What does this warning mean in Jersey 1.4:
WARNING: A sub-resource method, public final java.lang.String com.XXX.render(),
with URI template, "/", is treated as a resource method
This is how the method looks:
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("/")
public final String render() {
return "test";
}

Why do you need specify such path for method? #Get is enough to tell jersey that it is default method for entire class (I'm assuming that your class has some #Path("/MyRes") annotation).

Looks like you had the same problem last week with How to route JAX-RS request conditionally, depending on the suffix? - any luck fixing it there?
A look around on the net reveals you may have set-up your constructor incorrectly - have a read through http://jersey.576304.n2.nabble.com/Problem-using-the-JerseyTest-class-td3256608.html - someone who had a similar problem and was able to resolve it.

Related

Jesrsey #Path working mechanism

I noticed a class in some sample somewhere the following methods were was implemented
#Path("{id}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public void retrieve(#Suspended final AsyncResponse asyncResponse,
#PathParam("id") final String id) {....}
and
#Path("/{id}")
#GET
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput retrieveSSE(#PathParam("id") final String id,#Context final HttpHeaders headers) {...}
Seems like the path is the same for both.
In this case what would happen? If my understanding is right based on the 'Accept' header from the client, the relevant method would be called.
If the Accept header is not mentioned, then what happens here?
Would both the methods be called? Or just the first method as it is in the beginning?
How does jersey decide which method to be called if Accept Header is not added?
Also even if the header is specified are both the functions called?? And it is the functions duty to respond to whether the given header is available or not.
I.E if the API call is made with Accept header as application/json
Are both methods called however since the first method has the mechanism to handle JSON it responds?
Do correct me if I've even asked the question wrong.
If the api call is made with accept header as application/json the first method will respond as it is meant to handle JSON request.
about your question on if the accept header is not mentioned and the resources have same paths then Jersey will probably give an error if your request is such where multiple resources might respond.

A resource model has ambiguous (sub-)resource method for HTTP method GET and input mime-types as defined by"#Consumes" and "#Produces" annotations

How can the following produce this error when they have different URLs ?
#Path("/job/{empId}/empProfile")
public EmpProfileResource delegateToEventProfileResource() {
EmpProfileResource resource = new EmpProfileResource();
locator.inject(resource);
return resource;
}
#Path("/job/{empId}/empTask")
public EmpTaskResource getClientLevelAttendees(#PathParam("clientId") long clientId){
EmpTaskResource resource = new EmpTaskResource (empId);
locator.inject(resource);
return resource;
}
#Path("/")
public class EmpTaskResource{
}
#Path("/")
public class EmpProfileResource{
}
Yes, they both are GET and produce the same, so ?
#GET
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
Error:
[[FATAL] A resource model has ambiguous (sub-)resource method for HTTP
method GET and input mime-types as defined by"#Consumes" and
"#Produces" annotations at Java methods public
javax.ws.rs.core.Response
com.EmpTaskResource.getEmpTasks(java.time.LocalDate,java.time.LocalDate,java.lang.String)
and public javax.ws.rs.core.Response
com.EmpProfileResource.getEmpProfiles(long,java.lang.String) 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.;
Remove the #Path("/") from the sub-resource classes. Sub-resource classes don't need them. And if they have them, they get added as root resource classes, if you are scanning for #Path annotated classes. And this is the problem. You haven't show the methods of the sub-resource classes, but because the have the same root path, I would imagine that the problem is caused by some overlapping methods. So just remove the #Path("/") on sub-resource classes, and you should be OK.
I had the same error. Most people resolved the error by changing their #Path annotations because they where ubiquitous. In my case something different happened. I modified a package from aaa to bbb for example. For some reason in the artifact deployed to the server there where both the aaa and bbb packages, so the resources where duplicated and the server raised the exception. I had to clear the previous deployed artifact and deploy the new. Someone may check this case also where the error appears. Of course at the end of the day the reason is again a path ubiquity.
I am suffering with the same problem i have also updated a version check but its give me a same problem may jersey frame works is not supporting this
I had this error two times now. Both were different:
First time I had at the following above GET and POST Methods etc.
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
But I didn't have it infront of the class. So if you have different class-ressources like:
#Path("/users")
public Class User{}
and
#Path("/lists")
public Class List{}
Then BOTH of them need the
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
infront of them:
#Path("/users")
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
public Class User{}
Second time I moved a resource (endpoint) class from one folder to a different one (via refactor from Intellij) and apparently the IDE doesn't recognize this. Then the exact problem occurs which Panagiotis Piperopoulos already described.
To fix it I did the following:
Go to the folder where you project is located (<working_directory>). There you will find a folder called target (<working_directory>\target)
There was in my case
1: a war file. Delete that.
2: A folder which contains the meta-inf and web-inf and index.html. The name is probably your module name (in IntelliJ: File -> Project Structure -> Module). Rename that folder to something like <old_name>_old
If you re-compile your code then the folder and a new .war file should appear.
This error arises if we have written #PathParam instead of #Path in our service class or where ever we are defining the path for same.

JAX-RS resource method signatures

I'm using Jersey 2.19 to implement a REST API.
I'd like to know how I find out from the Jersey user guide or other specification how I'm supposed to know what the signature of my JAX-RS resource should be.
E.g. for a resource that handles POST requests I've experimented with the following different signatures using examples I've found.
public Response myResource()
public Response myResource(String param)
Both of these are valid in that they compile and run and the method is called under the right conditions.
Can anyone tell me where it is specified what the signatures should be and what the parameters mean? It seems like a straightforward question but I can't find the answer.
As you are saying its a POST request , so it should recieve some data from the Request. So you should expect something in Parameter.
public Response myResource(String param)
But the type of parameter should depend upon actually #Consumes annotation like :-
#Consumes(MediaType.APPLICATION_JSON) : This expects a JSONinput OR
#Consumes(MediaType.APPLICATION_XML) : This expects a XMLinput OR
#Consumes(MediaType.TEXT_PLAIN) : This expects a String plain text input
You annotate your Methods like described in the official documentation.
Also, do not forget to annotate the service-class with #Path
#Path("MyService")
public class MyService
{
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/User")
public List<User> getUser()
{
//Return all users
}
//Inserts new User in JSON Format
#Get
#Path("/User/UserId/{userid}")
public User getUserById(#PathParam("userid") String userid)
{
//Find User with ID in Database and return it
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public User getUserById(User user)
{
//add user to your Database or something
}
}
If you now want to get all users in json format you have to call:
http://ip-address/MyService/user
There is an exact answer to your question, but gird your loins. Because if the Jersey docs are overly vague these are in the extreme opposite direction: written by someone showing off their PhD in abstract algebra it looks to me.
The answer to everything is in the JAX-RS spec, of which Jersey is an implementation. You can download it here as PDF (after you sign away your soul)
The specific answer to how one of those methods is selected instead of the other, is too detailed for me to paste in here, but it's under section "3.7.2 Request Matching"
I won't even try to paste in the mathematical rules used to set up the list of potential methods to match a request, then select from among them. There's no chance of getting them formatted readably in SO.
For your more general questions, the section "3.3 Resource Methods" is much more accessible. Here are a few choice excerpts:
3.3 Resource Methods
...
JAX-RS defines a set of
request method designators for the common HTTP methods: #GET, #POST,
#PUT, #DELETE, #HEAD and #OPTIONS.
...
3.3.1 Visibility: Only public methods may be exposed as resource methods.
...
3.3.2 Parameters: Resource methods MUST have at most one entity parameter ...
3.3.3 Return Type: Resource methods MAY return void, Response, GenericEntity, or another Java type...
etc, etc.

Spring URL when both controller and method do not have #RequestMapping values

I'm being asked to take over a piece of code. Being that I am not an seasoned Spring developer, I have a question on what is the URI when both the controller and method does not specify a value for #RequestMapping.
For example, the code looks like this:
#Controller
public class FooController {
#RequestMapping
public String getThis(String input) {
return "This";
}
}
So what is the URL that I need to access the getThis method?
Sometime back i also had the same doubt. Am thinking that Controller without #RequestMapping will throw an exception (am not sure).
For method case:
If you don't have any values in #RequestMapping, method will listen on Controller path and you dint specify any method so it will listen ALL HTTP Methods.
Your method will not be reachable and you can see this via a warning message from Spring like :
21:57:50.608 [main] DEBUG o.s.w.s.h.BeanNameUrlHandlerMapping -
Rejected bean name
'org.springframework.context.annotation.internalConfigurationAnnotationProcessor':
no URL paths identified
If you need to have this method in the root URL, you need to use the value "/" instead of nothing.

Is there a way to access HttpRequest type inside a #Controller method

I have tried to find the answer to this, but I cannot seem to find what I am looking for. So I apologize if this question already exists.
PROBLEM:
I want to be able to access the request type of a request inside of a generic method within my Controller.
DESCRIPTION:
Using Spring ROO and Spring MVC, I have developed a small web service that will respond with certain tidbits from a database when queried. In one of my controller classes, I have some methods that handle some variety of GET, PUT, POST, etc., for the URIs that are mapped within the #RequestMapping parameter.
For example:
#RequestMapping(method = RequestMethod.Get, value = "/foo/bar")
#ResponseBody
public ResponseEntity<String> getFooBar() {
// stuff
}
If a request is made to the web service that it is not currently mapped, a 405 error is returned (which is correct), but I want to return more information along with a 405 response. Maybe respond with something like:
"I know you tried to execute a [some method], but this path only handles [list of proper methods]."
So I wrote a short method that only has the RequestMapping:
#RequestMapping(value = "/foo/bar")
I have found that the method with this mapping will catch all unhandled request types. But I am having trouble accessing the information of the request, specifically the type, from within the method.
QUESTION:
A. How can I access the request type from within the method? OR
B. Is this the right approach? What would be the right approach?
EDIT
ANSWER:
I added a HttpServletRequestobject to the method parameters. I was able to access the method type from that.
I tried using HttpRequest, but it didn't seem to like that much.
Thanks all!
You can add a method parameter of HttpServletRequest, but I think you'd be better off continuing to reply with 405. A client should then make an HTTP OPTIONS call (see How to handle HTTP OPTIONS with Spring MVC?) and you can return the list of allowed methods there.
A. you can access request if you mentioned it as parameter in controller method
public ... getFooBar(HttpRequest request) {
...
}
B. you do not need to add any other description as the 405 status is descriptive.
In answer to "A", just add "HttpRequest req" as an additional argument to your controller methods. Spring will automatically inject a reference to the request, and you can play with headers to your heart's content.
In answer to "B" - "What would be the right approach", how about this?
In order to return that 405, Spring has raised a MethodArgumentNotValidException. You can provide custom handling for this like so:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public MyMethodArgumentMessage handleMathodArgumentNotValidException(
MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
MyMethodArgumentMessage myMessage =
new MyMethodArgumentMessage(result.getFieldErrors());
return myMessage;
}
You should take a look at the #ExceptionHandler annotation. This lets you add methods such as the following to your controller. You can define your own exceptions and appropriate custom handlers for them. I use it to return well-structured XML and JSON from REST services. Although for it to work, you need to throw specific exceptions from your controller methods.
A good walk-through of using this was provided by Petri Kainulkainen in his blog:
http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/

Categories

Resources