Wrapped Response by ResponseBodyAdvice in Spring Boot not showing up in Swagger. Any idea how could it be done? - spring-boot

#ControllerAdvice
public class CA implements ResponseBodyAdvice<Object> { }
This class will wrap the response
#GetMapping
public Person getPerson()
{
return new Person();
}
In Swagger I want it to show WrappedResponse but instead it shows response of return type here(Person).
What changes to make so that it will show the wrapped response ?
Tried different combinations of APIReponse, APIModel, APIResponses of swagger but nothing seems to work

Related

How to Handle FORM_URL_ENCODED to POJO with Quarkus?

I can't seem to find any information on how to have Quarkus convert incoming URL_FORM_ENCODED requests into a POJO.
The documentation says I can annotate each parameter in my receiving method with the #RestForm parameter. But, in the case where we have a lot of form params that would mean I have to add each parameter to my method signature.
I tried simply doing something like:
public class FormStuff {
#RestForm
public String title;
....More fields
}
and then in my receiving method I have:
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void save(FormStuff stuff) {
log.info("Got Stuff! {}", stuff);
}
However, when I call this from my webpage I always get a 415 Unsupported MediaType
BUT! If I change my signature to:
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void save(#RestForm title) {
log.info("Got Stuff! {}", title);
}
The request goes through and I see the title field print out.
Does Quarkus support converting Forms to POJO like it does for MultiPart forms?
Thanks!
You need to do the following:
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void save(#BeanParam FormStuff stuff) {
log.info("Got Stuff! {}", stuff);
}
#BeanParam is a JAX-RS standard annotation that users can use to gather multiple HTTP params into a POJO.

Spring Boot - Why I cannot produce a String in RestController?

In Spring Boot, I am configuring the server and everything is working, except of my RestController. I dont know why:
(SO doesnt allow to include pictures yet, so here is a link)
Thats the little Controller class. Notice, that the method name in my Intellij IDEA
is grey - it is not used.
package com.example.intermediate.controller;
import org.springframework.web.bind.annotation.*;
#RestController
public class GrakaController {
#GetMapping(value = "/graka", produces = "text/plain")
#ResponseBody
public String getSimpleString() {
return "IT WORKED!";
}
}
In Postman I try to get the String by using http://localhost:8080/graka: I am getting a 200 return code, but with empty response body, no matter which response body format I choose in Postman. But I should get "IT WORKED!" back I think.
I have been struggling for some hours with that. Who got any ideas? Thanks for every tip!
try this
#GetMapping("/graka")
public String getSimpleString(){
return "IT WORKED!";
}
With Spring 4, if your Controller is annotated with #RestController, you don't need the #ResponseBody annotation.
Use ResponseEntity.
#GetMapping("/graka")
public ResponseEntity<String> getSimpleString() {
LOG.info("REST request get string value");
return new ResponseEntity<>("{\"status\" : \"IT WORKED!\"}", HttpStatus.OK);
}

Reactive Spring Security PostAuthorize annotation doesn't work

Using Webflux and Reactive Spring Security, how do you do post processing via annotations to control access to methods?
Trying a very basic sample, I'm not able to get the value from the PostAuthorize annotation. For example
#GetMapping
#PostAuthorize("#email == authentication.principal.email")
public Flux<Project> sampleTest(final String email) {
log.info("email: {}", email);
return Flux.empty();
}
The email will always be null. I have the basic wiring working to the fact if I set something like #PreAuthorize("hasRole('ADMIN')") I'll get back a 403.
I can extract the Authentication out with a helper like:
public Mono<Authentication> getAuthentication() {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.flatMap(Mono::just);
}
I may not be understanding your question correctly, but the PostAuthorize uses the return object - the body of the method doesn't have access to anything in the SPEL expression.
Something like this might work -
#GetMapping
#PostAuthorize("returnObject == someCondition")
public Flux<Project> sampleTest(final String email) {
// get some data and return it
}
But maybe you want to filter the items in the Flux?
You might look at the #PostFilter annotation -
// assuming there's an email property on your Project object.
#GetMapping
#PostFilter("filterObject.getEmail() == authentication.principal.email")
public Flux<Project> sampleTest() {
// get some data and return it
}

How to mock beans Autowired on service layer in #WebMvcTest

I am testing a REST API's in Spring boot gradle app, my mocked service using #MockBean is returning null. This mocked service return null if there are some beans Autowired in service class(I used constructor injection).
Here is sample Code(Not compiled, only for understanding)
#RestController
#RequestMapping("/xxx")
class TestController {
private RetriveDataService retriveDataService;
public TestControllerx(RetriveDataService retriveDataService) {
this.retriveDataService = retriveDataService;
}
#PostMapping(value = "/yyy")
public MyResponseModel myMethod(#RequestBody MyRequestModel model) {
return retriveDataService.retriveData(model);
}
}
#Service
class RetriveDataService {
private TokenService tokenService;
public RetriveDataService(TokenService tokenService) {
this.tokenService = tokenService;
}
public MyResponseModel retriveData(MyRequestModel model) {
String accessToken = tokenService.getToken().getAccessToken();
return retriveData(model, accessToken);
}
}
#RunWith(SpringRunner.class)
#WebMvcTest(TestController.class)
public class TestControllerTest {
#Autowired
private MockMvc mvc;
#Autowired
private ObjectMapper objectMapper;
#MockBean
private RetriveDataService retriveDataService;
#Test
public void testRetriveData() throws Exception {
mvc.perform(MockMvcRequestBuilders.post("/xxx/yyy").content(objectMapper.writeValueAsString(new MyRequestModel()))
.contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultHandlers.print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
}
}
When I run this test, i am getting following output(If my service do not need another bean, I am getting expected output)
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Due to this response i facing problem on line .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));. also when i check response body(as body is also a null)
Sample project to reproduce the issue is here
Checking your repository confirmed assumption form the discussion in comments under question.
You specify expectations on your mock
MyModel requestMessage = new MyModel();
requestMessage.setMessage("Hello Request Post");
given(testService1.getMessage(requestMessage)).willReturn(responseMessage);
but the message received to in your controller in your #WebMvcTest is not equal to requestMessage specified in the test. This is due to the fact that MyModel class does not override equals method.
In this situation, Mockito will use its default behaviour:
By default, for all methods that return a value, a mock will return either null, a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.
You have two options to fix the problem:
override equals (and hashCode) in your request class.
Get acquainted with argument matchers
More info on option 2.:
Technically, your expectation is equivalent to:
given(testService1.getMessage(ArgumentMatchers.eq(requestMessage)))
.willReturn(responseMessage);
You can use other matcher, or even define your own. This is useful if you cannot modify code of your argument's type (type coming from 3-rd party library etc).
For example, you can use ArgumentMatchers.any(MyModel.class))

Spring MVC REST - standard request body wrapper

What is the best way to achieve a common REST request body unwrap effect with Spring MVC #RestController ?
In other words, assuming I have the following controller:
#RestController
public class MyController {
#RequestMapping(value = "/", method = POST)
public Object hello(#RequestBody MyDTO dto) {
...
}
}
I would like the actual post body to be:
{
"version": "1.0",
"payload": {
...
}
}
Which can be represented by the following class:
public class ApiRequestDTO<TPayload> {
private String version;
private TPayload payload;
...
// Getters and Setters...
...
}
So in this particular case the client would send an instance of ApiRequestDTO<MyDTO>.
I achieved the opposite (response body wrapper) using a #ControllerAdvice, but I notice that it won't work exactly for the request body. One possible approach I can see is to decorate all the relevant message converters. But I was wondering if there is a better approach?

Resources