Getting place holder value from resource path in REST? - java

I am using Jersey RESTful web services. I have below resource.
#Path("/banker/{location}")
#Component
public class BankResource{
#GET
#Path("/{id}")
#Produces({MediaType.APPLICATION_XML})
#Override
public Response getBankerByID(#PathParam("id") String id) {
//some logic
}
}
In above class how can i get the value of {location} ? Because based on {location} value i need to do some processing. Is it possible to get its value?
Thanks!

You can get the location value using #PathParam and map it to method parameter as follows.
`
#Path("/banker/{location}")
#Component
public class BankResource{
#GET
#Path("/{id}")
#Produces({MediaType.APPLICATION_XML})
#Override
public Response getBankerByID(#PathParam("location") String location,
#PathParam("id") String id) {
//your code here
}
`

Related

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

How CXF Handles APIs If those are not annotated with the #Path Variable?

Scenario-1 : During my work I encountered below scenario, On which : getText1, getText2,getText3,getText4,getText5,getText6 are without #Path annotations,
But when I call the API (http://localhost:8080/.../testqa/ )it always returns following result :
{
"name" : "Sumit1 Arora",
"age" : 21,
"address" : "Lakshay1 Arora"
}
SimpleQAImpl
#Service("qaservice")
#Path("/testqa")
public class SimpleQAImpl {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/simpleqa")
public Person getText() {
return new Person("Sumit Arora",21,"Lakshay Arora");
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getText1() {
return new Person("Sumit1 Arora",21,"Lakshay1 Arora");
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getText3() {
return new Person("Sumit3 Arora",21,"Lakshay3 Arora");
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getText4() {
return new Person("Sumit4 Arora",21,"Lakshay4 Arora");
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getText5() {
return new Person("Sumit5 Arora",21,"Lakshay5 Arora");
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Person getText6() {
return new Person("Sumit6 Arora",21,"Lakshay6 Arora");
}
}
May you please tell me how Apache CXF works, if #Path not given like the case above or on other scenarios as well?
Is there any reference to understand such stuff?
Scenario-2 : On this scenario, No #Path variable defined on top of API Call, how all of these API would be called from URI ?
#Service
#Path("/customer")
public class CustomerResource {
private final Logger logger = LoggerFactory.getLogger(CustomerResource.class);
#Autowired
private CustomerService customerService;
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response create(Customer customer) {
if(customerService.createCustomer(customer).isPresent()) {
return Response.ok().build();
} else
return Response.status(Response.Status.BAD_REQUEST).entity(new Error(1,"test")).build();
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAll() {
logger.debug("Received request to fetch all the customers.");
List<Customer> customers = customerService.fetchAll();
GenericEntity<List<Customer>> customerEntities = new GenericEntity<List<Customer>>(customers) {};
return Response.ok(customerEntities).build();
}
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public Response update(Customer customer) {
return Response.status(Response.Status.NO_CONTENT).build();
}
}
The documentation for how CXF selects which method is executed is here: CXF resource selection overview. The docs talks about which method it prefers by looking at which has more path parameters or more a more specific path but each method in your first scenario has the same path so the first one is chosen. To differentiate between them you could use a path parameter.
The Second scenario requires you to change the HTTP method used with the URL so:
POST /customer
GET /customer
PUT /customer
would each invoke the different methods.

How to annotate jersey method if I want to pass json?

I have following jersey method declaration:
#POST
#Path("/fooPath")
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
public Response isSellableOnline(#FormParam("productCodes") final List<String> productCodes,
#FormParam("storeName") final String storeName,
#Context HttpServletRequest request) {
In rest client I try to invoke following method like this:
When I debug method I see that received parameters are null:
How to rewrite method declaration?
It is because on the isSellableOnlie method you are expecting or trying to extract form parameters, but the incoming POST request is JSON.
Well if you want JSON you should make POJO Class to be able to serialize the JSON.
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Store {
private String storeName;
private List<String> productCodes;
public Store() {
}
public String getName() {
return name;
}
public List<String> getProductCodes() {
return productCodes;
}
}
And then in your method:
#POST
#Path("/fooPath")
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
public Response isSellableOnline(Store store) {
store.getName();
...
}

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

Jersey #Path mapping queries

I have a following jersey class .
#Path("/static1/static2")
public class DoStuff {
#POST
#Path("/static3")
#Consumes(MediaType.APPLICATION_XML)
#Produces("application/xml")
public Response validation(String inputXML){
so my url is localhost/static1/static2/static3 and I get a 200
my goal is to have a URL that is
localhost/static1/{variable}/static2/static3
I tried modifying my class in the following way
#Path("/static1/{variable}/static2")
public class DoStuff {
#POST
#Path("/static3")
#Consumes(MediaType.APPLICATION_XML)
#Produces("application/xml")
public Response validation(String inputXML){
but I keep getting a 404 , what am I doing wrong ?
The problem seems to be with the last path segment static3.{format}. Try the following:
#Path("/static1/{variable}/static2")
public class DoStuff {
#POST
#Path("/{segment3:static3.*}")
#Consumes(MediaType.APPLICATION_XML)
#Produces("application/xml")
public Response validation(#PathParam("variable") String variable,
#PathParam("segment3") String segment3,
String inputXML) {
...............
}

Categories

Resources