form-data file upload + array of object - java

I want to push data inside a form to my Spring REST api. The handler method looks as follows:
#PostMapping
public RepresentationModel<?> handleFileUpload(
#RequestParam(value = "file") MultipartFile file,
#RequestParam(value = "description", required = false) String description,
#RequestParam(value = "public") Boolean publicAccessible,
#RequestParam(value = "access") #Valid List<SomeObject> access,
Authentication authentication) {
....
}
this gave me:
But I need a way to wrap a complex Object into my array.
This is the only thing I came up with so far.
How do I have to shape my request in Postman to satisfy my controller? The problem is the access attribute. Spring complains all the time access parameter is not present or access parameter is not of type List.
In Json my request should look like this:
"public": "true",
"description": "Bachelor Dokument",
"access": [
{
"someAttribute": "something",
"someAttribute2": "something"
},
{
"someAttribute": "something2",
"someAttribute2": "something2"
}
]
...
/*Content of uarttest.py*/
I need the form-data for uploading files I figured. Or do I do something wrong here?
Thanks in advance.

You need to just use one access variable in your Postman request with the desired JSON as value:
Of course, you need to specify the Content-Type as application/json of the access field.

Related

How to receive multipart request in Spring App

I've seen many sources and also few questions on SO but didn't find solution.
I want to send to my Spring app POST/PUT-requests that contain JSON-object Car and attached file.
For the moment I have a CarController which correctly works with JSON-objects
#PutMapping("/{id}/update")
public void updateCar(#PathVariable(value = "id") Long carId, #Validated #RequestBody Car car) throws ResourceNotFoundException {
// I can work with received car
}
I also have a FileController which correctly works with file
#PostMapping("/upload")
public void uploadFiles(#RequestParam("file") MultipartFile file) throws IOException {
// I can work with received file
}
But how should my method look like to be able to work with both car and file? This code doesn't provide me any of car or file.
#PutMapping("/{id}/update")
public void updateCar(#PathVariable(value = "id") Long carId, #Validated #RequestBody Car car, #RequestParam("file") MultipartFile file) throws ResourceNotFoundException, IOException {
// can not work neither with car nor with file
}
Separate controllers work well during test from Postman. But when I try third code I got these results:
You can use consumes = { MediaType.MULTIPART_FORM_DATA_VALUE } field of #RequestMapping annotation and #RequestPart annotation for method parameters:
ResponseEntity<> foo(#RequestPart ParType value, #RequestPart MultipartFile anotherChoice) {
...
Yes, I agree with Vladimir; multipart/form-data, #RequestParts instead of body & param:
#PutMapping(value = "/{id}/update", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public void updateCar(#PathVariable(value = "id") Long carId,
#RequestPart("car") Car car,
#RequestPart("file") MultipartFile file) {
...
Then in Postman:
use Body>form-data
when issues:
display Content-Type column.
set Content-Type per part.
There is nothing wrong with your code and it could work as it is.
You could eventually improve its readability by using #RequestPart instead of #RequestParam and #RequestBody when it's a multipart request.
You can find more details about multipart requests in this article https://www.baeldung.com/sprint-boot-multipart-requests
Most importantly, to make it work/ or to test in the correct way:
When using postman for multipart requests, you have to define the content type of each RequestPart.
It's a hidden column in the form-data screen, that you can show as follows:
Check the box "Content-Type" and the new column will appear:
And finally, define the content type of each part.

Mapping multiple values (multipart data + json) in Post method with #RequestParam arguments

I need to upload from Post request MultipartFile and map a class from json.
My controller code looks like this:
#PostMapping(value = API_FILE_DIRECT_ENDPOINT,
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = MediaType.APPLICATION_JSON_VALUE)
FileDto create( #RequestParam("file") #NotNull MultipartFile multipartFile,
#PathVariable( IbsAttachmentServiceApi.FILE_TYPE_KEY) String type,
#RequestParam("dto") #NotNull ApplyingFileDto applyingFileDto){
FileDto result= process(applyingFileDto, multipartFile);
return result;
}
when I'm trying to query it from Postman, like this
but it gives me an error
"Failed to convert value of type 'java.lang.String' to required type 'com.domain.ibs.attachment.model.ApplyingFileDto'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.domain.ibs.attachment.model.ApplyingFileDto': no matching editors or conversion strategy found"
So it doesn't map ApplyingFileDto class, only if I change it to String, and convert by ObjectMapper explicitly, then it works
#RequestParam("dto") #NotNull String applyingFileDto) ...
ApplyingFileDto mappedDto = objectMapper.readValue(applyingFileDto, ApplyingFileDto.class);
Is there is any way to configure editor to map it after #RequestParam ?
like the error says. You're trying to convert a String value to an ApplyingFileDto Object. The following method to pass objects to a service is to use the #RequestBody annotation.
I think that should solve your problem. Give it a try.
It can be because you are unnecessarily including #RequestParam in the controller method. You should use #RequestBody
But before that, Make sure the attributes received as request parameters have perfect getters and setters (eg for attribute bot - setBot) on the object to be mapped.
Add the object as a parameter in the controller method, but do not annotate with #RequestParam. The setter method of the target object will be called for each matching request parameter.
Example -
#PostMapping()
FileDto create(#RequestBody DTO dto) {
}
You have #RequestParam but the dto was not in your params it was in the body tab
I've found the solution for the answer. It is needed to add #RequestPart annotation instead #RequestParam like this
#PostMapping(value = API_FILE_DIRECT_ENDPOINT,
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = MediaType.APPLICATION_JSON_VALUE)
FileDto create( #RequestParam("file") #NotNull MultipartFile multipartFile,
#PathVariable( IbsAttachmentServiceApi.FILE_TYPE_KEY) String type,
#RequestPart("dto") #NotNull ApplyingFileDto applyingFileDto){
FileDto result= process(applyingFileDto, multipartFile);
return result;
}
then reason for is in different type of converters.
It is mentioned here
Note that #RequestParam annotation can also be used to associate the
part of a "multipart/form-data" request with a method argument
supporting the same method argument types. The main difference is that
when the method argument is not a String or raw MultipartFile / Part,
#RequestParam relies on type conversion via a registered Converter or
PropertyEditor while RequestPart relies on HttpMessageConverters
taking into consideration the 'Content-Type' header of the request
part. RequestParam is likely to be used with name-value form fields
while RequestPart is likely to be used with parts containing more
complex content e.g. JSON, XML).
also this example is very useful

