JAX-RS CXF access HTTP body from #BeanParam - java

My question is simple, but I didn't manage to find a response... Is it possible with JAX-RS (using CXF implementation) to access the HTTP request body from a #BeanParam annotated parameter ?
I tried this but it doesn't work :
#Path("/courses")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class CarsResource {
#POST
#Path("/{id}")
public Course update(#BeanParam CarUpdateRequest request){
...
}
}
public class CarUpdateRequest {
#PathParam("id")
private String id;
private CarUpdateData data; // inject here the body using JsonProvider
}
It seems like an helloword example but I can't find any working example. It's strange that JAX-RS doesn't have a #BodyParam...

Related

Method not allowed when using regex in #Path with jersey

I am trying to provide endpoints that will listen on multiple versions, i.e /v1/test and /v2/test. In order not to duplicate my code, I use jersey's ability to use patterns in the #Path annotation.
Let's assume I want to provide a GET and a POST endpoint:
#Controller
#Slf4j
#Path("/")
public class TestController {
#GET
#Path("/v{version:[12]}/test")
#Produces(MediaType.APPLICATION_JSON)
public String test1(#PathParam("version") String version) {
System.out.println(String.format("GET /v%s/test called", version));
return "{\"foo\":\"bar\"}";
}
#POST
#Path("/v{version:[12]}/test")
#Produces(MediaType.APPLICATION_JSON)
public String test2(#PathParam("version") String version) {
System.out.println(String.format("POST /v%s/test called", version));
return "{\"foo\":\"bar\"}";
}
}
That works fine.
If I, however, try to use a specific path for the GET endpoints and use a pattern for the POST endpoint, I run into trouble.
Here the controller that would not work:
#Controller
#Slf4j
#Path("/")
public class TestController {
#GET
#Path("/v1/test")
#Produces(MediaType.APPLICATION_JSON)
public String test1() {
System.out.println("GET /v1/test called");
return "{\"foo\":\"bar1\"}";
}
#GET
#Path("/v2/test")
#Produces(MediaType.APPLICATION_JSON)
public String test2() {
System.out.println("GET /v2/test called");
return "{\"foo\":\"bar2\"}";
}
#POST
#Path("/v{version:[12]}/test")
#Produces(MediaType.APPLICATION_JSON)
public String test3(#PathParam("version") String version) {
System.out.println(String.format("POST /v%s/test called", version));
return "{\"foo\":\"barPOST\"}";
}
}
Doing GET /v1/test or GET /v2/test works fine, POST /v1/test however does not.
I get a 405 Method Not Allowed Exception.
As far as I got it the exception is thrown in the MethodSelectingRouter when it recognizes the path, but cannot find a method with the appropriate HTTP verb.
The issue seems to be that it picks the most specific path (/v1/test in my case) for which it does not know the POST verb.
Does anybody have an idea how to avoid this problem?
Cheers
PS: I am using spring boot with jersey (i.e. spring-boot-starter-web and spring-boot-starter-jersey) in version 1.5.2.RELEASE

405 method not allowed in spring mvc but other actions and controller working fine?

I am new to Spring and my other controller running good but when I am trying to call getmyfriends endpoint, I got the 405 Method Not Allowed:
#Controller
#Path("friends")
public class FreindsJersey {
#Autowired
private FriendsService friendsService;
#POST
#Path("getmyfriends")
#Produces(MediaType.APPLICATION_JSON)
public Response getAllMyFriends(String json) {
ReturnData returnData = (ReturnData) Parser.getJsonFromString(json, ReturnData.class);
return Response.ok(friendsService.getMyFriendsList(returnData).getContainer()).build();
}
#GET
#Path("unfriend/{userId}/{friendId}")
#Produces(MediaType.APPLICATION_JSON)
public Response unfriendUser(#PathParam("userId") long userId, #PathParam("friendId") long friendId) {
return Response.ok(friendsService.deleteAFriendOfTheUser(userId, friendId).getContainer()).build();
}
}
The URL I'm calling is http://localhost:8080/Indulgge/friends/getmyfriends
TL;DR: getAllMyFriends requires POST
When you enter a URL into your browser, it will use GET. You cannot POST from the URL bar.
Your code only allows POST.
#POST // <-- here
#Path("getmyfriends")
#Produces(MediaType.APPLICATION_JSON)
public Response getAllMyFriends(String json) {
ReturnData returnData = (ReturnData) Parser.getJsonFromString(json, ReturnData.class);
return Response.ok(friendsService.getMyFriendsList(returnData).getContainer()).build();
}
In fact, you have it backwards - safe and idempotent requests should be GET (such as getAllMyFriends); unsafe and non-idempotent requests should be POST (such as unfriendUser).

