Post ArrayList of custom object in Jersey Client - jersey-2.0

I am trying to sent a custom arraylist of objects in Jersey, but no success at how this can be achieved.
My Clode,
Response response = target.request().post( EntityList), MediaType.APPLICATION_JSON_VALUE));
How can this be achieved?
Regards,
Rohit

The post method comes in three flavors
Response post(Entity<?> entity)
<T> T post(Entity<?> entity, Class<T> responseType)
<T> T post(Entity<?> entity, GenericType<T> responseType)
Since you want to just get an Response back, you will use the first one. As you can see it accepts an Entity. This class has a static json method, that you can pass an arbitrary object to. As long as you have a serializer (provider like Jackson) to handle this marshalling (and have configured it, if necessary), then something something like below should work fine
Response response = target.request().post(Entity.json(entityList));
If you get an exception about no MessageBodyWriter is found, then try to add this dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
This should automatically register with your Client (version 2.9 and up).

Related

Rest Assured: Isn't there a better way to test an array of results?

I am studying Rest Assured framework now.
Using some API I get the following (partial) JSON response:
{
"results": [
{
"type": "AAAA"
},
{
"type": "A"
}
]
}
I am trying to verify the types.
The only way I found so far is to use gson to translate the string to an object and then assert:
#Given("^test2$")
public void test2$() {
RestAssured.baseURI = BASE_URI;
String response =
given()
.param(KEY_KEY, API_KEY)
.param(URL_KEY, URL_TO_CHECK)
.when()
.get(RESOURCE)
.asString();
System.out.println(response);
GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting();
Gson gson = builder.create();
WhtResponse whtResponse = gson.fromJson(response, WhtResponse.class);
assertTrue(whtResponse.getResults().size() == 2);
assertTrue(whtResponse.getResults().get(0).getType().equals("AAAA"));
assertTrue(whtResponse.getResults().get(1).getType().equals("A"));
}
Please ignore that there are several asserts in one test method. I know it is not best practice but I am just "playing" now to study the material.
Is there a better, shorter, more fluent way to test both values? Maybe directly with Rest Assured and without the Gson?
Thanks!
There are probably a few ways but I want to present a specific one, using only RestAssured.
First, of all, you can create Java classes to represent the given JSON. You can always expand it.
Create a class ResultsObject (name doesn't matter)
public class ResultsObject {
public List<TypeObject> results;
}
We are declaring that RestAssured have to look for a JSON Array of JSON Objects. Each of these Object is parsed to TypeObject (this name also doesn't matter). What matters, is the results variable name. It matches the results in the JSON.
So, now we have to create TypeObject class to represent each of JSON Objects.
public class TypeObject {
public String type;
}
Again, the class name doesn't matter, what matters is type variable name. Just like in JSON.
Now, with a single line of code we can parse the JSON (either from Response or String) to the classes we created like this:
ResultsObject results = response.jsonPath().get("$", ResultObject.class);
Further work requires to create an assertion.
MatcherAssert.assertThat(types, Matchers.hasItems("AAAA", "A")); //you can use static imports if you'd like.
The assertion is from Hamcrest which is already included in RestAssured. It matches the Array of Strings to an Array of Strings of our choice.
You can notice, that types is not yet initialized. We need an Array of Strings but it's an Array of TypeObject. We can simply convert it using Java Stream API like this:
List<String> types = resultsObject.results.stream().map(x -> x.type).collect(Collectors.toList());
And that's it!
But the way, if you get the Exception like this Cannot deserialize object because no JSON deserializer found in classpath. Please put either Jackson (Databind) or Gson in the classpath. all you have to do is add jackson-databind to Maven. Rest Assured is able to use Gson or Jackson databind to transform JSON into Java classes.
All you need is the dependency, and you are all set.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
I already tested the solution.
It also gives you the flexibility of how you want to process the data, and as you can see, I used only 1 Assertion to compare all of the types from JSON.
Hope it helps!

Jersey 2: filters and #Context injections

I've the following question:
ContainerRequestFilter is a singleton, but reading this:
Jaxrs-2_0 Oracle Spec
in chapter 9.2, they say:
Context is specific to a particular request but instances of certain JAX-RS components (providers and resource classes with a lifecycle other than per-request) may need to support multiple concurrent requests. When injecting an instance of one of the types listed in Section 9.2, the instance supplied MUST be capable of selecting the correct context for a particular request. Use of a thread-local proxy is a common way to achieve this.
In the chapter 9.2, the HttpServletRequest is not mentioned.
So the question is: is it safe in terms of concurrency to inject the HttpServletRequest inside a custom ContainRequestFilter?
I mean this:
#Provider
#PreMatching
public class AuthenticationFilter implements ContainerRequestFilter {
#Context private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// This is safe because every thread call the method with its requestContext
String path = requestContext.getUriInfo().getPath(true);
// Is this safe? The property request is injected by using #Context annotation (see above)
String toReturn = (String)request.getAttribute(name);
[...]
}
I did some empirical tests on my IDE in debug mode, sending with two different browsers two different and concurrent requests and it seems to work well; I noticed that the filter's instance is ever the same (it's a singleton), but the injected HttpServletRequest is different in the two cases.
I readed even this thread: How to access wicket session from Jersey-2 request filter? and it seems that my tests are confirmed.
But I still have doubts.
Confirm?
Yes it's safe. To understand the problem, you should understand how scopes work. In any framework that deals with scopes (and injection), the feature is implemented similarly. If an object is in a singleton scope and another object in a lesser scope needs to be injected, usually a proxy of the object will be injected instead. When a call is made on the object, it's actually a call on the proxy.
Though the spec may not mention the HttpServletRequest specifically, most JAX-RS implementation have support for this. With Jersey in particular, if this was not possible (meaning the object is not proxiable), then you would get an error message on startup with something like "not within a request scope". The reason is that the ContainerRequestFilter is created on app startup, and all the injections are handled at that time also. If the HttpServletRequest was not proxiable, it would fail to inject because on startup, there is no request scope context.
To confirm that it is not the actual HttpServletRequest and is a proxy, you can log the request.getClass(), and you will see that it is indeed a proxy.
If you are unfamiliar with this pattern, you can see this answer for an idea of how it works.
See Also:
Injecting Request Scoped Objects into Singleton Scoped Object with HK2 and Jersey

Java EE UriInfo: append Query parameters

I want to append the query parameters list of a received UriInfo in a Rest service. The query comes from the client with some parameters and I need to add some more in server side.
I tried with:
uriInfo.getQueryParameters().add("Param", "value");
but when I display the URI, it doesn't has the new parameter.
On the other hand, if I do it like this:
URI uri = uriInfo.getRequestUriBuilder().queryParam("Param", "value").build();
when I display the URI, it contains the new parameter. The problem in this second case is to reconstruct a UriInfo object to give to the next functions, they require it.
I've seen that it cannot be instantiated, it has no constructors, it has to be added with #Context, its value can be updated by another UriInfo... but how to create this UriInfo with the URI I modified?
It is not possible to modify a UriInfo, there are no methods defined for that. The only option is to recreate it using one implementation of the interface. The only implementation available is org.jboss.resteasy.spi.ResteasyUriInfo.
The problem is that when deployed, and the function using it is called, it throws a ClassDefNotFound exception; even with a dependency in the manifest pointing to resteasy-jaxrs-2.3.2.Final.jar
So, the only option is to make our own implementation of the interface.

Java Jersey: Get client IP in rest method on Tomcat

I have a Jersey rest webservice that runs on tomcat 6. I have a #Post method that consumes Multipart:
#Path("identify")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_XML)
public String identifyReception(com.sun.jersey.multipart.MultiPart multiPart) throws Exception {
I would like to get the client IP address inside this method. I found out that you can use #Context HttpServletRequest inside Get method. But in post method I need the multipart input argument. I have also found out that tomcat does not support Servlet specification...
Is there another way I can do it?
I found out that you can use #Context HttpServletRequest inside Get method. But in post method I need the multipart input argument.
I don't think the two are mutually exclusive. Let your method take two arguments (I don't think it matters what order they're in) and annotate one of them with #Context. I believe that will work whether it's a get, post, whatever. You could also just annotate a field with #Context and Jersey will initialize it for you before it calls your #GET method.

Jersey Guice Accessing Post Parameters

I have a Jersey client that is hooked up using Guice. Really hooked up :)
The resources are also created using Guice.
Something like:
#Inject
class TestResource {
#Inject DataFatcher fetcher,
...
...
}
Now, DataFetcher object is created using Guice and has deep nested guice-created objects using composition. Now, some of these object need access to parameters passed over using POST.
I have a HttpServletModule that does that for me. I I thought that does the right work.
HttpServletModule.java
Map<String, String[]> providerRequestParametersMap(HttpServletRequest reuquest) {
request.getParametersMap()
}
Now, unfortunately, It looks like Jersey, has already intercepter the request and removed the POST parameters from the request parameters Map. So, this Map of mine is empty.
How, can I get access to the POST Parameters in Guice ? I do not want to Inject the Form of MultivaledMap in the Resource directly, since that will need to be passed down all the way from the Resource which will mess up my design.
Any tips greatly appreciated. I can think of creating a Filter that intercepts the HttpServletRequest before the Jersey filters kicks in. Hoping that there is a better,easier solution :).
The easiest solution is probably a servlet Filter that does what you suggest: intercepting the HttpServletRequest before it's handled by Jersey and setting data in a request-scoped object.
If you're using Guice Servlet, filtering is at least a few keystrokes less setup than it is in web.xml.
If you'd prefer a Jersey-only solution, you could use a ContainerRequestFilter. This gives you access to ContainerRequest, which in turn provides you with a Form (a javax.ws.rs.core.MultivaluedMap).