Spring Test MVC : How to use object as Request Parameters - java

I am trying to write Spring MVC Tests to test Spring controllers.
Currently if I wanted to test a controller method with this signature:
#RequestMapping(value = "/new/save", method = RequestMethod.POST)
#Transactional
public String postGateway(#Valid GatewayForm gatewayForm, BindingResult bindingResult, RedirectAttributes flash, Model model)
I would use MockMVC in this manner to populate the GatewayForm object parameter:
mvc.perform(
post("/new/save")
.sessionAttr("account", account)
.param("serialNumber", "SN1QRTY334V")
.param("branchId", "1")
.param("model", "1")
.param("templateId", "1")
The problem with this is that I can only set String/primitive values onto the GatewayForm object using the .param(String, String) method.
So there are object instance variables on the GatewayForm above that I cannot set. I have seen other people instead post a JSON string of the object, but this would require changing the implementation of the controller methods to consume "application/json" which I do not want to do.
Can anybody advise?

As the comments to the question state that strings are essentially the input for HTTP requests parameters, the goal is to convert your form object into an accepted string.
Looking at the spring-mvc-test-utils library there are multiple strategies to converting an object into a String. However, the default strategy for converting an object into a String within the source code is to use:
String.valueOf(Object object)
For example my use case was to pass a List as parameters into my integration test. My controller accepts an object with attributes:
public class MyObjectThatTheControllerExpects {
List<SomeEnum> listOfEnums;
Long id
...
Therefore, my integration test posts the parameters like so:
mvc
.perform(
post("/some/endpoint")
.param("listOfEnums", String.valueOf(SomeEnum.SOMEENUMCONSTANT), String.valueOf(SomeEnum.SOMEOTHERENUMCONSTANT))
.param("id", "100")
I am sure this may not be appropriate for more complex classes. However, for this trivial case it works.
Hope it helps!

Related

Spring Boot Controller Multiple parameters (<List> and multipart file) object

Hello i am looking if i can handle with only one RestController method multiple params...
with controllers method it could be done... but i couldnt find project with 2 like that.
#PostMapping(value ="upload")
public upload(#RequestParam MultipartFile file,#RequestParam List<String> myParams ){
some code here ....
return;
}
I am just wondering if is also a good practise ... having two deferent type of objects in same controller and if its possible,,, any idea????
Simple answer: Yes, that's possible.
But as you asked for good practice, here's some context:
It is very helpful to understand how HTTP actually transports data.
If your request uses GET as request method, parameters are added to the URL as a query string. That could look like this: http://example.com/index?param1=value1&param2=value2
In this case, Spring maps the key-value pairs from the query string to your method arguments. But this will only work for text.
If you're using POST, the data is sent inside the request body. How that is encoded depends on the media type of your data. For example, the default media type application/x-www-form-urlencoded would encode the data to the same query string as above.
If you want to upload mixed-type form data like a file/blob along with some textual parameters, your data should be encoded with multipart/form-data.
As long as the request body contains a key-value format, Spring Boot will still be able to distinguish and map the parameters via #RequestParam (If the keys don't differ from your attribute names, you don't even need to assign a name to the value attribute).
I highly recommend you to take a look at the #RequestBody and #RequestPart annotations as i think it often is best practice to use a model class (DTO) for the whole request body (or rather the form, semantically), especially if there are a lot of parameters to process.
You will need to specify the names of the variables.
#PostMapping(value ="upload")
public upload(
#RequestParam(value = "file") MultipartFile file,
#RequestParam(value = "myParams") List<String> myParams
){
some code here ....
return;
}

Http controller parameter object defined as DTO or other?

RPC in Internet transport layer, use dto is reasonable. Http controller? If all controller are used by front end, parameter defined as VO?
I guess you are asking whether the argument of the rest controller method can be a DTO.
Well it will depend on the framework you use. The http parameters are strings.
If the framework has an utility mechanism (probably an annotation) that lets you map the http params you receive into a DTO you supply as the rest controller method arg, there's no problem in the arg being a DTO.
If the framework doesn't have such utility (it just maps each http param into an string arg of the rest controller method), then you have to build manually the DTO in the rest controller method.
I don't know if Spring has such an utility annotation similar to #PathVariable but for gathering multiple request params into a DTO object.
UPDATE:
Spring #RequestBody annotation deserializes the JSON into the java object argument of the rest controller method. So, the arg annotated with #RequestBody is a DTO.
DDD says nothing about which type must be the params of a rest api. They can be either a DTO or Strings, it doesn't matter. If they where strings, you would have to construct the DTO by yourself. Using #RequestBody, Spring framework does it for you.
In java, an object that is carries between process is named following the camel case notation and having the DTO suffix.
e.g. ServiceMessageDTO
DTO stands for data transfer object.
This applies also to the request body parameters from the rest webmethods.

spring MVC request param auto mapping complex object

I have seen similar answer here:
Spring MVC: Complex object as GET #RequestParam
Spring map GET request parameters to POJO automatically
I really can't find document of this because this auto mapping is not even done by any annotation. (it doesn't even need #RequestParam in fact)
1) so far I only see simple mapping, the object contain all primitive data, how about if my request is a complicated JSON object which contain several level of attributes (a object contain other objects)? Will the auto-mapping still work?
2) so far I only see Spring controller can take in one auto-map object, can I let it auto-map more than one object? For example:
public #ResponseBody List<MyObject> myAction(MyObject myObject,
MyObject2 myObject2) { ... }
Anyone know where is the document to describe how the mapping work behind the scene? Based on my second question, if Spring allow to do such thing, what if I have same attributes name in MyObject and MyObject2, how the mapping will do?
If you do things like this:
public #ResponseBody List<MyObject> myAction(#RequestBody MyObject myObject) { ... }
Of course you can only have one body in your http request.
As long as you have Jackson in your classpath (spring boot will add this automatically) your objects will be marshalled correctly.
If the JSON in your body is incorrect you will get a 400 (Invalid Request) returned.

Spring MVC - send model to view and back to controller

I have a problem with data flow in my app..
In the controller I am taking some model from DB, then I pass it to view - here some fields are shown (not all of them), and the user is able to modify them..
Then when he submits form, the controller should update the model in db.
The problem is flow, because not all of the fields are in tags, so they won't pass after submiting the form..
The only solution I found, is to create additional tags with all of the fields, which are not used in to pass them forward..
But in case I have many fields, for example - 30, I would have to create a lot of hidden fields...
What solution do you think would be the best?
Greetings,
M.
You have 2 options
Create a #ModelAttribute annotated method to get the model object from the database for each request
Put it in the session using #SessionAttributes.
#ModelAttribute annotated method
Instead of having a GET method filling the model you can also use a #ModelAttribute annotated method. This method will be invoked before each request handling method in the controller. One thing to take care of is that the id is passed in each request.
#ModelAttribute
public YourObject modelObject(#RequestParam long id) {
return yourObjectDao.findOne(id);
}
Now you can simply remove the filling of the model from the GET method and add a #ModelAttribute annotated method argument to your POST method. Which will then use the freshly obtain object.
Drawback of this approach is that when using optimistic locking it doesn't work so well anymore because each time you get the most recent version.
Using #SessionAttributes
Annotate your controller with #SessionAttributes this instructs the web handling to store the matching model objects in the session and retrieve them from there before binding.
#SessionAttributes("yourObject")
#Controller
public class YourController { ... }
Now in your POST method add an argument of the type SessionStatus and when everything is well call the isComplete method on that object. This will cleanup any session attributes put in the session by this controller.
public String handlePost(#ModelAttribute YourObject model, BindingResult result, SessionStatus status) {
if (result.hasErrors) {
return "yourView";
} else {
status.isComplete();
yourObjectDao.save(model);
return "redirect:your-new-view";
}
}

Spring MVC - Is it possible to receive a strongly typed request object on a GET?

I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}

Categories

Resources