Java REST: #GET and #PUT at the same path?

I have currently trying to learn the basics of Java REST, using JAX-RS.
Within the UserService class (near bottom) of this example there is both an #GET AND #PUT method with the same #path annotation:
#GET
#Path("/users")
#Produces(MediaType.APPLICATION_XML)
public List<User> getUsers() {
return userDao.getAllUsers();
}
and
#PUT
#Path("/users")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String createUser(#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("profession") String profession,
#Context HttpServletResponse servletResponse) throws IOException {
User user = new User(id, name, profession);
int result = userDao.addUser(user);
if(result == 1) {
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
}
How does the Program know which method to invoke, considering that they are both point at the same #path ?
Resource classes have methods that are invoked when specific HTTP method requests are made, referred to as resource methods. In order to create Java methods that will be invoked with specific HTTP methods, a regular Java method must be implemented and annotated with one of the JAX-RS #HttpMethod annotated annotations (namely, #GET, #POST, #PUT, and #DELETE).
For more info take a look at this example1 and example2
JAX-RS evaluates the HTTP method of the request and then calls the appropriate Java method in UserService.

Jersey - Marshal Object from HTTP Headers

Is it possible to have Jersey take a series of HTTP headers and marshall them into a POJO, much as one might do with POST parameters?
If you are using jersey 1.x then you can use #InjectParam,
But I would suggest you to upgrade to 2.x and start using #BeanParam
If you want to get access to a specific #HeaderParam as a String, use the answers provided by #Juned Ahsan or #DJ Spiess. If you want to inject them into a POJO, I would recommend using Jersey's #BeanParam in 2.x.
For example:
#Path("/foo")
public class FooResource {
#GET
#Path("/bar")
public void bar(#BeanParam MyBean myBean) {
// Do something
}
}
public class MyBean {
private String uaCompatible;
public MyBean(#HeaderParam("X-UA-Compatible") String uaCompatible) {
this.uaCompatible = uaCompatible;
}
public String getUacompatible() {
return this.uaCompatible;
}
}
#BeanParam can be replaced with #InjectParam for Jersey 1.x (>=1.4) or #Inject in 1.x earlier than 1.4. javax-#Inject can also be used if you're using a dependency injection framework such as Spring.
Yes, you'd do it like this. (from http://www.mkyong.com/webservices/jax-rs/get-http-header-in-jax-rs/)
#Path("/users")
public class UserService {
#GET
#Path("/get")
public Response addUser(#HeaderParam("user-agent") String userAgent) {
return Response.status(200)
.entity("addUser is called, userAgent : " + userAgent)
.build();
}
}
Yes you can do so using the #HeaderParams

JAX-RS multiple classes with the same path

With JAX-RS, is it possible to have more than one class assigned to a single path? I'm trying to do something like this:
#Path("/foo")
public class GetHandler {
#GET
public Response handleGet() { ...
}
#Path("/foo")
public class PostHandler {
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response handlePost() { ...
}
This apparently isn't allowed as I get:
com.sun.jersey.api.container.ContainerException: A root resource, class PostHandler, has a non-unique URI template /foo
I can always create one class to handle requests and then delegate to helper classes. I was hoping there was a standard way of doing so.
The JAX-RS spec doesn't forbid such a mapping. For example, Resteasy JAX-RS implementation allows for it. The feature should be jersey specific.
Regarding:
I can always create one class to handle requests and then delegate to helper classes. I was hoping there was a standard way of doing so.
Usually you have the resource classes with the same name as the path:
#Path("/foo")
public class FooResource {
#GET
#Path("/{someFooId}")
public Response handleGet() {
...
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response handlePost() {
...
}
}
You cannot have multiple resources mapped to the same path. I tried that few days back and landed up at similar error.
I ended up doing subpaths such as /api/contacts for one resource and /api/tags for another.
The only other long way is to create resources in multiple packages and then create different app for each.
I had the similar issue, making the class level #PATH annotation to empty string and moving the resource name to method level #PATH annotation fixed this issue.
#Path("")
public class GetHandler {
#GET
#Path("/foo")
public Response handleGet() {
// impl
}
}
#Path("")
public class PostHandler {
#POST
#Path("/foo")
#Consumes(MediaType.APPLICATION_JSON)
public Response handlePost() {
// impl
}
}

Categories