is there any way to set general header on response of all api paths in JaxRS ?
for example i have a api like this :
#Path("/api/v1")
public class JaxRsConfig extends Application {
}
and
#Path("/voucher")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class Voucher {
#POST
public Response add(...) {
return Response.ok().header("API_EXPIRE_DATE","2025/05/12").build();
}
#GET
public Response get(...) {
return Response.ok().header("API_EXPIRE_DATE","2025/05/12").build();
}
#GET
public Response list(...) {
return Response.ok().header("API_EXPIRE_DATE","2025/05/12").build();
}
}
and this:
#Path("/invoice")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class Invoice {
#POST
public Response add(...) {
return Response.ok().header("API_EXPIRE_DATE","2025/05/12").build();
}
#GET
public Response get(...) {
return Response.ok().header("API_EXPIRE_DATE","2025/05/12").build();
}
#GET
public Response list(...) {
return Response.ok().header("API_EXPIRE_DATE","2025/05/12").build();
}
}
I always have to put this header in the response .
JaxRs has any mechanism to set this header generally ?
Note: I use JavaEE-8 on Liberty Application Server
You can try to use a WriterInterceptor to add this header.
Some good examples explained here: https://dennis-xlc.gitbooks.io/restful-java-with-jax-rs-2-0-2rd-edition/content/en/part1/chapter12/reader_and_writer_interceptors.html
Related
I have an API REST service, developed using JAX-RS. I need to make its request accept snake case as it currently only receives camel case.
NOTE:
I'm using the #Json_ignore property but it doesn't work
Controller
#POST
#Consumes("application/json")
public Response listarAcuerdos(ListarAcuerdosRequestType request) throws Exception {
...
return Response.ok().entity(result).build();
}
Request Bean
#XmlRootElement
public class ListarAcuerdosRequestType {
#JsonProperty("codigo_matv")
private String codigoMatv;
public String getCodigoMatv() {
return codigoMatv;
}
public void setCodigoMatv(String codigoMatv) {
this.codigoMatv = codigoMatv;
}
}
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.
I want to authorize calls made to my rest api differently depending on which method is being called. But the RequestHandler looks like this:
public interface RequestHandler {
Response handleRequest(Message m,
ClassResourceInfo resourceClass);
}
I can't figure out how to get the Method that will be called from that resourceClass. Is this possible?
The ResponseHandler seems to have a parameter that can do this named OperationResourceInfo:
public interface ResponseHandler {
Response handleResponse(Message m,
OperationResourceInfo ori,
Response response);
}
But by that time, I will have already deleted something I had no permission to delete (as an example).
How do I figure out what method will be called in a request filter? FWIW, the reason I want the Method is because I want to search for a custom built annotation I will put on each method. If there is a better way to approach this, I'm open to the idea.
For completeness, here's the documentation on the topic: http://cxf.apache.org/docs/jax-rs-filters.html
You can use Interceptors, rather than RequestHandler filters as the request handlers are deprecated and replaced in JAXRS 2.0 with ContainerRequestFilter and ContainerResponseFilter
For Example
Say I've RestService shown below
#Service
#Path("/Course")
public class KPRestService {
private final Logger LOG = LoggerFactory.getLogger(KPRestService.class);
#POST
#Path("/create")
#Consumes(MediaType.APPLICATION_JSON)
public Response create(CourseType course){
LOG.info("You have selected {}", course.getCName());
return Response.ok().build();
}
#POST
#Path("/get")
#Produces(MediaType.APPLICATION_JSON)
public CourseType get(#FormParam("cDate")Date date){
final CourseType course = new CourseType();
if(date.after(new Date())){
course.setCName("E&C");
course.setCDuration(4);
}else{
course.setCName("Mech");
course.setCDuration(3);
}
return course;
}
}
I prevent calling the get method using interceptor as shown below.
#Component
public class KPFilter extends AbstractPhaseInterceptor<Message> {
private final static Logger LOG = LoggerFactory.getLogger(KPFilter.class);
public KPFilter() {
super(Phase.PRE_LOGICAL);
}
public void handleMessage(Message message) throws Fault {
final Exchange exchange = message.getExchange();
exchange.put(Message.REST_MESSAGE, Boolean.TRUE);
OperationResourceInfo resourceInfo = exchange.get(OperationResourceInfo.class);
LOG.info("Method name is {}", resourceInfo.getMethodToInvoke().getName());
if (resourceInfo != null && resourceInfo.getMethodToInvoke().getName().equals("get")) {
Response response = Response.status(Response.Status.FORBIDDEN).entity("You are not authorised")
.type(MediaType.TEXT_XML).build();
exchange.put(Response.class, response);
}
}
}
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) {
...............
}
Jersey 1.6 can produce:
#Path("/stock")
public class StockResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Stock> get() {
Stock stock = new Stock();
stock.setQuantity(3);
return Lists.newArrayList(stock);
}
}
But cannot do the same with:
#Path("/stock")
public class StockResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response get() {
Stock stock = new Stock();
stock.setQuantity(3);
return Response.ok(Lists.newArrayList(stock)).build();
}
}
Giving the error: A message body writer for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/json was not found
This prevent the use of HTTP status code and headers.
It is possible to embed a List<T> in a Response the following way:
#Path("/stock")
public class StockResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response get() {
Stock stock = new Stock();
stock.setQuantity(3);
GenericEntity<List<Stock>> entity =
new GenericEntity<List<Stock>>(Lists.newArrayList(stock)) {};
return Response.ok(entity).build();
}
}
The client have to use the following lines to get the List<T>:
public List<Stock> getStockList() {
WebResource resource = Client.create().resource(server.uri());
ClientResponse clientResponse =
resource.path("stock")
.type(MediaType.APPLICATION_JSON)
.get(ClientResponse.class);
return clientResponse.getEntity(new GenericType<List<Stock>>() {
});
}
For some reason the GenericType fix wasn't working from me. However, since type erasure is done for Collections but not for Arrays, this worked.
#GET
#Produces(MediaType.APPLICATION_XML)
public Response getEvents(){
List<Event> events = eventService.getAll();
return Response.ok(events.toArray(new Event[events.size()])).build();
}
my solution for methods that use AsyncResponse
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public void list(#Suspended
final AsyncResponse asyncResponse) {
asyncResponse.setTimeout(10, TimeUnit.SECONDS);
executorService.submit(() -> {
List<Product> res = super.listProducts();
Product[] arr = res.toArray(new Product[res.size()]);
asyncResponse.resume(arr);
});
}