I have a spring boot controller with
@RestController@Tags(@Tag(name = "app"))public class MyController { @Operation( requestBody = @RequestBody( content = @Content( mediaType = "multipart/form-data", schema = @Schema(type = "object"), schemaProperties = { @SchemaProperty(name = "info", schema = @Schema(implementation = Info.class)), @SchemaProperty(name = "file", schema = @Schema(type = "string", format = "binary")) } ) ) ) @PostMapping(value = "/upload") ResponseEntity<Void> upload(HttpServletRequest request) throws Exception { UUID uuid = UUID.randomUUID(); byte[] file = request.getPart("file").getInputStream().readAllBytes(); System.out.printf("=================== %s ===========================%n", uuid); System.out.println(Arrays.toString(file).substring(0, 2750)); Path path = Paths.get(".\\file_" + uuid +".pdf"); try { Files.write(path, file);} catch (IOException exception) { throw new RuntimeException(exception); } return ResponseEntity.ok().build(); }}
From that controller I generate 2 open api files.
openapi: 3.0.1info: title: OpenAPI definition version: v0servers: - url: http://localhost:8080 description: Generated server urlpaths: /upload: post: tags: - app operationId: upload requestBody: content: multipart/form-data: schema: type: object properties: info: $ref: '#/components/schemas/Info' file: type: string format: binary responses:'200': description: OK /test: get: tags: - app operationId: test responses:'200': description: OKcomponents: schemas: Info: type: object properties: firstname: type: string lastname: type: string
And the second with a little change, I remove the format: binary
file: type: string
Then, with the openapi-generator-maven-plugin
I generate 2 clients.
For the first definition file, the plugin generates a method with that signature
public void upload(Info info, File _file)
And for the second
public void upload(Info info, String _file)
I test all that with
File originalPdf;try { originalPdf = new ClassPathResource("Original.pdf").getFile(); }catch (IOException exception) { throw new RuntimeException(exception); }try { appApi.upload(new Info(), originalPdf); }catch (ApiException exception) { throw new RuntimeException(exception); }byte[] byteArray = new byte[(int) originalPdf.length()];try (FileInputStream inputStream = new FileInputStream(originalPdf)) { inputStream.read(byteArray);}catch (Exception exception) { throw new RuntimeException(exception); }try { appApiString.upload(new Info(), new String(byteArray)); }catch (ApiException exception) { throw new RuntimeException(exception); }
The original pdf contains (just the begining)
00000000: 2550 4446 2d31 2e37 0d0a 25b5 b5b5 b50d 0a31 2030 206f 626a :%PDF-1.7..%......1 0 obj00000018: 0d0a 3c3c 2f54 7970 652f 4361 7461 6c6f 672f 5061 6765 7320 :..<</Type/Catalog/Pages 00000030: 3220 3020 522f 4c61 6e67 2866 722d 4245 2920 2f53 7472 7563 :2 0 R/Lang(fr-BE) /Struc00000048: 7454 7265 6552 6f6f 7420 3136 2030 2052 2f4d 6172 6b49 6e66 :tTreeRoot 16 0 R/MarkInf00000060: 6f3c 3c2f 4d61 726b 6564 2074 7275 653e 3e2f 4d65 7461 6461 :o<</Marked true>>/Metada00000078: 7461 2034 3120 3020 522f 5669 6577 6572 5072 6566 6572 656e :ta 41 0 R/ViewerPreferen00000090: 6365 7320 3432 2030 2052 3e3e 0d0a 656e 646f 626a 0d0a 3220 :ces 42 0 R>>..endobj..2 000000a8: 3020 6f62 6a0d 0a3c 3c2f 5479 7065 2f50 6167 6573 2f43 6f75 :0 obj..<</Type/Pages/Cou000000c0: 6e74 2031 2f4b 6964 735b 2033 2030 2052 5d20 3e3e 0d0a 656e :nt 1/Kids[ 3 0 R] >>..en000000d8: 646f 626a 0d0a 3320 3020 6f62 6a0d 0a3c 3c2f 5479 7065 2f50 :dobj..3 0 obj..<</Type/P000000f0: 6167 652f 5061 7265 6e74 2032 2030 2052 2f52 6573 6f75 7263 :age/Parent 2 0 R/Resourc00000108: 6573 3c3c 2f46 6f6e 743c 3c2f 4631 2035 2030 2052 3e3e 2f45 :es<</Font<</F1 5 0 R>>/E00000120: 7874 4753 7461 7465 3c3c 2f47 5337 2037 2030 2052 2f47 5338 :xtGState<</GS7 7 0 R/GS800000138: 2038 2030 2052 3e3e 2f58 4f62 6a65 6374 3c3c 2f49 6d61 6765 : 8 0 R>>/XObject<</Image00000150: 3131 2031 3120 3020 522f 496d 6167 6531 3320 3133 2030 2052 :11 11 0 R/Image13 13 0 R00000168: 3e3e 2f50 726f 6353 6574 5b2f 5044 462f 5465 7874 2f49 6d61 :>>/ProcSet[/PDF/Text/Ima00000180: 6765 422f 496d 6167 6543 2f49 6d61 6765 495d 203e 3e2f 416e :geB/ImageC/ImageI] >>/An00000198: 6e6f 7473 5b20 3920 3020 5220 3130 2030 2052 5d20 2f4d 6564 :nots[ 9 0 R 10 0 R] /Med000001b0: 6961 426f 785b 2030 2030 2035 3935 2e33 3220 3834 312e 3932 :iaBox[ 0 0 595.32 841.92000001c8: 5d20 2f43 6f6e 7465 6e74 7320 3420 3020 522f 4772 6f75 703c :] /Contents 4 0 R/Group<000001e0: 3c2f 5479 7065 2f47 726f 7570 2f53 2f54 7261 6e73 7061 7265 :</Type/Group/S/Transpare000001f8: 6e63 792f 4353 2f44 6576 6963 6552 4742 3e3e 2f54 6162 732f :ncy/CS/DeviceRGB>>/Tabs/00000210: 532f 5374 7275 6374 5061 7265 6e74 7320 303e 3e0d 0a65 6e64 :S/StructParents 0>>..end00000228: 6f62 6a0d 0a34 2030 206f 626a 0d0a 3c3c 2f46 696c 7465 722f :obj..4 0 obj..<</Filter/00000240: 466c 6174 6544 6563 6f64 652f 4c65 6e67 7468 2034 3230 3e3e :FlateDecode/Length 420>>00000258: 0d0a 7374 7265 616d 0d0a 789c ad95 d16b 1431 10c6 df17 f67f :..stream..x....k.1......
On the last line starting at the e of stream it gives 616d 0d0a 789c ad95
so 114, 101, 97, 109, 13, 10, 120, -100
Now looking at the results of the upload api.
With the pdf as File, the same bytes sequence is 114, 101, 97, 109, 13, 10, 120, -100
And it is ok.
With the pdf as String, the sequence is 114, 101, 97, 109, 13, 10, 120, -17
What could make such a difference ? Is it a encoding problem ?
I tried adding utf-8
or cp1252
for the new String(byteArray)
. For each the sequence (-100) is different but none is right.
And looking at the client log, for the first try (File)
Content-Disposition: form-data; name="file"; filename="Original.pdf"Content-Type: application/pdfContent-Length: 51375
and for the second (String)
Content-Disposition: form-data; name="file"Content-Type: text/plain; charset=utf-8Content-Length: 87293
The length is the same as original for the first and much larger for the second.
What can I do ?