Error:param #param is always null - java

I have a problem with Jersey and Grizzly. The problem could be very basic but I am struggling to solve it. The idea is that I am creating an exercise application that needs to store books. Everything seems to be alright but it does not work as expected. Here is the source code:
#Path("/books")
public class BooksResource
{
private BookDao bookDao= new BookDao();
#GET
#Produces(MediaType.APPLICATION_JSON)
public Collection<Book> getBooks()
{
return (bookDao.getBooks());
}
#Path("/{id}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Book getBook(#PathParam("id")String id)
{
Book book = bookDao.getBook(id);
return (book);
}
As can be observed, the path /books is working perfectly but the problem is that id is always null and it shouldn't be. Does anyone know where the problem comes from?

Try removing "/" from the path and it should work.
From
#Path("/{id}")
To
#Path("{id}")

Related

Java REST API GET test

im wondering how to test GET given below. I don't have much experience with testing so would be glad if some 1 could show me proper approach or comment what should i do better.
#Path("/some")
public class SomeApi {
#Inject
SomeLogic someLogic;
#GET
#Produces({"application/json;charset=utf-8","application/json"})
#RolesAllowed("ek_external")
public Response getSome(#QueryParam("id") Long id, #QueryParam("name") String name, #Min(0) #DefaultValue("0") #QueryParam("offset") Integer offset, #Min(1) #Max(50) #DefaultValue("20") #QueryParam("limit") Integer limit, #Context SecurityContext securityContext) {
return someLogic.getSome(id, name, offset, limit, securityContext);
}
}
This is my GET. Im not sure how to handle all these QueryParams and annotated args.
Im trying something like this
#QuarkusTest
public class SomeApiTest {
#Test
public void testGetSome() {
given()
.when().get("/some")
.then()
.statusCode(200)
.body()
}
}
i ll be glad for showing me which way to go :)
The example in the documentation here: https://quarkus.io/guides/getting-started-testing#recap-of-http-based-testing-in-jvm-mode suggests the only thing missing might be setting the body... ...(200).body(is(someBody)).
The example given here: https://quarkus.io/guides/getting-started-testing#restassured also looks relevant.
Also ensure you provide #TestConfiguration so that when you #Inject the class for SomeLogic, it is not null.

In Spring, is it better practice to return a ResponseEntity directly from the service or should i create it inside the controller?

Which of the two options is better practice:
1)
Controller:
#GetMapping("/{id}")
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_BACKOFFICE')")
public ResponseEntity<Employee> getEmployee(#PathVariable long id) {
return employeeService.getEmployee(id);
}
Service:
ResponseEntity<Employee> getEmployee(long id) {
return ResponseEntity.ok(findByEmployeeId(id));
}
2)
Controller:
#GetMapping("/{id}")
#PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_BACKOFFICE')")
public ResponseEntity<Employee> getEmployee(#PathVariable long id) {
return ResponseEntity.ok(employeeService.getEmployee(id));
}
Service:
Employee getEmployee(long id) {
return findByEmployeeId(id);
}
I personally thought 1) is the better option, because some API-requests can return different ResponseEntities. A PUT-request for example could return ResponseEntity.ok if the resource exists and was updated. If the resource doesnt exist, it could create it and return ResponseEntity.created. By returning that directly in the service im avoiding adding logic to the controller. That way im keeping the controller clean. But in other projects ive seen people using option 2) and i wonder, whats the advantage of that?
Option 2 is better, as the service should not be aware of http related things

Error 404 accessing to a SubResource in a JAX-RS Jersey