Incomplete Swagger documentation for SpringBoot endpoint with MultipartFile parameter

I am using Swagger with SprintBoot to generate the endpoints documentation, it is working great with one exception: I have a POST endpoint with a MultipartFile parameter. In this case Swagger generates the documentation but not the Example Value (it is empty).
public String create(#ApiParam(value = "Record to be created", required = true, type = "json", format = "json")
#RequestPart(name = "candidate") MyDto record,
#ApiParam(value = "File associated to the record", required = false)
#RequestPart(value = "file", required = false) MultipartFile file) throws Exception
Without the MultipartFile the Example Value shows the JSON example which can be used. I would like to have the same when an additional (optional) MultipartFile parameter is included.
Can this be addressed somehow?
as i know swagger docs can be placed when adding annotations something like this:
#ApiModel(value="MyFile")
public class MyFile{
#ApiModelProperty(value = "originalFileName", example="The original filename")
private String getOriginalFilename;
[...]
}
I would suggest to extend the MultipartFile Object and add this Annotations. So you can add documentation to the params and your optional params too.
P.S. MultipartFile is an Interface so you have to extend one of the Implementations e.g. CommonsMultipartFile. Than you have to include the org.apache.commons.fileupload dependency to your project (for FileItem).

SpringBoot deserialize a JSON array in Java using Jackson

I am currently writing a SpringBoot application that retrieves a JSON array from an external API. The part of the JSON I need looks like:
{
"users": [
"id": 110,
"name": "john"
]
}
In my Controller I am doing the following:
ResponseEntity<Users> response = restTemplate
.exchange(url, headers, Users.class);
return response
I then have a Users class that looks like:
#JsonProperty("id")
public String id;
#JsonProperty("name")
public string name;
How can I access the information inside the JSON array?
Thanks in advance.
Instead of loading into a POJO based on your return type you need to accept list of Users.
You cannot accept List of user class in ResponseEntity you need to first cast into object class.
ResponseEntity<Object> response = restTemplate .exchange(url, headers, Object.class);
Then you need to convert it into list of users.
List<Users> usersList = (List<Users>) response.getBody();
The JSON you posted above is not correct. It needs to be:
{
"users": [
{
"id": 110,
"name": "john"
}
]
}
and whatever object is used needs a list of Users.
The other thing is you restTemplate call is wrong, you are expecting the call to return ResponseEntity<Opportunities> class yet when in your restTemplate you are giving it the User class and that will return ResponseEntity<User> instead

Can we use swagger annotation values in our java code

I am new to java. Trying to develop a application to schedule http api calls in a cron job. Only the method name will be the input. All the apis are configured with swagger annotations. Can I use these annotations to determine whether the api is post or get or delete etc. For example
public class ABC {
#ApiOperation(
httpMethod = "GET",
value = "value",
notes = "notes",
response = ABC.class)
ABC getValue()
{
}
}
only getValue is the input to my application. Can I get the #ApiOperation values to determine the http method type.
You can, but it is in the RequestMapping annotation (the one where you specify which URL should be linked to the method):
For example, this method will be called when someone navigates to myBaseURl/persons in GET. It will return JSON.
#ApiOperation( value = "List of persons",
notes = "List all my base's persons. ",
response = Person.class,
responseContainer = "List",
tags = { "Persons", })
#RequestMapping(value = "/persons",
produces = { "application/json" },
method = RequestMethod.GET)
public PagedResources<PersonResource> persons(...) {}

Categories

Resources