Multiple #RequestBody values in one controller method - spring-mvc

I'm receiving error 400 when I send PATCH request to my endpoint that looks like this
#RequestMapping(value = "...",
method = RequestMethod.PATCH,
consumes = "application/json",
produces = "application/json")
#ResponseBody
public User updateUserPartial(#PathVariable("userId") String userId,
#RequestBody Map<String, Object> userMap,
#RequestBody User user,
HttpServletResponse response) {
...
}
so basically both userMap and user should contain same data in different structure.
If I omit one #RequestBody value, this seems to work correctly.
Is it somehow possible to have both #RequestBody values?

You cannot use two #RequestBody as it can bind to a single object only (the body can be consumed only once). As Luke explained the easiest would be to create one object that will capture all the relevent data, and than create the objects you have in the arguments.
On the other hand, if you're insisting on your approach, you can create a custom ArgumentResolver as explained here

I'm pretty sure that won't work. There may be a workaround, but the much easier way would be to introduce a wrapper Object and change your signature.
Here you will find more info about it: Spring MVC controller with multiple #RequestBody

Related

Can Spring be directed to take a parameter from either the body or the URL?

An argument to a Spring MVC method can be declared as RequestBody or RequestParam. Is there a way to say, "Take this value from either the body, if provided, or the URL parameter, if not"? That is, give the user flexibility to pass it either way which is convenient for them.
You can make both variables and check them both for null later on in your code
like this :
#RequestMapping(value = GET_SOMETHING, params = {"page"}, method = RequestMethod.GET)
public
#ResponseBody
JSONObject getPromoByBusinessId(
#PathVariable("businessId") String businessId, #RequestParam("page") int page,
#RequestParam("valid") Boolean valid,
#RequestParam("q") String promoName) throws Exception {}
and then use a series if if-else to react to requests.
I wrote it to work with any of the three params be null or empty, react to all different scenarios.
To make them optional, see :
Spring Web MVC: Use same request mapping for request parameter and path variable
HttpServletRequest interface should help solve this problem
#RequestMapping(value="/getInfo",method=RequestMethod.POST)
#ResponseBody
public String getInfo(HttpServletRequest request) {
String name=request.getParameter("name");
return name;
}
Now, based on request data coming from body or parameter the value will be picked up
C:\Users\sushil
λ curl http://localhost:8080/getInfo?name=sushil-testing-parameter
sushil-testing-parameter
C:\Users\sushil
λ curl -d "name=sushil-testing-requestbody" http://localhost:8080/getInfo
sushil-testing-requestbody
C:\Users\sushil
λ

Access HttpServletRequest and HttpServletResponse in a Thymeleaf dialect processor

I'm trying to create a Thymeleaf dialect processor which performs a ServletDispatcher.include. I have extended the AbstractElementTagProcessor and overridden the doProcess method. The relevant code fragment is:
#Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final IElementTagStructureHandler structureHandler) {
ServletContext servletContext = null; // TODO: get servlet context
HttpServletRequest request = null; // TODO: get request
HttpServletResponse response = null; // TODO: get response
// Retrieve dispatcher to component JSP view
RequestDispatcher dispatcher = servletContext.getRequestDispatcher("/something");
// Create wrapper (acts as response, but stores output in a CharArrayWriter)
CharResponseWrapper wrapper = new CharResponseWrapper(response);
// Run the include
dispatcher.include(request, wrapper);
String result = wrapper.toString();
// Create a model with the returned string
final IModelFactory modelFactory = context.getModelFactory();
final IModel model = modelFactory.parse(context.getTemplateData(), result);
// Instruct the engine to replace this entire element with the specified model
structureHandler.replaceWith(model, false);
I wrote similar code in the past in the form of a custom JSP tag. Problem is: I don't know how to access the ServletContext, HttpServletRequest and the HttpServletResponse!
Can this be done at all, or should I just accept that Thymeleaf is too good at hiding the HTTP context?
You can access request (by using #request object that gives you the direct access to javax.servlet.http.HttpServletRequest object) parameters and session (with #session object that gives you direct access to the javax.servlet.http.HttpSession object) attributes directly in Thymeleaf views:
${#request.getAttribute('foo')}
${#request.getParameter('foo')}
${#request.getContextPath()}
${#request.getRequestName()}
<p th:if="${#request.getParameter('yourParameter') != null
th:text="${#request.getParameter('yourParameter')}"}">Request Param</p>
${#session.getAttribute('foo')}
${#session.id}
${#session.lastAccessedTime}
<p th:if="${session != null}"> th:text="${session.yourAttribute}"</p>
Read more here.
I found myself with a very similar requirement of accessing the request from an implementation of IExpressionObjectFactory.
The way i solved it (following #Sebastian Marsching advise in a previous comment) is by accessing the objects registered in IExpressionContext that are available from the view in the context of template evaluation (all those objects described in Appendix A and Appendix B of thymeleaf documentation), so you have access to request, response, servletContext and many other utility objects.
Speaking in code:
IExpressionObjects expressionObjects = context.getExpressionObjects();
HttpServletRequest request = (HttpServletRequest)expressionObjects.getObject("request");
There is also an expressionObjects.getObjectNames() method you can call to get a Set<String> with the names of all registered objects, which in my case gives the following list:
[i18nutils, ctx, root, vars, object, locale, request, response, session,
servletContext, conversions, uris, calendars, dates, bools, numbers, objects,
strings, arrays, lists, sets, maps, aggregates, messages, ids, execInfo,
httpServletRequest, httpSession, fields, themes, mvc, requestdatavalues]

#RequestParam for unknown key value pair

I am very new to WebApp in general and Spring MVC in particular. I am writing a small project where I wish to get the key value pair posted by a client. I can do it if I know the value of the key beforehand. The tutorials I've read in parameter processing also assumes that you know the parameter name. But what if I don't know the parameter name.
#Controller
#RequestMapping(value = "/keyvaluepost")
public class ProcessController {
#RequestMapping(method = RequestMethod.POST)
public String doPost(
HttpServletRequest request,
HttpServletResponse response,
#RequestParam("knownKey") String knownKey) {
// process knownKey here
// but what if i do not know the key?
}
Basically, I am looking for something similar to $_POST in php where I can get the key value pair. Any help will be greatly appreciated. Thanks.

How to pass single parameter to contoller in Spring MVC?

I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable

ASP.NET Web Service returns IndexOutOfRangeException with arguments

I have the following web service:
[ScriptService]
public class Handler : WebService {
[WebMethod]
public void method1() {
string json = "{ \"success\": true }";
System.Web.HttpContext.Current.Response.Write(json);
}
[WebMethod]
public object method2(Dictionary<string, object> d) {
Dictionary<string, object> response = new Dictionary<string, object>();
response.Add("success", true);
return response;
}
}
The first method accepts a traditional html form post and response writes a JSON string to the page. The second method accepts a JSON value posted via AJAX and returns a serialized object.
Both these methods work fine on their own but when put together in the same web service I get this error when calling method1:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
When I remove the arguments from method2 they work.
Can anyone suggest why this is happening?
Edit:
The problem spans from the argument type of method2. If I change it to a string or simple data type it works fine. As Joel suggests it's probably because Dictionaries can't be serialized. This doesn't seem to affect my requests sent by ajax and only breaks direct form posts to this handler. Therefore my workaround is to put the form post handlers in a separate file by themselves. Not ideal but works for my application.
Dictionaries are not serializable. Hiding it behind an object doesn't do anything for you. You must first convert your dictionary to an array or some other serializable object before sending it out.
Why isn't there an XML-serializable dictionary in .NET?
http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx
http://www.tanguay.info/web/index.php?pg=codeExamples&id=333

Resources