I have a form that's being posted to my back-end (Kotlin, Spring Web). That form had some text inputs and the post worked flawlessly. But when I added a file input, the post stopped working, returning the following error:
{status: 400, error: "Bad Request",…}
error: "Bad Request"
exception: "org.springframework.http.converter.HttpMessageNotReadableException"
message: "Could not read document: No suitable constructor found for type [simple type, class com.test.InsertConfigCommand]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)↵ at [Source: java.io.PushbackInputStream@2cb43211; line: 1, column: 2]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.test.InsertConfigCommand]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)↵ at [Source: java.io.PushbackInputStream@2cb43211; line: 1, column: 2]"
Here are the codes of my stack:
View:
<form ng-submit="insert(config)">
<input type="text" ng-model="config.name">
<input type="text" ng-model="config.address">
<input type="file" ng-model="config.file">
<button type="submit">Save</button>
</form>
Controller (front-end):
$scope.insert = function (config) {
$http.post('/config', config)
.then(function (response) {
$.snackbar({content: "Success!"});
}, $scope.showErrorMessage);
};
Controller (back-end):
@RequestMapping(method = arrayOf(RequestMethod.POST))
fun insert(@RequestBody config: InsertConfigCommand) = service.save(config)
InsertConfigCommand
data class InsertConfigCommand (
val name : String = "",
val address : String = "",
val file : MultipartFile
)
I've tried to do the post the following way, it works, but only sends the file:
Controller (front-end):
$scope.insert = function (file) {
var fd = new FormData();
fd.append('file', file);
return $http.post('/config', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
});
};
Controller (back-end):
@RequestMapping(method = arrayOf(RequestMethod.POST))
fun insert(@RequestParam(value = "file", required = true) file: MultipartFile) = service.save(file)
What do I need to change for this post to work? I want to send the input file on the same object that the name and address.
I've used this tutorial which encapsulates the file inside the FormData object, and posts that object https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
$scope.insert = function (config) {
var fd = new FormData();
fd.append('name', config.name);
fd.append('address', config.address);
fd.append('file', $scope.file);
$http.post('/config', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.then(function (response) {
$.snackbar({content: "Success!"});
}, $scope.showErrorMessage);
};
And on my Kotlin controller, I receive each attribute as a separate param:
@RequestMapping(method = arrayOf(RequestMethod.POST))
fun insert(@RequestParam(value = "name", required = true) name: String,
@RequestParam(value = "address", required = true) address: String,
@RequestParam(value = "file", required = false) file: MultipartFile): InsertConfigCommand? {
val command = InsertConfigCommand(
name = name,
address = address,
file = file)
return service.save(command)
}