Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RequestBody is unable to bind (merge) JSON formatted POST form data to existing Command Object [SPR-10552] #15183

Closed
spring-issuemaster opened this issue May 12, 2013 · 8 comments

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented May 12, 2013

Richard Seldon opened SPR-10552 and commented

Please also see my own StackOverflow question on this:

http://stackoverflow.com/questions/16473727/spring-3-ajax-post-request-with-requestbody-and-modelattribute-and-sessionatt

In summary, wish to bind JSON request form data to an existing Command Object (so data is merged) with the JSON form POST data being merged (overwriting) those attributes of a superset of data already populated into Command object prior to Form presentation on view. The links above should provide sufficient illustration of the problem.

It seems that @RequestBody is capable of using Jackson JSON converter to populate a new Command Object (which may have nested objects) with the form data, but unable to leverage @ModelAttribute to automatically write the attribute values into an existing Command object (either stored in session or retrieved again using @ModelAttribute at the method declaration level.

This is a severe limitation for anyone wishing to use the Spring MVC framework and have full support for Form submissions with JSON request and response types.


Affects: 3.2.2

Reference URL: http://stackoverflow.com/questions/15124858/spring-partial-update-object-data-binding

8 votes, 6 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jun 4, 2013

Rossen Stoyanchev commented

What is the content type of the request, application/x-www-form-urlencoded or application/json? It can't be both so I'm not sure what you mean by "JSON form POST data". Can you show some sample request body content and also the Content-Type header?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jun 4, 2013

Richard Seldon commented

Thanks for your enquiry for more info. Something like the following (where both produces and consumses set to application/json:
@RequestMapping(value="/blah/updateContact",method=RequestMethod.POST, consumes = "application/json;charset=UTF-8", produces = "application/json;charset=UTF-8")
public @ResponseBody Map<String, ? extends Object> updateContact(@RequestBody ContactCommand cmd, HttpServletRequest request)

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jun 4, 2013

Richard Seldon commented

The issue is that Server side, when the JSON data sent is "bound" to the Command object instance, there is no way to get both existing Command object fields that were prepopulated during initial model setup, and the new values from JSON request together. Using various annotation constructs, you can either get the old data again (using @ModelAttribute etc) or you can get just the new JSON post data that was sent - yes that is, serialized to be JSON format prior to sending with POST command. NOT using wwww-form-urlencoded in any of the request headers.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jun 4, 2013

Richard Seldon commented

Client side JQUERY:

$.ajax({
'type': 'POST',
'url': url,
'headers': {
'Accept' : "application/json;charset=UTF-8",
'Content-Type': "application/json;charset=UTF-8"
},
'dataType': "json",
'scriptCharset': "utf-8",
'contentType': "application/json;charset=UTF-8",
'data': data
.....
}

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jun 4, 2013

Richard Seldon commented

In the above, data is derived as follows from an HTML FORM:

var formData = $('#ContactForm').serializeObject();
var data = JSON.stringify(formData);

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jun 4, 2013

Richard Seldon commented

Below is some very contrived code snippet to demo what I think Spring is "auto-magically" doing for us with Jackson mapping. Notice here it will always create a new instance of the Command Object. I want it to retrieve my initialised COmmand object from Session state and then bind in the values from JSON submission. Or do this in separate steps (a new command object as below, grab my existing command object from session state and then do the merge automatically. It doesn't do that atm.

       ContactCommand cmd = new ContactCommand();
try {
     final ObjectMapper mapper = new ObjectMapper();
     cmd = mapper.readValue(jsonInput, ContactCommand.class);
} catch (JsonParseException e) {
     logger.error("Json input: " + jsonInput);
     logger.error("Error extracting values from jsonInput: " + e.getMessage());
} catch (IOException e) {
     logger.error("Json input: " + jsonInput);
     logger.error("Error extracting values from jsonInput: " + e.getMessage());
}
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Sep 5, 2013

Nikita Tovstoles commented

+1 for this request. Maybe I am missing something but there appears to be no way to implement a partial update where POST'd JSON contains a subset of an entity's properties. ie something like:


/**
* inject existing widget into model, looking up by id
*/
@ModelAttribute("entity")
public WidgetDTO(@PathVariable("id") Long id)
{
return getWidgetService().getById(id);
}

@RequestMapping(value="/widgets/{id}", method=POST)
public WidgetDTO updateWidget(@ModelAttribute("entity") @RequestBody WidgetDTO widget)
{
//widget is initially loaded by id from service and injected as model attr; then some of its' properties are updated by deserializing JSON in post body
return getWidgetService().updateWidget(widget)
}
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jan 12, 2019

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.