What I found out when trying to send multipart/form-data requests with CXF v3.5:
1. You can have just one request body parameter. This can be a MultipartBody, or a List<Attachment> but you'll have to set the headers (Content-ID,Content-Type, Content-Disposition) yourself. 2. I believe you can also have just one request body parameter representing a List<Files> or a single File. Here a Content-Disposition header will be set based on the filename (didn't check this, but the code seems to reveal this). 3. You can have just one request parameter annotated with @Multipart. This will add the Content-ID and Content-Type headers based on the annotation, but not the Content-Disposition. 4. You can have multiple request body parameters but then all of them need to be annotated with @Multipart. This will add the headers Content-Type and Content-ID as specified in the annotation, but it will not add a 'Content-Disposition' header. So the OpenAPI specification/examples as enlisted below requires us to convert everything to attachments (to get the Content-Disposition header in place) and either send a request body consisting of a List<Attachment> or MultipartBody. The fact that in CXF-v3.5.x you can not: * specify a Content-Disposition header for a @Multipart input parameter * mix Attachment objects with @Multipart annotated objects (which by the stack are converted to Attachment objects) as a list of input parameters seems to be a short-coming. It doesn't align well with the OpenAPI v3.0.x specification. Is this a correct conclusion? Regards, J.P. Urkens -----Oorspronkelijk bericht----- Van: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com> Verzonden: donderdag 14 november 2024 11:29 Aan: 'Andriy Redko' <drr...@gmail.com>; 'dev@cxf.apache.org' <dev@cxf.apache.org> Onderwerp: RE: CXF JAX-RS: working with multipart form-data Hi Andriy, Actually, I think you'll have to set the Content-Disposition yourself in the Attachment object, while for File objects it will be retrieved from the file name. Looking at https://swagger.io/docs/specification/v3_0/describing-request-body/multipa rt-requests/ how would you translate the request body to an method signature that works with CXF (v3.5.x)? The example shows the 'Content-Disposition' header to be present for all multipart parts irrespective of their data type and that is something I don't know how to achieve in a clean way using CXF. The @org.apache.cxf.jaxrs.ext.multipart.Multipart annotation won't do the job and CXF only adds it for File objects and for Attachment objects (if it is present in the Attachment object). Regards, J.P. -----Oorspronkelijk bericht----- Van: Andriy Redko <drr...@gmail.com> Verzonden: woensdag 13 november 2024 23:42 Aan: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; dev@cxf.apache.org Onderwerp: Re: CXF JAX-RS: working with multipart form-data Hi Jean, JPU> When looking at the classes MultipartProvider and JAXRSUtils (cxf v3.5.9) JPU> then it shows that only object for which a 'Content-Disposition' header will JPU> be written is a File Object. The problem is that my application is JPU> generating the file content on the fly, so I have it either as a byte[] or JPU> InputStream. I believe the 'Content-Disposition' will be written for File and Attachment. Respectively, it is going to be read for these multipart content parts as well. This is why the @Multipart annotation has no 'Content-Disposition' or alike (I think). > JPU> Even passing a List<Attachment> doesn't work as the MultiPartProvider will JPU> loop through the list and try to create a DataHandler for an Attachment JPU> object which is also not supported (throws an exception). This is surprising, I will take a look shortly why it does not work. What kind of exception are you getting? Thank you. Best Regards, Andriy Redko JPU> Hi Andriy, JPU> When looking at the classes MultipartProvider and JAXRSUtils (cxf v3.5.9) JPU> then it shows that only object for which a 'Content-Disposition' header will JPU> be written is a File Object. The problem is that my application is JPU> generating the file content on the fly, so I have it either as a byte[] or JPU> InputStream. JPU> This surprises me as according to JPU> https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposit ion: JPU> "a multipart/form-data body requires a Content-Disposition header to provide JPU> information about each subpart of the form (e.g., for every form field and JPU> any files that are part of field data)". JPU> Also the Multipart annotation class only allows to specify Content-Type, JPU> Content-ID so there is no way for me to provide 'Content-Disposition' JPU> information on objects like byte[] or InputStream. JPU> Even passing a List<Attachment> doesn't work as the MultiPartProvider will JPU> loop through the list and try to create a DataHandler for an Attachment JPU> object which is also not supported (throws an exception). JPU> The only way I see to pass it is to construct Attachment objects for each JPU> multipart part, with 'Content-Disposition' set, and add them all to a JPU> MultipartBody object and pass this as input parameter to my method JPU> signature. But then I loose all swager information for input objects that JPU> are not byte[] or InputStream. JPU> Am I missing something? JPU> Regards, JPU> J.P. JPU> -----Oorspronkelijk bericht----- JPU> Van: Andriy Redko <drr...@gmail.com> JPU> Verzonden: vrijdag 4 oktober 2024 2:52 JPU> Aan: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; JPU> dev@cxf.apache.org JPU> Onderwerp: Re: CXF JAX-RS: working with multipart form-data JPU> Hi Jean, JPU> Yeah, I think the @Multipart + Attachment may not work, but you could accept JPU> the List<Attachment> instead, right? (since you send many). JPU> The logging configuration does not seem right: you use interceptors AND JPU> feature (as per snippet below). JPU> factory.getOutInterceptors().add(new JPU> LoggingOutInterceptor()); JPU> factory.getInInterceptors().add(new JPU> LoggingInInterceptor()); JPU> LoggingFeature feature = new LoggingFeature(); JPU> feature.setLogMultipart(true); JPU> feature.setLogBinary(true); JPU> ... JPU> You only need one of those, either interceptors (please configure JPU> setLogBinary & setLogMultipart for them): JPU> factory.getOutInterceptors().add(new JPU> LoggingOutInterceptor()); JPU> factory.getInInterceptors().add(new JPU> LoggingInInterceptor()); JPU> Or feature: JPU> LoggingFeature feature = new LoggingFeature(); JPU> feature.setLogMultipart(true); JPU> feature.setLogBinary(true); JPU> ... JPU> Hope it helps, thanks! JPU> Best Regards, JPU> Andriy Redko JPU>> Hi Andriy, JPU>> Thanks for the swift response, but I could still use some JPU> clarifications on: JPU>> 1) You mention that passing an Attachment object as service method JPU>> parameter should work. JPU>> My initial test setup did pass an Attachment object as input JPU>> parameter as shown in ">>> 1)API interface declaration" in my mail. However when the JPU>> client (see code below) tries to send a request with this JPU>> signature, the JPU>> JAXRSUtils.writeMessageBody(...) method that is called by the CXF JPU>> stack throws an exception on the Attachment parameter saying: JPU>> okt 03, 2024 9:46:54 AM JPU>> org.apache.cxf.jaxrs.provider.MultipartProvider JPU>> getHandlerForObject SEVERE: No message body writer found for class JPU>> : class org.apache.cxf.jaxrs.ext.multipart.Attachment. JPU>> okt 03, 2024 9:47:05 AM JPU>> org.apache.cxf.jaxrs.utils.JAXRSUtils JPU>> logMessageHandlerProblem SEVERE: Problem with writing the data, JPU>> class java.util.ArrayList, ContentType: multipart/form-data JPU>> okt 03, 2024 9:47:14 AM JPU>> org.apache.cxf.phase.PhaseInterceptorChain JPU>> doDefaultLogging WARNING: Interceptor for JPU>> {http://api.documenten.magda.common.aeo.dvtm.be/}MessagesApi has JPU>> thrown exception, unwinding now JPU>> org.apache.cxf.interceptor.Fault: Problem with JPU>> writing the data, class java.util.ArrayList, ContentType: JPU> multipart/form-data JPU>> at JPU>> JPU> org.apache.cxf.jaxrs.client.ClientProxyImpl$BodyWriter.doWriteBody(ClientP roxyImpl.java:1142) JPU>> at JPU>> org.apache.cxf.jaxrs.client.AbstractClient$AbstractBodyWriter.handl JPU>> eMessage(AbstractClient.java:1223) JPU>> The JAXRSUtils.writeMessageBody(...) method takes an 'entity' JPU>> Object that is a List<Attachment>. The first Attachment in the list JPU>> contains an object of type MessageToSend, while the second one JPU>> contains an object of type Attachment for which 'no message body JPU> writer' could be found. JPU>> The stack creates itself an Attachment object for each parameter of JPU>> the multipart body, that is why I though that I can not pass it as JPU>> a parameter to my service method. I guess I am not allowed to annotate JPU> an 'Attachment' JPU>> parameter with @Multipart annotation as currently done in the JPU>> method JPU>> signature: JPU>> @FormDataParam(value="upfile1") @Parameter(schema = JPU>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>> "upfile1", type="application/pdf", required = false) Attachment JPU>> upfile1Detail JPU>> However leaving the @Multipart annotation for the Attachment JPU>> parameter away leads to the error: JPU>> javax.ws.rs.ProcessingException: Resource method JPU>> be.dvtm.aeo.common.magda.documenten.api.MessagesApi.createMessage2 JPU>> has more than one parameter representing a request body JPU>> I.e. now it is no longer clear that the Attachment parameter is JPU>> part of the 'multipart'. That's why I switched to using an JPU>> InputStream as parameter with @Multipart annotation but then I loose JPU> the Content-Disposition information. JPU>> The @Multipart annotation doesn't allow to specify JPU>> Content-Disposition information. Is there an alternative here? JPU>> 2) Logging of Binary Data. I create my client with: JPU>> private static MessagesApi getThreadsafeProxy(String JPU> baseAddress) { JPU>> JacksonJsonProvider jjProvider = new JPU>> JacksonJsonProvider(new CustomObjectMapper()); JPU>> List<Object> providers = Arrays.asList(new JPU>> MultipartProvider(), jjProvider); JPU>> final JAXRSClientFactoryBean factory = new JPU> JAXRSClientFactoryBean(); JPU>> factory.setAddress(baseAddress); JPU>> factory.setServiceClass(MessagesApi.class); JPU>> factory.setProviders(providers); JPU>> factory.getOutInterceptors().add(new JPU> LoggingOutInterceptor()); JPU>> factory.getInInterceptors().add(new JPU> LoggingInInterceptor()); JPU>> factory.setThreadSafe(true); JPU>> LoggingFeature feature = new LoggingFeature(); JPU>> feature.setLogMultipart(true); JPU>> feature.setLogBinary(true); JPU>> JPU> feature.addBinaryContentMediaTypes(MediaType.APPLICATION_OCTET_STREAM); JPU>> feature.addBinaryContentMediaTypes("application/pdf"); JPU>> factory.setFeatures(Arrays.asList(feature)); JPU>> MessagesApi api = factory.create(MessagesApi.class); JPU>> ClientConfiguration config = WebClient.getConfig(api); JPU>> addTLSClientParameters(config.getHttpConduit()); JPU>> return api; JPU>> } JPU>> Here I do activate the logging for multipart and binary and also JPU>> added some mediatypes (although couldn't find what it actually JPU>> does). So I was expecting to see the whole message (attachments are JPU>> rather small as it is a test). JPU>> Well I used wireshark to get the full message and it doesn't show JPU>> any Content-Disposition headers for the multipart elements. JPU>> Regards, JPU>> J.P. Urkens JPU>> -----Original Message----- JPU>> From: Andriy Redko <drr...@gmail.com> JPU>> Sent: donderdag 3 oktober 2024 1:01 JPU>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; JPU>> dev@cxf.apache.org JPU>> Subject: Re: CXF JAX-RS: working with multipart form-data JPU>> Hi Jean, JPU>>> What is the correct way to annotate a file attachment as part of a JPU>>> mutlipart/form-data content body? JPU>> We have many examples in our test suites over here [1], it really JPU>> depends on the problem at hand. JPU>>> -> Question-01: Is this the appropriate way to pass files JPU>>> (PDF documents) as attachment in a mutlipart/form-data request, or JPU>>> are JPU>> there better ways? JPU>> You would probably better of with "multipart/mixed" [2] as in you JPU>> case, you are sending different data types. But JPU>> "multipart/form-data" should be fine as well. The right answer JPU>> answer depends on how large the files are. In many cases you are JPU>> better off using chunked transfer (no need to read the whole file in JPU> memory), like you do with InputStream. JPU>>> -> Question-02: When I activate logging, I can't see JPU>>> anything about the file attachment, not is content, nor the JPU>>> appropriate Content-Disposition settings? I get '--Content JPU>> suppressed--', e.g.: JPU>> Correct, by default the logging interceptors do not log binary JPU>> data, you could checks the docs here [3]. JPU>>> -> Question-03: Don't I need to set anything regarding the JPU>>> Content-Disposition header? The example here is simplified in a JPU>>> sense that I used a test setup with just one file attachment. In JPU>>> the real interface up to JPU>>> 20 attachments can be passed. Somehow I need to know which part JPU>>> relates JPU>> to JPU>>> which attachment or not? JPU>> This is probably caused by the fact you are sending the InputStream JPU>> and not an Attachment, if my understanding is correct. I am pretty JPU>> sure passing the Attachment (as you did initially) should work. JPU>>> -> Question-04: At the server implemtation side, since JPU>>> upfile1Detail is passed as a method parameter, who is going to JPU>>> close this InputStream at the server side? JPU>> The stream should be closed by the service implementation (since JPU>> the stream is expected to be consumed). The Apache CXF runtime will JPU>> try to close the stream in most cases as well but sometimes it may not JPU> be able to. JPU>> Hope it answers your questions. Thanks! JPU>> [1] JPU>> https://github.com/apache/cxf/blob/main/systests/jaxrs/src/test/jav JPU>> a/org/apache/cxf/systest/jaxrs/MultipartStore.java JPU>> [2] JPU>> https://learn.microsoft.com/en-us/exchange/troubleshoot/administrat JPU>> ion/multipart-mixed-mime-message-format JPU>> [3] https://cxf.apache.org/docs/message-logging.html JPU>> Best Regards, JPU>> Andriy Redko JPU>>> Hi Andriy, JPU>>> What is the correct way to annotate a file attachment as part of a JPU>>> mutlipart/form-data content body? JPU>>> I currently have the following (only the relevant parts): JPU>>> 1)API interface declaration JPU>>> ====================== JPU>>> @POST JPU>>> @Path("/messages1") JPU>>> @Consumes("multipart/form-data") JPU>>> @Produces({ "application/json" }) JPU>>> @Operation(...) JPU>>> @ApiResponses(...) JPU>>> Response createMessage1( JPU>>> @HeaderParam("x-correlation-id") @NotNull JPU>>> @Size(min = 10, max = 36) @Parameter(description="ID of the JPU>>> transaction. Use this ID for log tracing and incident handling.") JPU>> String xCorrelationId, JPU>>> @HeaderParam("Idempotency-Key") @NotNull JPU>>> @Size(min = 10, max = 36) @Parameter(description="When retrying a JPU>>> failed call, the retry call should have the same Idempotency JPU>>> Key.") JPU>> String idempotencyKey, JPU>>> @FormDataParam(value="messageToSend") JPU>>> @Parameter(required=true,schema = JPU>>> @Schema(implementation=MessageToSend.class)) @Multipart(value = JPU>>> "messageToSend", type="application/json", required= true) JPU>>> MessageToSend messageToSend, JPU>>> @FormDataParam(value="upfile1") JPU>>> @Parameter(schema = @Schema(type = "string", format = "binary")) JPU>>> @Multipart(value = "upfile1", type="application/octet-stream", JPU>>> required = false) Attachment upfile1Detail); JPU>>> So I pass the file to upload as an Attachment object. JPU>>> 2)API client test code JPU>>> ================= JPU>>> String xCorrelationId = UUID.randomUUID().toString(); JPU>>> String idempotencyKey = JPU>>> UUID.randomUUID().toString(); JPU>>> //01. Get the attachment to include JPU>>> String fileName = "test.pdf"; JPU>>> try (InputStream is = JPU>>> this.getClass().getClassLoader().getResourceAsStream(fileName); JPU>>> BufferedReader reader = new JPU>>> BufferedReader(new InputStreamReader(is))) { JPU>>> if (is == null) { JPU>>> Assert.fail("Couldn't load JPU>>> test.pdf JPU>> from classpath!"); JPU>>> } JPU>>> DataHandler dataHandler = new JPU>>> DataHandler(is, JPU>> "application/pdf"); JPU>>> ContentDisposition cd = new JPU>>> ContentDisposition("attachment;name=upfile1;filename="+fileName); JPU>>> Attachment upfile1Detail = new JPU>> AttachmentBuilder() JPU>>> .id("upfile1") JPU>>> .dataHandler(dataHandler) JPU>>> .contentDisposition(cd) JPU>>> .mediaType("application/pdf") JPU>>> .build(); JPU>>> //02. create the message to send JPU>>> MessageToSend mts = new MessageToSend(); JPU>>> //03. Call the server JPU>>> Response resp = JPU>>> apiClient.createMessage1(xCorrelationId, idempotencyKey, mts, JPU>>> upfile1Detail); JPU>>> When running the API client test code and getting at '03.' The method: JPU>>> JAXRSUtils.writeMessageBody(List<WriterInterceptor> JPU>>> writers,Object entity,Class<?> type, Type genericType,Annotation[] JPU>>> annotations,MediaType mediaType,MultivaluedMap<String, Object> JPU>>> httpHeaders,Message message) JPU>>> is called. The 'entity' object is a list of Attachment objects where: JPU>>> - the first Attachment object contains an object of type JPU>>> MessageToSend JPU>>> - the second Attachment object contains an object of type JPU>>> Attachment JPU>>> This second object leads to a fatal error within the JPU>>> JAXRSUtils.writeMessageBody(...) method: JPU>>> okt 02, 2024 1:36:02 PM JPU>>> org.apache.cxf.jaxrs.provider.MultipartProvider JPU>>> getHandlerForObject JPU>>> SEVERE: No message body writer found for class : class JPU>>> org.apache.cxf.jaxrs.ext.multipart.Attachment. JPU>>> okt 02, 2024 1:36:02 PM JPU>>> org.apache.cxf.jaxrs.utils.JAXRSUtils JPU>>> logMessageHandlerProblem JPU>>> SEVERE: Problem with writing the data, class JPU>>> java.util.ArrayList, JPU>>> ContentType: multipart/form-data JPU>>> I modified the interface and implementation classes to use JPU>>> 'InputStream upfile1Detail' as type for the input parameter of the JPU>>> service method. And in this case my 'dummy' server implementation JPU>>> can read the file and save it to disk. JPU>>> -> Question-01: Is this the appropriate way to pass files JPU>>> (PDF documents) as attachment in a mutlipart/form-data request, or JPU>>> are JPU>> there better ways? JPU>>> -> Question-02: When I activate logging, I can't see JPU>>> anything about the file attachment, not is content, nor the JPU>>> appropriate Content-Disposition settings? I get '--Content JPU>> suppressed--', e.g.: JPU>>> [MAGDADOC] 2024-10-02 14:29:08,911 [main] INFO JPU>>> $--$ JPU>>> (org.apache.cxf.ext.logging.slf4j.Slf4jEventSender:84) - REQ_OUT JPU>>> Address: JPU>>> http://localhost:8091/services/magdadoc/api/v1/messages/messages1 JPU>>> HttpMethod: POST JPU>>> Content-Type: multipart/form-data; JPU>>> boundary="uuid:3c3fa9c0-8470-4655-b026-3ed09f79e862" JPU>>> ExchangeId: a583a695-d881-4fa7-b65a-8961cdbbd412 JPU>>> Headers: {Authorization=Bearer JPU>>> f4262ccf-3250-4bcf-a1bc-7ee1bf9a56cf, JPU>>> Accept=application/json, JPU>>> Idempotency-Key=bd06c05d-9fe2-4b60-b8db-5ad1121b74dc, JPU>>> x-correlation-id=511c51ba-95fe-4f69-9443-f05c377cffab} JPU>>> Payload: JPU>>> --uuid:3c3fa9c0-8470-4655-b026-3ed09f79e862 JPU>>> Content-Type: application/json JPU>>> Content-Transfer-Encoding: binary JPU>>> Content-ID: <messageToSend> JPU>>> { JPU>>> "delivery" : "AUTOMATIC", JPU>>> "eboxDeliveryData" : { /* all fine */}, JPU>>> "paperDeliveryData" : {/* all fine */}, JPU>>> "emailDeliveryData" : null, JPU>>> "businessData" : [ ] JPU>>> } JPU>>> --uuid:3c3fa9c0-8470-4655-b026-3ed09f79e862 JPU>>> --- Content suppressed --- JPU>>> -> Question-03: Don't I need to set anything regarding the JPU>>> Content-Disposition header? The example here is simplified in a JPU>>> sense that I used a test setup with just one file attachment. In JPU>>> the real interface up to JPU>>> 20 attachments can be passed. Somehow I need to know which part JPU>>> relates JPU>> to JPU>>> which attachment or not? JPU>>> -> Question-04: At the server implemtation side, since JPU>>> upfile1Detail is passed as a method parameter, who is going to JPU>>> close this InputStream at the server side? JPU>>> Regards, JPU>>> J.P. Urkens JPU>>> P.S.: Is there a migration document describing upgrading CXF-3.5.6 JPU>>> (my current version) to CXF-3.5.8 (latest JDK8 version). I'd like JPU>>> to know whether upgrading can happen without too much burden. JPU>>> -----Original Message----- JPU>>> From: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com> JPU>>> Sent: vrijdag 5 juli 2024 13:04 JPU>>> To: 'Andriy Redko' <drr...@gmail.com>; 'dev@cxf.apache.org' JPU>>> <dev@cxf.apache.org> JPU>>> Subject: RE: CXF JAX-RS: working with multipart form-data JPU>>> Hi Andriy, JPU>>> When searching the net I came along this Jersey annotation but JPU>>> since I was not depending on 'Jersey' components I skipped it. So JPU>>> apparently swagger-core has processing for externally defined JPU>>> annotations (like this FormDataParam in Jersey), indeed inside JPU>> know-how. JPU>>> I included it in my project as JPU>>> io.swagger.v3.oas.annotations.FormDataParam, JPU>>> since it should somehow be included in the supported swagger JPU>>> annotations (maybe we should submit a request for it to the JPU>>> swagger-core team) and this indeed generates an appropriate JPU>> openapi.json spec. JPU>>> Thanks alot, JPU>>> J.P. Urkens JPU>>> -----Original Message----- JPU>>> From: Andriy Redko <drr...@gmail.com> JPU>>> Sent: vrijdag 5 juli 2024 2:16 JPU>>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; JPU>>> dev@cxf.apache.org JPU>>> Subject: Re: CXF JAX-RS: working with multipart form-data JPU>>> Hi Jean, JPU>>> Here is how you could make it work (there is some magic knowledge JPU>>> involved sadly). First of all, define such annotation anywhere in JPU>>> your codebase (where it dims appropriate): JPU>>> import java.lang.annotation.ElementType; import JPU>>> java.lang.annotation.Retention; import JPU>>> java.lang.annotation.RetentionPolicy; JPU>>> import java.lang.annotation.Target; JPU>>> @Target({ElementType.PARAMETER, ElementType.METHOD, JPU>>> ElementType.FIELD}) JPU>>> @Retention(RetentionPolicy.RUNTIME) JPU>>> public @interface FormDataParam { JPU>>> String value(); JPU>>> } JPU>>> Use this annotation on each Attachment parameter: JPU>>> /* Skipping other annotations as those are not important here */ JPU>>> public Response createMessage( JPU>>> @HeaderParam("x-correlation-id") @NotNull @Size(min = 10, JPU>>> max = 36) @Parameter(description="ID of the transaction. Use this JPU>>> ID for log tracing and incident handling.") String xCorrelationId, JPU>>> @HeaderParam("Idempotency-Key") @Size(min = 10, max = 36) JPU>>> @Parameter(description="When retrying a failed call, the retry JPU>>> call should have the same Idempotency Key.") String idempotencyKey, JPU>>> @FormDataParam("upfile1") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile1", type="application/octet-stream", required = false) JPU>>> InputStream upfile1Detail, JPU>>> @FormDataParam("upfile2") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile2", type="application/octet-stream", required = false) JPU>>> InputStream upfile2Detail, JPU>>> @FormDataParam("upfile3") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile3", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile3Detail, JPU>>> @FormDataParam("upfile4") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile4", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile4Detail, JPU>>> @FormDataParam("upfile5") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile5", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile5Detail, JPU>>> @FormDataParam("upfile6") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile6", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile6Detail, JPU>>> @FormDataParam("upfile7") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile7", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile7Detail, JPU>>> @FormDataParam("upfile8") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile8", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile8Detail, JPU>>> @FormDataParam("upfile9") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile9", type="application/octet-stream", required = false) JPU>>> Attachment JPU>> upfile9Detail, JPU>>> @FormDataParam("upfile10") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile10", type="application/octet-stream", required = false) JPU>>> Attachment upfile10Detail, JPU>>> @FormDataParam("upfile11") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile11", type="application/octet-stream", required = false) JPU>>> Attachment upfile11Detail, JPU>>> @FormDataParam("upfile12") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile12", type="application/octet-stream", required = false) JPU>>> Attachment upfile12Detail, JPU>>> @FormDataParam("upfile13") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile13", type="application/octet-stream", required = false) JPU>>> Attachment upfile13Detail, JPU>>> @FormDataParam("upfile14") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile14", type="application/octet-stream", required = false) JPU>>> Attachment upfile14Detail, JPU>>> @FormDataParam("upfile15") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile15", type="application/octet-stream", required = false) JPU>>> Attachment upfile15Detail, JPU>>> @FormDataParam("upfile16") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile16", type="application/octet-stream", required = false) JPU>>> Attachment upfile16Detail, JPU>>> @FormDataParam("upfile17") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile17", type="application/octet-stream", required = false) JPU>>> Attachment upfile17Detail, JPU>>> @FormDataParam("upfile18") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile18", type="application/octet-stream", required = false) JPU>>> Attachment upfile18Detail, JPU>>> @FormDataParam("upfile19") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile19", type="application/octet-stream", required = false) JPU>>> Attachment upfile19Detail, JPU>>> @FormDataParam("upfile20") @Parameter(schema = JPU>>> @Schema(type = "string", format = "binary")) @Multipart(value = JPU>>> "upfile20", type="application/octet-stream", required = false) JPU>>> Attachment upfile20Detail, JPU>>> @FormDataParam("qrfile") @Parameter(schema = @Schema(type JPU>>> = "string", format = "binary")) @Multipart(value = "qrfile", JPU>>> type="application/octet-stream", required = false) Attachment JPU>> qrfileDetail JPU>>> ) { JPU>>> .... JPU>>> } JPU>>> With that, you will get a nice request body schema (publishing a JPU>>> bit large YAML snippet to preserve the context): JPU>>> paths: JPU>>> /sample/messages: JPU>>> post: JPU>>> tags: JPU>>> - messages JPU>>> summary: "Send a message, using a channel (email, paper JPU>>> mail, JPU>>> ebox) and delivery\ JPU>>> \ method (registered or normal) of your choice. More than JPU>>> 6 upfiles only supported\ JPU>>> \ for PAPER delivery." JPU>>> operationId: createMessage JPU>>> parameters: JPU>>> - name: x-correlation-id JPU>>> in: header JPU>>> description: ID of the transaction. Use this ID for log JPU>>> tracing and incident JPU>>> handling. JPU>>> required: true JPU>>> schema: JPU>>> maxLength: 36 JPU>>> minLength: 10 JPU>>> type: string JPU>>> - name: Idempotency-Key JPU>>> in: header JPU>>> description: "When retrying a failed call, the retry call JPU>>> should have the\ JPU>>> \ same Idempotency Key." JPU>>> schema: JPU>>> maxLength: 36 JPU>>> minLength: 10 JPU>>> type: string JPU>>> requestBody: JPU>>> content: JPU>>> multipart/form-data: JPU>>> schema: JPU>>> type: object JPU>>> properties: JPU>>> upfile1: JPU>>> type: string JPU>>> format: binary JPU>>> upfile2: JPU>>> type: string JPU>>> format: binary JPU>>> upfile3: JPU>>> type: string JPU>>> format: binary JPU>>> upfile4: JPU>>> type: string JPU>>> format: binary JPU>>> upfile5: JPU>>> type: string JPU>>> format: binary JPU>>> upfile6: JPU>>> type: string JPU>>> format: binary JPU>>> upfile7: JPU>>> type: string JPU>>> format: binary JPU>>> upfile8: JPU>>> type: string JPU>>> format: binary JPU>>> upfile9: JPU>>> type: string JPU>>> format: binary JPU>>> upfile10: JPU>>> type: string JPU>>> format: binary JPU>>> upfile11: JPU>>> type: string JPU>>> format: binary JPU>>> upfile12: JPU>>> type: string JPU>>> format: binary JPU>>> upfile13: JPU>>> type: string JPU>>> format: binary JPU>>> upfile14: JPU>>> type: string JPU>>> format: binary JPU>>> upfile15: JPU>>> type: string JPU>>> format: binary JPU>>> upfile16: JPU>>> type: string JPU>>> format: binary JPU>>> upfile17: JPU>>> type: string JPU>>> format: binary JPU>>> upfile18: JPU>>> type: string JPU>>> format: binary JPU>>> upfile19: JPU>>> type: string JPU>>> format: binary JPU>>> upfile20: JPU>>> type: string JPU>>> format: binary JPU>>> qrfile: JPU>>> type: string JPU>>> format: binary JPU>>> The key here is @FormDataParam annotation which (originally) comes JPU>>> from Jersey but has special treatment in Swagger Core (but, JPU>>> likely, no attribution to Jersey). JPU>>> Hope it helps! JPU>>> Thank you. JPU>>> Best Regards, JPU>>> Andriy Redko >>>> V2.2.22 (15/05/2024) is the latest version of io.swagger.core.v3 >>>> libraries. >>>> I upgrade to this version to make sure I had the latest swagger >>>> implementation. >>>> -----Original Message----- >>>> From: Andriy Redko <drr...@gmail.com> >>>> Sent: donderdag 4 juli 2024 4:44 >>>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; >>>> dev@cxf.apache.org >>>> Subject: Re: CXF JAX-RS: working with multipart form-data >>>> Hi Jean, >>>> Interesting, I was experimenting with different ways to express what >>>> you need, but no luck so far, I will try to spend a bit more time on >>>> that this week since OAS 3.x does support multipart [1] but we may >>>> indeed hit the >>>> limitation(s) of this particular Swagger Core version. Thank you. >>>> [1] >>>> https://swagger.io/docs/specification/describing-request-body/multip >>>> a >>>> r >>>> t-requests/ >>>> Best Regards, >>>> Andriy Redko >>>>> Hi Andriy, >>>>> I already tried this but it didn't work. E.g. for following API >>>>> interface >>>>> specification: >>>>> /** >>>>> * Send a message, using a channel (email, paper >>>>> mail, >>>>> ebox) and delivery method (registered or normal) of your choice. >>>>> More than >>>>> 6 upfiles only supported for PAPER delivery. >>>>> * >>>>> */ >>>>> @POST >>>>> @Path("/messages") >>>>> @Consumes("multipart/form-data") >>>>> @Produces({ "application/json" }) >>>>> @Operation( >>>>> summary >>>>> = "Send a message, using a channel (email, paper mail, ebox) and >>>>> delivery method (registered or normal) of your choice. More than 6 >>>>> upfiles only supported for PAPER delivery.", >>>>> tags = >>>>> {"messages" }, operationId="createMessage", >>>>> security=@SecurityRequirement(name="BearerAuthentication")) >>>>> @ApiResponses({ @ApiResponse( responseCode = >>>>> "201", description = "Created", content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,array=@ArraySchema(sc >>>>> h e m a=@Schema(implementation=SendStatusMessage.class))), >>>>> headers = {@Header( >>>>> name="X-Magda-Exceptions", >>>>> required=false, >>>>> description="Only used in the context of EBOX delivery and if there >>>>> was a problem with the consent of the receiver's ebox.", >>>>> schema=@Schema(implementation=MagdaExceptionList.class)) >>>>> }), >>>>> @ApiResponse( >>>>> responseCode = "400", >>>>> description = "Invalid data supplied", content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implem >>>>> e >>>>> n >>>>> t >>>>> ation=ErrorMessage.class))), >>>>> @ApiResponse( >>>>> responseCode = "401", >>>>> description = "Invalid authorization", content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implem >>>>> e >>>>> n >>>>> t >>>>> ation=ErrorMessage.class))), >>>>> @ApiResponse( >>>>> responseCode = "500", >>>>> description = "Unexpected Server Error", content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implem >>>>> e >>>>> n >>>>> t >>>>> ation=ErrorMessage.class))), >>>>> @ApiResponse( >>>>> responseCode = "502", >>>>> description = "Bad Gateway", >>>>> content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implem >>>>> e >>>>> n >>>>> t >>>>> ation=ErrorMessage.class))), >>>>> @ApiResponse( >>>>> responseCode = "503", >>>>> description = "Service unavailable", content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implem >>>>> e >>>>> n >>>>> t >>>>> ation=ErrorMessage.class))), >>>>> @ApiResponse( >>>>> responseCode = "504", >>>>> description = "Gateway Timeout", >>>>> content = >>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implem >>>>> e >>>>> n >>>>> t >>>>> ation=ErrorMessage.class))) >>>>> }) >>>>> public Response createMessage( >>>>> @HeaderParam("x-correlation-id") @NotNull @Size(min = 10, max = 36) >>>>> @Parameter(description="ID of the transaction. Use this ID for log >>>>> tracing and incident handling.") String xCorrelationId, >>>>> @HeaderParam("Idempotency-Key") @Size(min = 10, max = 36) >>>>> @Parameter(description="When retrying a failed call, the retry call >>>>> should have the same Idempotency Key.") String idempotencyKey, >>>>> @Parameter(required=true,schema = >>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value = >>>>> "messageToSend", type="application/json", required= true) >>>>> MessageToSend messageToSend, @Parameter(schema = @Schema(type = >>>>> "string", format = "binary")) @Multipart(value = "upfile1", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile1Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile2", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile2Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile3", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile3Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile4", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile4Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile5", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile5Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile6", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile6Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile7", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile7Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile8", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile8Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile9", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile9Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile10", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile10Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile11", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile11Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile12", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile12Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile13", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile13Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile14", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile14Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile15", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile15Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile16", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile16Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile17", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile17Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile18", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile18Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile19", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile19Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "upfile20", >>>>> type="application/octet-stream", required = false) Attachment >>>>> upfile20Detail, @Parameter(schema = @Schema(type = "string", format >>>>> = >>>>> "binary")) @Multipart(value = "qrfile", >>>>> type="application/octet-stream", required = false) Attachment >>>>> qrfileDetail); I've attached the generated openapi specification. >>>>> It only contains the 'messageToSend' as part of the >>>>> multipart/form-data requestBody content, all attachments are ignored. >>>>> Below I've listed the libraries I've included in the project (cxf >>>>> v3.5.8 and swagger v2.2.2). Which of these libraries is acutal >>>>> responsible for generating the openapi.json specification from the >>>>> interface description? >>>>> * cxf-rt-rs-service-description-common-openapi:3.5.8 >>>>> * cxf-rt-rs-service-description-openapi:3.5.8 >>>>> * cxf-rt-rs-service-description-swagger-ui:3.5.8 >>>>> * swagger-core:2.2.2 >>>>> * swagger-annotations:2.2.2 >>>>> * swagger-integration:2.2.2 >>>>> * swagger-jaxrs2: 2.2.2 >>>>> * swagger-model: 2.2.2 >>>>> Note that I am still on JDK8, so I guess I can't upgrade to a >>>>> higher version (currently our projects use cxf-v3.5.6 and swagger >>>>> 2.1.13). >>>>> Regards, >>>>> J.P. Urkens >>>>> -----Original Message----- >>>>> From: Andriy Redko <drr...@gmail.com> >>>>> Sent: woensdag 3 juli 2024 5:57 >>>>> To: Jean Pierre URKENS <jean-pierre.urk...@devoteam.com>; >>>>> dev@cxf.apache.org >>>>> Subject: Re: CXF JAX-RS: working with multipart form-data Hi Jean >>>>> Pierre, I suspect the @Multipart annotation is coming from CXF >>>>> (org.apache.cxf.jaxrs.ext.multipart.Multipart), right? If yes, this >>>>> is not a part of JAX-RS specification but CXF specific extension. >>>>> You may need to add Swagger API annotation to the parameters in >>>>> question: >>>>> @Parameter(schema = @Schema(type = "string", format = "binary")) >>>>> Hope it helps. >>>>> Thank you. >>>>> Best Regards, >>>>> Andriy Redko >>>>> Monday, July 1, 2024, 12:09:17 PM, you wrote: >>>>>> Hi all, >>>>>> I am having problems to correctly annotate service methods which >>>>>> consumes multipart/form-data that contains attachments next to >>>>>> other model objects. >>>>>> I've an openapi specification that contains following requestBody >>>>>> definition: >>>>>> /messages: >>>>>> post: >>>>>> tags: >>>>>> - "messages" >>>>>> summary: "Send a message, using a channel (email, paper >>>>>> mail, >>>>>> ebox) and delivery method (registered or normal) of your choice. >>>>>> More than 6 upfiles only supported for PAPER delivery." >>>>>> operationId: createMessage >>>>>> parameters: >>>>>> - $ref: '#/components/parameters/CorrelationId' >>>>>> - $ref: '#/components/parameters/Idempotency-Key' >>>>>> requestBody: >>>>>> content: >>>>>> multipart/form-data: >>>>>> schema: >>>>>> type: object >>>>>> required: >>>>>> - messageToSend >>>>>> properties: >>>>>> messageToSend: >>>>>> $ref: '#/components/schemas/MessageToSend' >>>>>> upfile1: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile2: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile3: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile4: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile5: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile6: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile7: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile8: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile9: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile10: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile11: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile12: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile13: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile14: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile15: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile16: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile17: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile18: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile19: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> upfile20: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> qrfile: >>>>>> type: string >>>>>> format: binary >>>>>> nullable: true >>>>>> required: true >>>>>> When using the openapi-generator-maven-plugin v7.6.0 it generates >>>>>> following method signature: >>>>>> @POST >>>>>> @Path("/messages") >>>>>> @Consumes("multipart/form-data") >>>>>> @Produces({ "application/json" }) >>>>>> @Operation( >>>>>> summary = "Send a message, using a channel >>>>>> (email, paper mail, ebox) and delivery method (registered or >>>>>> normal) of your choice. More than 6 upfiles only supported for >>>>>> PAPER delivery.", >>>>>> tags = {"messages" }, >>>>>> operationId="createMessage", >>>>>> security=@SecurityRequirement(name="BearerAuthentication"), >>>>>> responses= { >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "201", >>>>>> >>>>>> description = "Created", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,array=@ArraySchema(s >>>>>> c h em a=@Schema(implementation=SendStatusMessage.class))), >>>>>> headers = >>>>>> {@Header( name="X-Magda-Exceptions", required=false, >>>>>> description="Only used in the context of EBOX delivery and if >>>>>> there was a problem with the consent of the receiver's ebox.", >>>>>> schema=@Schema(implementation=MagdaExceptionList.class)) >>>>>> }), >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "400", >>>>>> >>>>>> description = "Invalid data supplied", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(imple >>>>>> m >>>>>> e >>>>>> nt >>>>>> ation=ErrorMessage.class))), >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "401", >>>>>> >>>>>> description = "Invalid authorization", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(imple >>>>>> m >>>>>> e >>>>>> nt >>>>>> ation=ErrorMessage.class))), >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "500", >>>>>> >>>>>> description = "Unexpected Server Error", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(imple >>>>>> m >>>>>> e >>>>>> nt >>>>>> ation=ErrorMessage.class))), >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "502", >>>>>> >>>>>> description = "Bad Gateway", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(imple >>>>>> m >>>>>> e >>>>>> nt >>>>>> ation=ErrorMessage.class))), >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "503", >>>>>> >>>>>> description = "Service unavailable", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(imple >>>>>> m >>>>>> e >>>>>> nt >>>>>> ation=ErrorMessage.class))), >>>>>> @ApiResponse( >>>>>> >>>>>> responseCode = "504", >>>>>> >>>>>> description = "Gateway Timeout", >>>>>> content = >>>>>> @Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(imple >>>>>> m >>>>>> e >>>>>> nt >>>>>> ation=ErrorMessage.class))) >>>>>> }) >>>>>> public Response createMessage( >>>>>> @HeaderParam("x-correlation-id") @NotNull >>>>>> @Size(min = 10, max = 36) @Parameter(description="ID of the >>>>>> transaction. Use this ID for log tracing and incident handling.") >>>>>> String xCorrelationId, >>>>>> @HeaderParam("Idempotency-Key") @Size(min >>>>>> = 10, max = 36) @Parameter(description="When retrying a failed >>>>>> call, the retry call should have the same Idempotency Key.") >>>>>> String idempotencyKey, >>>>>> @Multipart(value = "messageToSend", >>>>>> required= >>>>>> true) MessageToSend messageToSend, >>>>>> @Multipart(value = "upfile1", required = >>>>>> false) Attachment upfile1Detail, >>>>>> @Multipart(value = "upfile2", required = >>>>>> false) Attachment upfile2Detail, >>>>>> @Multipart(value = "upfile3", required = >>>>>> false) Attachment upfile3Detail, >>>>>> @Multipart(value = "upfile4", required = >>>>>> false) Attachment upfile4Detail, >>>>>> @Multipart(value = "upfile5", required = >>>>>> false) Attachment upfile5Detail, >>>>>> @Multipart(value = "upfile6", required = >>>>>> false) Attachment upfile6Detail, >>>>>> @Multipart(value = "upfile7", required = >>>>>> false) Attachment upfile7Detail, >>>>>> @Multipart(value = "upfile8", required = >>>>>> false) Attachment upfile8Detail, >>>>>> @Multipart(value = "upfile9", required = >>>>>> false) Attachment upfile9Detail, >>>>>> @Multipart(value = "upfile10", required = >>>>>> false) Attachment upfile10Detail, >>>>>> @Multipart(value = "upfile11", required = >>>>>> false) Attachment upfile11Detail, >>>>>> @Multipart(value = "upfile12", required = >>>>>> false) Attachment upfile12Detail, >>>>>> @Multipart(value = "upfile13", required = >>>>>> false) Attachment upfile13Detail, >>>>>> @Multipart(value = "upfile14", required = >>>>>> false) Attachment upfile14Detail, >>>>>> @Multipart(value = "upfile15", required = >>>>>> false) Attachment upfile15Detail, >>>>>> @Multipart(value = "upfile16", required = >>>>>> false) Attachment upfile16Detail, >>>>>> @Multipart(value = "upfile17", required = >>>>>> false) Attachment upfile17Detail, >>>>>> @Multipart(value = "upfile18", required = >>>>>> false) Attachment upfile18Detail, >>>>>> @Multipart(value = "upfile19", required = >>>>>> false) Attachment upfile19Detail, >>>>>> @Multipart(value = "upfile20", required = >>>>>> false) Attachment upfile20Detail, >>>>>> @Multipart(value = "qrfile", required = >>>>>> false) Attachment qrfileDetail); If I now generate the swagger >>>>>> from this code (I modified the annotations in the generated code >>>>>> for using OAS v3 annotations through swagger-jaxrs2 v2.1.13 and I >>>>>> am using cxf-v3.5.6 having swagger-ui v4.18.2 generate the user >>>>>> interface) none of the upload files appears as request parameter, >>>>>> only the messageToSend is shown. >>>>>> Is the above signature for the method createMessage(...) incorrect? >>>>>> If I look at the generated openapi.json all the Attachment upFiles >>>>>> are missing from the specification? So is it a >>>>>> problem/short-coming(?) of the used software libraries, which then: >>>>>> . cxf-rt-rs-service-description-common-openapi v3.5.6 -> >>>>>> this library references swagger-jaxrs2 v2.1.13 . swagger-jaxrs2 >>>>>> v2.1.13 -> can I upgradethis >>>>>> to >>>>>> e.g. swagger-jaxrs2 v2.2.22 (latest) while retaining cxf v3.5.6? >>>>>> . ...another? >>>>>> Regards, >>>>>> J.P.