Manually serializing Jersey Response - java

I have a resource:
#Path("/")
public class Resource {
#GET
public Response getResponse() {
//..
final GenericEntity<List<BusinessObject>> entity = new GenericEntity<List<BusinessObject>>(businessobjects) { };
return Response.status(httpResultCode).entity(entity).build();
}
}
I want to unit test this method without using a Jersey client, but I don't know how to get the body of the Response object. I can't see a method that works. Here's the test method:
#Test
public void testMethod() {
Resource resourceUnderTest = new Resource();
Response response = resourceUnderTest.getResponse();
List<BusinessObject> result = ???;
}
I can get the result I want if I go though a Jersey Client, but I would rather just call the method directly without making any HTTP requests.

List<BusinessObject> result = (List<BusinessObject>)response.getEntity();
This will return the object you pass into the entity method of response builder. The Response object doesn't serialize the result. Looking at the previous method, getEntity will probably return GenericEntity> so you'd want code like this.
GenericEntity<List<BusinessObject>> result = (GenericEntity<List<BusinessObject>>)response.getEntity();

Related

How to get Authorization header from an MethodInterpcetor on micronaut?

Before everything I tried this two solution but didn't work for me
Equivalent of javax.ws.rs NameBinding in Micronaut?
https://blogs.ashrithgn.com/custom-annotation-to-handle-authorisation-in-micronaut-aop-tutorial/
In my application I have to get a string in the Authorization header and then decode it from base64 and the json transform it into a POJO. Certainly the string is a jwt and I need to decode the public part of the json to get a data from a field.
Technically speaking a client will forward the header to me to take it, decode it and extract the data. (It's very bad practice but that's what I have to do).
For this I am using micronaut 2.4.1 and this is my code:
Interceptor:
public class HeadInterceptor implements MethodInterceptor<Object, Object> {
#SneakyThrows
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
Request request = (Request) context.getParameterValueMap().get("request");
// Where do i get Authorization header?
// i.e String token = (String) context.getParameterValueMap().get("Authorization");
String token = "eyJhdWQiOiJ0ZXN0IiwiaXNzIjoidGVzdCIsInN1YiI6InRlc3QiLCJleHAiOjExMTExMTEsImlhdCI6MTExMTExMTEsImRhdGEiOiJ0ZXN0In0=";
ObjectMapper mapper = new ObjectMapper();
Info info = mapper.readValue(new String(Base64.getDecoder().decode(token)), Info.class);
request.setData(info.getSub().toUpperCase());
return context.proceed();
}
}
Controller:
#Controller("/main")
public class MainController {
#Post
#Head
public Single<Response> index(#Body #Valid Request request) {
return Single.just(
Response.builder()
.message(String.format("%s-%s", request.getData(), request.getInfo()))
.build()
);
}
}
Here's a sample app https://github.com/j1cs/micronaut-jacksonxml-error
(ignore the name is for other issue)
In your implementation, the header cannot be shown in the interceptor because your index method doesn't receive it as a parameter.
So, if you add it as a parameter as below:
...
#Post
#Head
public Single<Response> index(#Body #Valid Request request, #Header("Authorization") String authorizationHeader) {
return Single.just(
Response.builder()
.message(String.format("%s-%s", request.getData(), request.getInfo()))
.build()
);
}
...
Then, you can retrieve it in the intercept method via getParameterValues(). Basically, it will be the second argument.
...
#SneakyThrows
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
...
String token = (String) context.getParameterValues()[1];
...
}
...
Update
Since you want your Request to contain both body and header, I edited the solution a bit. Basically, the header is added as a member variable to Request as below:
public class Request {
#NotNull
#NotBlank
private String info;
private String data;
#Header("Authorization")
String authorizationHeader;
}
Then, use #RequestBean rather than a #Body annotation on your Request parameter:
...
#Post
#Head
public Single<Response> index(#RequestBean #Valid Request request) {
return Single.just(
Response.builder()
.message(String.format("%s-%s", request.getData(), request.getInfo()))
.build()
);
}
...
Finally, you can access the header easily in your intercept() method as follows:
#SneakyThrows
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
...
Request request = (Request) context.getParameterValueMap().get("request");
String token = request.authorizationHeader;
...
}
I created a pull request for this change here, so you can check how it works.
In order to address the problem, you may first break the problem into parts.
Part 1: How to get arbitrary header (or list all headers)?
Try to use request.getHeaders() doc.
Part 2: How to get the header named Authorization ?
Use the way in part 1. In addition, be careful about the case. For example, is Authorization the same as authorization?
Method 2:
In controller (https://github.com/j1cs/micronaut-jacksonxml-error/blob/master/src/main/java/me/jics/MainController.java):
public Single<Response> index(#Body Request request, #Header('Authorization') String authorization) {
...
}
p.s. the "Header" annotation's doc is here: https://docs.micronaut.io/2.0.1/api/io/micronaut/http/annotation/Header.html
In interceptor:
...
String token = context.getParameterValueMap().get("authorization");
...
Why the code looks like this:
Firstly get the auth header you want using parameter injection.
Secondly, recall the fundamental concepts of AOP / AspectJ (which your interceptor class uses). Inside your interceptor, you intercept a method (in your case, the index method in controller. Thus, you can happily get the parameters of that method. In the code above, just the authorization parameter.
Please tell me if you are stuck on somewhere (and paste the code and the outputs).

Java REST API: Returning Multiple objects from API Method

I am trying to return multiple objects (such as String, Boolean, MyOwnClass, etc) from a Java REST API Method using JAX-RS in Eclipse.
Here's what I have right now:
My API Method
#Path("/")
public class myAPI {
#GET
#Produces({ "application/xml", "application/json" })
#Path("/getusers")
public Response GetAllUsers() {
//Data Type #1 I need to send back to the clients
RestBean result = GetAllUsers();
//Data Type #2 I need to send with in the response
Boolean isRegistered = true;
//The following code line doesn't work. Probably wrong way of doing it
return Response.ok().entity(result, isRegistered).build();
}
}
RestBean class:
public class RestBean {
String status = "";
String description = "";
User user = new User();
//Get Set Methods
}
So I'm basically sending two data types: RestBean and Boolean.
What's the right way of sending back a JSON response with multiple data objects?
Firstly, Java conventions are that class names begin with an uppercase letter and method names with a lowercase letter. It's generally a good idea to follow them.
You need to wrap your response inside a single class, as #Tibrogargan suggests.
public class ComplexResult {
RestBean bean;
Boolean isRegistered;
public ComplexResult(RestBean bean, Boolean isRegistered) {
this.bean = bean;
this.isRegistered = isRegistered;
}
}
and then your resource looks like...
public Response getAllUsers() {
RestBean restBean = GetAllUsers();
Boolean isRegistered = true;
final ComplexResult result = new ComplexResult(bean, isRegistered);
return Response.ok().entity(Entity.json(result)).build();
}
What you really need to know, however, is what your response document should look like. You can only have a single response document - which is what the wrapper is for - and the way your wrapper is serialised affects how the parts of the document are accessed.
Note - you have your resource listed as being able to produce both XML and JSON and what I've done only works for json. You can get the framework to do all the content-negotiation heavy lifting for you, and that would probably be a good idea, by just returning the document type from the method rather than Response ...
public ComplexResponse getAllUsers() {
...
return new ComplexResult(bean, isRegistered);

How to put parameters in RESTful POST with JerseyFramework

Let's assume that I have simple class:
public class Test
{
#Path("/test")
#POST
#Produces(APPLICATION_JSON)
#Consumes(APPLICATION_JSON)
public TestResponse post(TestResponse request, #HeaderParam("text") String text)
{
return new TestResponse(request.getData());
}
}
and I want to test this class. So how I can param in code like this:
Entity<TestRequest> requestEntity = Entity.entity(request, MediaType.APPLICATION_JSON);
final TestResponse response = target("test").request().post(requestEntity, TestResponse.class);
target("test").request().header("text", "value").post(...);
When you call request(). You get back an Invocation.Builder. You can take a look at the other methods. For the most part they all return the same Invocation.Builder, so can just chain the calls.

Spring MVC - How to return simple String as JSON in Rest Controller

My question is essentially a follow-up to this question.
#RestController
public class TestController
{
#RequestMapping("/getString")
public String getString()
{
return "Hello World";
}
}
In the above, Spring would add "Hello World" into the response body. How can I return a String as a JSON response? I understand that I could add quotes, but that feels more like a hack.
Please provide any examples to help explain this concept.
Note: I don't want this written straight to the HTTP Response body, I want to return the String in JSON format (I'm using my Controller
with RestyGWT which requires the response to be in valid JSON
format).
Either return text/plain (as in Return only string message from Spring MVC 3 Controller) OR wrap your String is some object
public class StringResponse {
private String response;
public StringResponse(String s) {
this.response = s;
}
// get/set omitted...
}
Set your response type to MediaType.APPLICATION_JSON_VALUE (= "application/json")
#RequestMapping(value = "/getString", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
and you'll have a JSON that looks like
{ "response" : "your string value" }
JSON is essentially a String in PHP or JAVA context. That means string which is valid JSON can be returned in response. Following should work.
#RequestMapping(value="/user/addUser", method=RequestMethod.POST)
#ResponseBody
public String addUser(#ModelAttribute("user") User user) {
if (user != null) {
logger.info("Inside addIssuer, adding: " + user.toString());
} else {
logger.info("Inside addIssuer...");
}
users.put(user.getUsername(), user);
return "{\"success\":1}";
}
This is okay for simple string response. But for complex JSON response you should use wrapper class as described by Shaun.
In one project we addressed this using JSONObject (maven dependency info). We chose this because we preferred returning a simple String rather than a wrapper object. An internal helper class could easily be used instead if you don't want to add a new dependency.
Example Usage:
#RestController
public class TestController
{
#RequestMapping("/getString")
public String getString()
{
return JSONObject.quote("Hello World");
}
}
You can easily return JSON with String in property response as following
#RestController
public class TestController {
#RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE)
public Map getString() {
return Collections.singletonMap("response", "Hello World");
}
}
Simply unregister the default StringHttpMessageConverter instance:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
/**
* Unregister the default {#link StringHttpMessageConverter} as we want Strings
* to be handled by the JSON converter.
*
* #param converters List of already configured converters
* #see WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)
*/
#Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(c -> c instanceof StringHttpMessageConverter);
}
}
Tested with both controller action handler methods and controller exception handlers:
#RequestMapping("/foo")
public String produceFoo() {
return "foo";
}
#ExceptionHandler(FooApiException.class)
public String fooException(HttpServletRequest request, Throwable e) {
return e.getMessage();
}
Final notes:
extendMessageConverters is available since Spring 4.1.3, if are running on a previous version you can implement the same technique using configureMessageConverters, it just takes a little bit more work.
This was one approach of many other possible approaches, if your application only ever returns JSON and no other content types, you are better off skipping the default converters and adding a single jackson converter. Another approach is to add the default converters but in different order so that the jackson converter is prior to the string one. This should allow controller action methods to dictate how they want String to be converted depending on the media type of the response.
I know that this question is old but i would like to contribute too:
The main difference between others responses is the hashmap return.
#GetMapping("...")
#ResponseBody
public Map<String, Object> endPointExample(...) {
Map<String, Object> rtn = new LinkedHashMap<>();
rtn.put("pic", image);
rtn.put("potato", "King Potato");
return rtn;
}
This will return:
{"pic":"a17fefab83517fb...beb8ac5a2ae8f0449","potato":"King Potato"}
Make simple:
#GetMapping("/health")
public ResponseEntity<String> healthCheck() {
LOG.info("REST request health check");
return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK);
}
Add produces = "application/json" in #RequestMapping annotation like:
#RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")
Hint: As a return value, i recommend to use ResponseEntity<List<T>> type. Because the produced data in JSON body need to be an array or an object according to its specifications, rather than a single simple string. It may causes problems sometimes (e.g. Observables in Angular2).
Difference:
returned String as json: "example"
returned List<String> as json: ["example"]
Add #ResponseBody annotation, which will write return data in output stream.
This issue has driven me mad: Spring is such a potent tool and yet, such a simple thing as writing an output String as JSON seems impossible without ugly hacks.
My solution (in Kotlin) that I find the least intrusive and most transparent is to use a controller advice and check whether the request went to a particular set of endpoints (REST API typically since we most often want to return ALL answers from here as JSON and not make specializations in the frontend based on whether the returned data is a plain string ("Don't do JSON deserialization!") or something else ("Do JSON deserialization!")). The positive aspect of this is that the controller remains the same and without hacks.
The supports method makes sure that all requests that were handled by the StringHttpMessageConverter(e.g. the converter that handles the output of all controllers that return plain strings) are processed and in the beforeBodyWrite method, we control in which cases we want to interrupt and convert the output to JSON (and modify headers accordingly).
#ControllerAdvice
class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> {
override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
converterType === StringHttpMessageConverter::class.java
override fun beforeBodyWrite(
body: Any?,
returnType: MethodParameter,
selectedContentType: MediaType,
selectedConverterType: Class<out HttpMessageConverter<*>>,
request: ServerHttpRequest,
response: ServerHttpResponse
): Any? {
return if (request.uri.path.contains("api")) {
response.getHeaders().contentType = MediaType.APPLICATION_JSON
ob.writeValueAsString(body)
} else body
}
}
I hope in the future that we will get a simple annotation in which we can override which HttpMessageConverter should be used for the output.
Simple and Straightforward send any object or return simple List
#GetMapping("/response2")
#ResponseStatus(HttpStatus.CONFLICT)
#ResponseBody List<String> Response2() {
List<String> response = new ArrayList<>(Arrays.asList("Response2"));
return response;
}
I have added HttpStatus.CONFLICT as Random response to show how to pass RequestBody also the HttpStatus
Annotate your method with the #ResponseBody annotation to tell spring you are not trying to render a view and simple return the string plain

Jersey Viewable with status code

The JAX-RS implementation Jersey supports MVC style web applications through the Viewable class, which is a container for a template name and a model object. It is used like this:
#GET
public Viewable get() {
return new Viewable("/index", "FOO");
}
I wonder how a status code could be returned with this approach. The above would implicitly return 200, but that wouldn't be appropriate in any case. Is there a way to set a status code explicitly?
You will have to return a Response set up with the correct status code and headers containing your Viewable, e.g.:
#GET
public Response get() {
return Response.status(myCode).entity(new Viewable("/index", "FOO")).build();
}
Hmm you can create custom Response object in jersey thusly:
this will return a 200:
#GET
public Response get() {
URI uri=new URI("http://nohost/context");
Viewable viewable=new Viewable("/index", "FOO");
return Response.ok(viewable).build();
}
to return something different use this approach:
#GET
public Response get() {
int statusCode=204;
Viewable myViewable=new Viewable("/index","FOO");
return Response.status(statusCode).entity(myViewable).build();
}
Hope that helped....

Categories

Resources