I have these 2 resources
#Path("/orders")
public class OrderResource {
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getOrder(#PathParam("id") String orderid)
throws JSONException {
Order order = db.getOrder(orderid);
return Response.status(Status.OK).entity(order).build();
}
#GET
#Path("/{orderid}/products")
public ProductResource getProducts() {
return new ProductResource();
}
}
#Path("/")
public class ProductResource {
#GET
#Path("/{productid}")
#Produces(MediaType.APPLICATION_JSON)
public Response getProduct(#PathParam("orderid") String orderid, #PathParam("productid") String productid) throws JSONException {
Product product = db.getProduct(productid);
return Response.status(Status.OK).entity(product).build();
}
}
I get a successful output when I do this:
http://localhost:8080/testApp/api/orders/O101
I can see the collection of the products linked to the order in the output so I copied the id and tried this
http://localhost:8080/testApp/api/orders/O101/products/P101
But I always get a 404 error. Why? How can I solve this?
This is my config in the web.xml
<servlet-mapping>
<servlet-name>TestApp</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
EDIT
Thank you so much for your answers. Woke up this morning tired to test it with no success.
I tried your suggestions, but still get 404.
#Path("/orders")
public class OrderResource {
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getOrder(#PathParam("id") String orderid)
throws JSONException {
Order order = db.getOrder(orderid);
return Response.status(Status.OK).entity(order).build();
}
#GET
#Path("/{orderid}/products") //Here I added after products /{productID} which gives me an empty JSON. Never reach the method from the subresource.
public ProductResource getProducts() {
return new ProductResource();
}
}
public class ProductResource {
#Path("/{productid}") //Here I tried to remove the slash also.
#Produces(MediaType.APPLICATION_JSON)
public Response getProduct(#PathParam("orderid") String orderid, #PathParam("productid") String productid) throws JSONException {
Product product = db.getProduct(productid);
return Response.status(Status.OK).entity(product).build();
}
}
The problem is the #GET on the getProducts. A sub-resource locator is defined as a method with a #Path and which has no #METHOD. If you think about it, it makes perfect sense, as the there can be more than say just a #GET in the sub-resource class. So remove the #GET, and it should work. Leaving it would cause the method to not be a sub-resource locator, and it would behave like a normal resource method.
Aside from that, what others have suggested about the #Path("/") is not the cause of the problem, but it is a problem. What this does is cause Jersey to also register the ProductsResource as a root resource. So would be able to access /api/1234, since it is mapped to /. You probably don't want this. So you should remove the #Path("/") from the ProductsResource.
Sub-resources shouldn't be annotated with #Path on class level and they need to be registered with the JAX-RS runtinme.
Just remove the #Path annotation.
In your case, the problem seems to be the annotation #Path in your sub-resource. When defining a sub-resource, it should not be annotated at the class level with #Path. Also in your ProductResource, try removing the '/' from #Path("/{productid}") as it should be referenced from the context of the parent(OrderResource) and should not exists as an individual instance.
Thanks

Intertwining resources in Jersey in a mutual way

I'm trying to get my head around this RESTful scenario in Jersey: I have two resources, User and Item, and i want to retrieve all the items connected to a certain user and all the users connected to a certain item. In short, there exists a many-to-many relationship between User and Item.
I came across this RESTful design:
All the items connected to a certain user: GET .../users/{user_id}/items
All the users connected to a certain item: GET .../items/{item_id}/users
How can I implement this in Jersey? I found this solution, but it's related to sub-resources nested in the root resource, whereas in my case User and Item are both root resources accessible via their own URIs.
The following should work.
#Path("users")
public class UserResource {
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("{user_id}/items")
public Response getItems(#PathParam("user_id") String userId) {
//get the items and return a response
}
}
#Path("items")
public class ItemResource {
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("{item_id}/users")
public Response getUsers(#PathParam("item_id") String itemId) {
//get the users and return a response
}
}
I decided to implement the solution suggested here, that is to create specific resources that represent the relantionships described above.
The code that models the items-related-to-users relationship is this:
#Path("users/{userId}/items")
public class RelatedItemResource {
#GET
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<Item> getRelatedItems(#PathParam("userId") String userId) {
// returns list of related items
}
// Other methods
}
The code that models the users-related-to-items relationship is this:
#Path("items/{itemId}/users")
public class RelatedUserResource {
#GET
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List<User> getRelatedUsers(#PathParam("itemId") String itemId) {
// returns the list of related users
}
// Other methods
}
For all users connected to a certain item, this sounds more like a search criteria to get a list of users. So i would suggest this path : /users?item={itemid}. Given this notation you can really build a flexible search criteria endpoint where every query parameter is optional and is respected if some value is given in it.

Multiple GET methods match: select most specific

I have a web service that looks like:
#Path("/ws")
public class Ws {
#GET public Record getOne(#QueryParam("id") Integer id) { return record(id); }
#GET public List<Record> getAll() { return allRecords(); }
}
The idea is that I can either call:
http://ws:8080/ws?id=1 to get a specific record
http://ws:8080/ws to get all available records
However when I use the second URL, the first #GET method is called with a null id.
Is there a way to achieve what I want without using different paths?
I think this can be achieved with Spring using the #RequestMapping(params={"id"}) and #RequestMapping annotations for the first and second methods respectively but I can't use Spring in that project.
Since the path is the same, you cannot map it to a different method. If you change the path using REST style mapping
#Path("/ws")
public class Ws {
#GET #Path("/{id}") public Response getOne(#PathParam("id") Integer id) { return Response.status(200).entity(record(id)).build(); }
#GET public Response getAll() { return Response.status(200).entity(allRecords()).build(); }
then you should use:
http://ws:8080/ws/1 to get a specific record
http://ws:8080/ws to get all available records

Categories

Resources