how to pass object as a parameter to the mockmvc? - java

MvcResult mvcResult = mockMvc.perform(post("/user/addItemIntoCart").andExpect(status().isOk()).andReturn();
#PostMapping(value = "/addItemIntoCart",consumes = {"application/json"})
public ResponseEntity<String> addItemToCart(#RequestBody CartDto cartDto) {
return cartService.addItemIntoCart(cartDto);
}
how can I pass object of CartDto to the mockmvc
I am trying to test addItemIntoCart method, but not sure how to pass object to the mockmvc

Here you can use the answer that contains what you want: https://stackoverflow.com/a/35402975/11988137
In a nutshell, you need to create the object and using objectMapper, convert it to a a json string. Then you need to use contentType() and content() method in order to send the json string you've created to the api.

Related

How to pass a plain(not annotated api parameter) object with MockMvc

i am trying to pass a regular object to an api, via the MockMvc library.
Here is the example (Partiucalarly the FilterProperties properties object):
API:
#GetMapping("/test-api")
public PageResponse<SomeDto> getAllObjects(
FilterProperties properties,
#RequestParam(value = "searchPhrase", defaultValue = "") String searchPhrase,
#RequestParam(value = "actionType") ActionType actionType) {
System.out.println(searchPhrase);
return null;
}
I managed to successfully pass the #RequestParams with .param("searchPhrase", "SomePhrase"), however i cannot seem to find a way to pass the FilterProperties object, since its just a plain object and is not annotated as param, request body or some sort of attribute.
TEST:
final MvcResult mvcResult = restServiceMockMvc
.perform(get(CONTROLLER_BASE_PATH + "/test-api")
.param("searchPhrase", "SomePhrase")
.param("actionType", String.valueOf(ActionType.EDIT))
.requestAttr("properties", filterProperties)
.contentType(APPLICATION_JSON_UTF8))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
I tried with requestAttr, flashAttr, sessionAttr and it does not break the call, however the api receives an empty object for filterProperties.
I appreciate any insights!
FilterProperties will be treated as there are #ModelAttribute annotated on it (mentioned by the rules in this table).
And #ModelAttribute will enable data binding which will try to bind the value from query parameters , or field name of the form data or others (see this for more details) to FilterProperties .
So that means assuming FilterProperties has the following fields :
public class FilterProperties {
private String prop1;
private String prop2;
}
Then you can configure the MockMvc as
mockMvc.perform(get(CONTROLLER_BASE_PATH + "/test-api")
.param("searchPhrase", "SomePhrase")
.param("actionType", String.valueOf(ActionType.EDIT))
.param("prop1", "prop1-value")
.param("prop2", "prop2-value"))
in order to pass the following values to the fields of the FilterProperties :
prop1 = prop1-value
prop2 = prop2-value
whenever you pass an object to an api, it has to be part of the api signature in one way or another; i guess here you want to pass a body for the GET api(which is highly discouraged),since GET calls are idempotent by nature.
if though if its for testing try passing it as a requestbody and then mock it

How to handle multiple parameters with ObjectMapper?

I would like to know how one tests a controller (post) which requires multiple arguments.
#RequestMapping(value = PATH_TO_OBFUSCATED, method = RequestMethod.POST)
public ResponseEntity<String> download(#RequestBody String requestBody, #RequestParam("obfuscated") boolean obfiscated) {
return obfuscated.download(requestBody, obfiscated);
}
I know, when I am testing a spring mvc controller with one param, I can use ObjectMapper like so:
.content(new ObjectMapper().writeValueAsString(obfuscated))
But, how should I use the ObjectMapper when there's >=2?
As said in the comments you have just 1 body. So maybe something like this:
this.mockMvc.perform(
post("/obfuscated").
contentType(MediaType.APPLICATION_JSON).
content(json).// <-- the body
param("obfuscated", "true"))// <-- the param
.andExpect(status().isOk());

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

Parsing json object in java code

I am stuck with code actually i am using spring MVC 4. I have one condition where i need to pass the json object at controller side an iterate it. My Json object look like below
{"comptocome":[
{"1":"Key Parameters","2":"Cellular Limited","3":"limited","4":"Cellular Limited"},
{"1":"- Long term","2":"Reaffirmed","3":"football","4":"golf"}
]
}
with respect to above i have pass this to controller and iterate according to the number of row for example from above two times loop and also to fetch data as per key can any one help me out sort this problem with help of import org.json.simple.JSONObject package.
Thanks in advance.
Parse using Jackson JSON
eg:
{
"foo" : ["1","2","3","4"],
"bar" : "xxxx",
"baz" : "yyyy"
}
Could be mapped to this class:
public class Fizzle{
private List<String> foo;
private boolean bar;
private int baz;
// getters and setters omitted
}
Now if you have a Controller method like this:
#RequestMapping("somepath")
#ResponseBody
public Fozzle doSomeThing(#RequestBody Fizzle input){
return new Fozzle(input);
}
You can use com.google.gson for it:
#RequestMapping(value = "/request", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody ResponseClass addDeparturePoint(#RequestBody String request) {
Gson gson = new Gson();
RequestClass request = gson.fromJson(request, RequestClass.class);
ResponseClass response = buildResponce(request);
return response;
}

Spring MVC, deserialize single JSON?

How can I easily separate JSON values that are sent in the same request?
Given that I POST a JSON to my server:
{"first":"A","second":"B"}
If I implement the following method in the Controller:
#RequestMapping(value = "/path", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void handleRequest(#RequestBody String input) {
// ...
}
then the input parameter will constitute a String with the entire JSON object, {"first":"A","second":"B"}. What I really want is two separate Strings (or a String and an int whichever is suitable for the particular request) with just the two values (other key / value pairs that the client may send should be ignored).
If the strings were sent as request parameters instead of JSON request body it would be simple:
#RequestMapping(value = "/path", method = RequestMethod.POST)
public void handleRequest(#RequestParam("first") String first,
#RequestParam("second") String second) {
// ...
}
I know that I can create a simple bean class that can be used in conjunction with the #RequestBody annotation that will contain both A and B when used, but it seems like a detour, since they will have different purposes inside the web app.
Dependencies:
org.springframework : spring-web : 3.1.0.RELEASE
org.codehaus.jackson : jackson-mapper-asl : 1.9.3
POJO
public class Input {
private String first;
private String second;
//getters/setters
}
...and then:
public void handleRequest(#RequestBody Input input)
In this case you need Jackson to be available on the CLASSPATH.
Map
public void handleRequest(#RequestBody Map<String, String> input)
I have written a custom WebArgumentResolver that does exactly this, combined with a custom annotation.
I don't have the source available to me now, but basically I annotated my method like this:
#RequestMapping(value = "/path", method = RequestMethod.POST)
public void handleRequest(#JsonField("first") String first, #JsonField("second") String second) {
// ...
}
Then my JsonFieldWebArgumentResolver checks if the method parameter is annotated with JsonField, and if it is it extracts the actual type from the parameter (not quite straight-forward it turns out if you want to handle generic parameters as well, such as List<String> or List<Pojo>), and invokes Jackson's JsonParser manually to create the correct type. It's a shame I can't show you any code, but that's the gist of it.
However, that solution is for Spring MVC 3.0, and if you are using 3.1 I think you will be better off using a custom HandlerMethodArgumentResolver instead. But the idea should be the same.

Categories

Resources