Jersey - Marshal Object from HTTP Headers - java

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

Related

Quarkus & Microprofile : Is there a better way to use a property from application.properties into #ClientHeaderParam?

I'm trying to build a simple app that calls an API with quarkus-rest-client.
I have to inject an API Key as a header which is the same for all resources of the API.
So I would like to put the value of this API Key (that depends on the environment dev/qa/prod) in the application.properties file located in src/main/resources.
I tried different ways to achieve this:
Use directly com.acme.Configuration.getKey into #ClientHeaderParam value property
Create a StoresClientHeadersFactory class which implements ClientHeadersFactory interface to inject the configuration
Finally, I found the way described below to make it work.
My question is: Is there a better way to do it?
Here's my code:
StoreService.java which is my client to reach the API
#Path("/stores")
#RegisterRestClient
#ClientHeaderParam(name = "ApiKey", value = "{com.acme.Configuration.getStoresApiKey}")
public interface StoresService {
#GET
#Produces("application/json")
Stores getStores();
}
Configuration.java
#ApplicationScoped
public class Configuration {
#ConfigProperty(name = "apiKey.stores")
private String storesApiKey;
public String getKey() {
return storesApiKey;
}
public static String getStoresApiKey() {
return CDI.current().select(Configuration.class).get().getKey();
}
}
StoresController.java which is the REST controller
#Path("/stores")
public class StoresController {
#Inject
#RestClient
StoresService storesService;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Stores getStores() {
return storesService.getStores();
}
}
Late to the party, but putting this here for my own reference. There seems to be a difference in using #ClientHeaderParam and #HeaderParam, so I investigated a little further:
According to the Microprofile docs, you can put a compute method for the value in curly braces. This method can extract the property value.
See link for more examples.
EDIT: What I came up with resembles the original, but uses a default method on the interface, so you can at least discard the Configuration class. Also, using the org.eclipse.microprofile.config.Config and ConfigProvider classes to get the config value:
#RegisterRestClient
#ClientHeaderParam(name = "Authorization", value = "{getAuthorizationHeader}")
public interface StoresService {
default String getAuthorizationHeader(){
final Config config = ConfigProvider.getConfig();
return config.getValue("apiKey.stores", String.class);
}
#GET
#Produces("application/json")
Stores getStores();
I will get rid of the Configuration class and use an #HeaderParam to pass your configuration property from your rest endpoint to your rest client. The annotation will then send this property as an HTTP header to the remote service.
Somthing like this should works:
#Path("/stores")
#RegisterRestClient
public interface StoresService {
#GET
#Produces("application/json")
Stores getStores(#HeaderParam("ApiKey") storesApiKey);
}
#Path("/stores")
public class StoresController {
#ConfigProperty(name = "apiKey.stores")
private String storesApiKey;
#Inject
#RestClient
StoresService storesService;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Stores getStores() {
return storesService.getStores(storesApiKey);
}
}

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

jax-ws invocation in Jersy

We have Rest services implemented using Jersy,my question is when invoking some soap service from our rest implementation, we are creating object for delegate like below,
#POST
#Path("/forgotuserid/validate/mobilenumber")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ServiceResponse validateMobileNumber(CommunicationDTO commonDTO)
throws ApplicationException, Exception {
ChMTYWebservicesProvidersWsMTY service = new ChMTYWebservicesProvidersWsMTY();
WsMTYPortType portType = service.getChMTYWebservicesProvidersWsMTYPort();
//TODO : other stuffs go here
return response;
}
is there any way to avoid new object creation and have single here?
If you are using Spring framework then there is an option Dependency Injection , You can use that feature.
You can code something like this:
public class SoapWSUtil{
private static WsMTYPortType type;
static {
type = (new ChMTYWebservicesProvidersWsMTY()).getChMTYWebservicesProvidersWsMTYPort();
}
public static WsMTYPortType getType(){
return type;
}
}
And then use it as SoapWSUtil.getType(). It will be thread safe in case, if you won't add state to SoapWSUtil

JAX-RS CXF access HTTP body from #BeanParam

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...

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