Does this also apply to mutlipart/mixed and multipart/related content
types?
Anyway I created https://issues.apache.org/jira/browse/CXF-9138.

Regards,

J.P.

-----Oorspronkelijk bericht-----
Van: Andriy Redko <[email protected]>
Verzonden: dinsdag 20 mei 2025 2:28
Aan: Jean Pierre URKENS <[email protected]>;
[email protected]
Onderwerp: Re: CXF JAX-RS: working with multipart form-data

Hi Jean,

I believe the rfc-7578 [1] deprecates Content-Transfer-Encoding (section
4.7), so
it should be safe to remove it. Please feel free to file an issue [2], it
should be an
easy fix. Thank you!

[1] https://www.rfc-editor.org/rfc/rfc7578
[2] https://issues.apache.org/jira/browse/

Best Regards,
    Andriy Redko

> Hi andriy,

> Indeed after omitting the Attachment::id property, which dropped the
> Content-ID header, it worked.
> However I couldn't get rid of the Content-Transfer-Encoding header, but
> the server seems to have no problem with it.

> Below the API method my client uses:
>         public Response createMessage(String xCorrelationId,String
> idempotencyKey,MessageToSend messageToSend,DataSource upfile1,DataSource
> upfile2,DataSource upfile3)
>         throws GeneralSecurityException, AuthorizationException {
>                 //Create a multipartbody
>                 List<Attachment> attachments = new ArrayList<>();
>                 attachments.add(new AttachmentBuilder()
>                                 .object(messageToSend)
>                                 .contentDisposition(new
> ContentDisposition("form-data; name=\"messageToSend\""))
>                                 .mediaType("application/json")
>                                 .build());
>
>                 if (upfile1 != null) {
>                         attachments.add(new AttachmentBuilder()
>                                         .dataHandler(new
> DataHandler(upfile1))
>                                         .contentDisposition(new
> ContentDisposition("form-data; name=\"upfile1\";
> filename=\""+upfile1.getName()+"\""))
>                                         .build());
>                 }
>                 if (upfile2 != null) {
>                         attachments.add(new AttachmentBuilder()
>                                         .dataHandler(new
> DataHandler(upfile2))
>                                         .contentDisposition(new
> ContentDisposition("form-data; name=\"upfile2\";
> filename=\""+upfile2.getName()+"\""))
>                                         .build());
>                 }
>                 if (upfile3 != null) {
>                         attachments.add(new AttachmentBuilder()
>                                         .dataHandler(new
> DataHandler(upfile3))
>                                         .contentDisposition(new
> ContentDisposition("form-data; name=\"upfile3\";
> filename=\""+upfile3.getName()+"\""))
>                                         .build());
>                 }
>                 MultipartBody body = new
> MultipartBody(attachments,MediaType.MULTIPART_FORM_DATA_TYPE,false);
>
>                 //Authorize API client
>                 Client client = WebClient.client(getApiProxy());
>
>
authorizationHandler.authorize(client,resourceClientId,consumerClientId,Ma
> gdadocService.MAGDADOC_SCOPES,consumerPrivKey);
>
>                 WebClient wc = WebClient.fromClient(client,true)
>                                 .header("x-correlation-id",
> xCorrelationId)
>                                 .header("Idempotency-Key",
idempotencyKey)
>                                 .path("/messages")
>
.accept(MediaType.APPLICATION_JSON_TYPE);
>
>                 return
> wc.post(Entity.entity(body,MediaType.MULTIPART_FORM_DATA_TYPE));
>         }


> -----Oorspronkelijk bericht-----
> Van: Andriy Redko <[email protected]>
> Verzonden: maandag 19 mei 2025 17:06
> Aan: Jean Pierre URKENS <[email protected]>;
> [email protected]
> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

> Hi Jean,

> Looked into it, so the Content-ID comes from Attachment::id property,
the
> good news -
> this property is not required and could be omitted. Once omitted, the
> Content-ID
> header will not be sent. I am wondering how do you construct
MultipartBody
> /Attachment
> instance that is being submitted to the service? Thank you.

> Best Regards,
>     Andriy Redko


>> Hi Andriy,

>> Indeed, according to https://www.rfc-editor.org/rfc/rfc7578 -
> section-4.8
>> only the headers Content-Type, Content-Disposition, and
>> Content-Transfer-Encoding (in specific cases) are supported.
>> Actually (cf. https://www.rfc-editor.org/rfc/rfc7578#section-4.7) the
> use
>> of Content-Transfer-Encoding is deprecated. It is not clear to me where
>> this header is set in CXF when constructing/streaming the parts of the
>> multipart/formdata.

>> Regards,

>> J.P. Urkens



>> -----Oorspronkelijk bericht-----
>> Van: Andriy Redko <[email protected]>
>> Verzonden: zaterdag 17 mei 2025 3:45
>> Aan: Jean Pierre URKENS <[email protected]>;
>> [email protected]
>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>> Hi Jean,

>> Ah interesting, I briefly checked [1], [2] and indeed Content-ID is
>> not mentioned there. I will try to look over the weekend what is
>> happening,
>> thank you.

>> [1] https://www.rfc-editor.org/rfc/rfc2388.html
>> [2] https://www.rfc-editor.org/rfc/rfc7578

>> Best Regards,
>>     Andriy Redko

>>> Hi Andriy,

>>> It seems that the reason is the content-id header in the different
>>> multiparts.
>>> When I get the MessageToSend object passed along with 'Content-ID:

>> <null>'
>>> thus having the header like e.g.:

>>>         --uuid:0b5e2920-24d8-44fb-ac8f-672731573a3a
>>>         Content-Type: application/json
>>>         Content-Transfer-Encoding: binary
>>>         Content-ID: <null>
>>>         Content-Disposition: form-data; name="messageToSend"

>>> then it works.


>>> -----Oorspronkelijk bericht-----
>>> Van: Andriy Redko <[email protected]>
>>> Verzonden: vrijdag 16 mei 2025 3:41
>>> Aan: Jean Pierre URKENS <[email protected]>;
>>> [email protected]
>>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>>> Hi Jean,

>>> On the first glance (comparing the example request and the real
request
>>> you are sending), I see no issues: there is one attachment in both of

>> them

>>> "upfile1". It is difficult to say what the cause is, but would you be

>> able

>>> to debug it by sending the POST request manually (Postman or even
> curl)?
>>> (if that is possible). Since you have both payloads (+ headers), we
>> could
>>> try to pinpoint the problematic part(s). What do you think?

>>> Thank you.

>>> Best Regards,
>>>     Andriy Redko

>>>> Hi Andriy,

>>>> Now that I am starting to test with the test server of the service
>>>> provider its reporting me an '400 BAD REQUEST' with the message:

>>>>         "Number of attachments specified is different from the number

>> of
>>>> provided MultiPart files"

>>>> It appears to me that the server is expecting 3 attachments
(multipart
>>>> files) and one object (messagetoSend).
>>>> However, looking at the

>> org.apache.cxf.jaxrs.ext.multipart.MultipartBody
>>>> class, I can only add attachments to the multipartbody.
>>>> It is not clear to me:
>>>>         - what exactly the difference is between what the server
>> expects
>>>> and what I send (see below)
>>>>         - how I can/should combine objects and files together in one
>>>> MultipartBody of content-type mutlipart/form-data

>>>> I am new to multipart messages, especially when it regards different
>>>> content parts having different content-types, so any clarification
>>>> would be helpful.

>>>> Regards,

>>>> J.P. Urkens

>>>> The service provider provides following example as a valid request:
>>>>         POST /api/v1/messages/messages
>>>>         Authorization: Bearer oPilB4*************
>>>>         X-Correlation-ID: 7cb999b8-5e2a-450a-ae30-c2be9c1ba01c
>>>>         idempotency-key: fc1deb23-3869-4ccd-8afc-f0e40ad2b751
>>>>         Accept: */*
>>>>         Content-Type: multipart/form-data;
>>>> boundary=--------------------------451703456417497490651597
>>>>         ----------------------------451703456417497490651597
>>>>         Content-Disposition: form-data; name="messageToSend"
>>>>         {
>>>>             "delivery": "EBOX",
>>>>             "eboxDeliveryData": {
>>>>                 "recipient": {
>>>>                     "eboxType": "CITIZEN",
>>>>                     "eboxIdValue": "92042816483"
>>>>                 },
>>>>                 "subject": {
>>>>                     "nl": "Onderwerp van het bericht",
>>>>                     "fr": "Sujet du message",
>>>>                     "de": "Test onderwerp in DE"
>>>>                 },
>>>>                 "messageTypeId":

>> "139b65e2-12cf-4ef4-9023-641d0637f294",
>>>>                 "senderOrganizationId": "0316380841",
>>>>                 "senderApplicationId":
>>>> "7d96bab6-e365-4c62-804a-aca5e07e2f57",
>>>>                 "registeredMail": false,
>>>>                 "bodyMainContent": false,
>>>>                 "replyAuthorized": false,
>>>>                 "attachments": [{
>>>>                     "httpPartName": "upfile1",
>>>>                     "mainContent": true,
>>>>                     "attachmentSigned": false
>>>>                 }]
>>>>             }
>>>>         }
>>>>         ----------------------------451703456417497490651597
>>>>         Content-Disposition: form-data; name="upfile1";
>>>> filename="dummy.pdf"
>>>>         <dummy.pdf>
>>>>         ----------------------------451703456417497490651597--

>>>> While my code is sending something like:
>>>>         [MAGDADOC] 2025-05-06 09:25:28,222 [main] INFO  $--$
>>>> (org.apache.cxf.ext.logging.slf4j.Slf4jEventSender:84) - REQ_OUT
>>>>             Address:
>>>> https://iv.api.tni-vlaanderen.be/api/v1/messages/messages
>>>>             HttpMethod: POST
>>>>             Content-Type: multipart/form-data;
>>>> boundary="uuid:eb20df03-1120-4e02-b5c5-cb2f050ea975"
>>>>             ExchangeId: 0e03de2a-b3a8-41cb-98e2-7d3771e5dd7e
>>>>             Headers: {Authorization=Bearer
>>>> 5XDR-xWf77BP5Pq3Xyt4Q5HWhzdAEu2Pmrz1zhzjMsM, Accept=application/json,
>>>> Idempotency-Key=18ae8f19-9feb-4ff4-9ec3-52995964b90d,
>>>> x-correlation-id=42623224-2755-45b2-abf5-5631ed247324}
>>>>             Payload:
>>>>         --uuid:eb20df03-1120-4e02-b5c5-cb2f050ea975
>>>>         Content-Type: application/json
>>>>         Content-Transfer-Encoding: binary
>>>>         Content-ID: <messageToSend>
>>>>         Content-Disposition: form-data; name="messageToSend";

>>>>         {
>>>>           "delivery" : "EBOX",
>>>>           "eboxDeliveryData" : {
>>>>             "recipient" : {
>>>>               "eboxType" : "ENTERPRISE",
>>>>               "enterpriseNumber" : "0887693124",
>>>>               "eboxIdValue" : "0887693124"
>>>>             },
>>>>             "subject" : {
>>>>               "nl" : "ProjectOnontvankelijkMail Project:
2025-EP-0001"
>>>>             },
>>>>             "registeredMail" : false,
>>>>             "attachments" : [ {
>>>>               "httpPartName" : "upfile1",
>>>>               "mainContent" : true,
>>>>               "attachmentSigned" : false
>>>>             }],
>>>>             "bodyMainContent" : false,
>>>>             "businessDataList" : [ ],
>>>>             "replyAuthorized" : false,
>>>>             "messageActions" : [ ]
>>>>           },
>>>>           "businessData" : [ ]
>>>>         }
>>>>         --uuid:eb20df03-1120-4e02-b5c5-cb2f050ea975
>>>>         Content-Type: application/pdf
>>>>         Content-Transfer-Encoding: binary
>>>>         Content-ID: <upfile1>
>>>>         Content-Disposition: form-data; name="upfile1";

>>>>         <...I skipped the pdf-data content...>

>>>>         --uuid:eb20df03-1120-4e02-b5c5-cb2f050ea975--



>>>> -----Oorspronkelijk bericht-----
>>>> Van: Jean Pierre URKENS <[email protected]>
>>>> Verzonden: maandag 24 maart 2025 10:31
>>>> Aan: 'Andriy Redko' <[email protected]>
>>>> Onderwerp: RE: CXF JAX-RS: working with multipart form-data

>>>> Hi andriy,

>>>> The project was put on hold for some time. Now it kicks off and I had
> a
>>>> look at it again.

>>>> Debugging the validation showed that method validation failed because

>>> the
>>>> required header parameters where null.
>>>> The method signature includes two header parameters, so in my client
I

>>> had
>>>> to add the headers:

>>>>         WebClient wc = WebClient.fromClient(client)
>>>>                 .headers(headers)
>>>>                 .path("/messages")
>>>>                 .accept(MediaType.APPLICATION_JSON_TYPE);

>>>> And initially I made the mistake to add the headers with a wrong
> header
>>>> name. I added them using the 'parameter name' in the method signature
>>>> whereas I should have used the name indicated in the @HeaderParam
>>>> annotation.

>>>>                 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") @NotNull
>>> @Size(min
>>>> = 10, max = 36) @Parameter(description="When retrying a failed call,
>> the
>>>> retry call should have the same Idempotency Key.") String
>>> idempotencyKey,
>>>>                         @FormDataParam(value="messageToSend")
>>>> @Parameter(required=true,schema =
>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value =
>>>> "messageToSend", type="application/json", required= true)
> MessageToSend
>>>> messageToSend,
>>>>                         @FormDataParam(value="upfile1")

>>> @Parameter(schema
>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>> "upfile1", type="application/pdf", required = false) InputStream
>>>> upfile1Detail,
>>>>                         @FormDataParam(value="upfile2")
>>> @Parameter(schema
>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>> "upfile2", type="application/pdf", required = false) InputStream
>>>> upfile2Detail,
>>>>                         @FormDataParam(value="upfile3")
>>> @Parameter(schema
>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>> "upfile3", type="application/pdf", required = false) InputStream
>>>> upfile3Detail)
>>>>                 throws GeneralSecurityException,
>> AuthorizationException;

>>>> I.e. I added a header with name 'xCorrelationId' whereas it should be
> '
>>>> x-correlation-id'.

>>>> Fixing this also passed the validation (as otherwise the header
params
>>>> would be null and they are listed as required).
>>>> So problem was at my side.

>>>> Regards,

>>>> J.P. Urkens

>>>> -----Oorspronkelijk bericht-----
>>>> Van: Andriy Redko <[email protected]>
>>>> Verzonden: maandag 25 november 2024 3:33
>>>> Aan: Jean Pierre URKENS <[email protected]>;
>>>> [email protected]
>>>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>>>> Hi Jean,

>>>> My apologies for the delay, took me a bit longer to find the time. So

>>> I've
>>>> added
>>>> another test case to the existing pull request [1], that includes
>>>> multipart and
>>>> bean validation, no issues and the validation works as expected.
Could

>>> you
>>>> help
>>>> me out and point what I am doing differently (one difference is that

>> the
>>>> CXF tests
>>>> use Hibernate Validator under the hood but it should not matter I
>>> believe,
>>>> in any
>>>> case I will try to run the tests with the library you are using).

>>>> Thanks.

>>>> [1] https://github.com/apache/cxf/pull/2152

>>>> Best Regards,
>>>>     Andriy Redko

>>>>> If I deactivate the bean validation feature in

>>> createMagdadocServer(...)
>>>>> it works.

>>>>> Some further questions:

>>>>> 1. Setting the target address when using WebClient directly
>>>>> ================================================

>>>>> Currently I create my client using JAXRSClientFactoryBean
> refereincing

>>>> my
>>>>> service class as follows (<PT> is either my service interface class
> or
>>>>> some interface extending on it):
>>>>>         protected synchronized PT getApiProxy() {
>>>>>                 if (apiProxy == null) {
>>>>>                         //Get the base address of the service
> endpoint
>>>>>                         String baseAddress =
>
Configuration.getInstance().getItem("magdadocumentendienst.service.base.ur
>>>>> i");
>>>>>                         apiProxy = getThreadsafeProxy(baseAddress);
>>>>>                 }
>>>>>                 return apiProxy;
>>>>>         }
>>>>>         private PT getThreadsafeProxy(String baseAddress) {
>>>>>                 JacksonJsonProvider jjProvider = new
>>>>> JacksonJsonProvider(new CustomObjectMapper());
>>>>>                 List<Object> providers = Arrays.asList(new
>>>>> MultipartProvider(), jjProvider);
>>>>>                 final JAXRSClientFactoryBean factory = new
>>>>> JAXRSClientFactoryBean();
>>>>>                 factory.setAddress(baseAddress);
>>>>>                 factory.setServiceClass(getPTClass());
>>>>>                 factory.setProviders(providers);
>>>>>                 factory.setThreadSafe(true);
>>>>>                 //only for testing the sending of attachments as
>>>>> multipart/form-data
>>>>>                 LoggingFeature feature = new LoggingFeature();
>>>>>                 feature.setLogMultipart(true);
>>>>>                 feature.setLogBinary(true);
>>>>>                 feature.setLimit(128*1000);
>> feature.addBinaryContentMediaTypes(MediaType.APPLICATION_OCTET_STREAM);
> feature.addBinaryContentMediaTypes("application/pdf");
>>>>>                 factory.setFeatures(Arrays.asList(feature));

>>>>>                 PT api = (PT) factory.create(getPTClass());
>>>>>                 ClientConfiguration config =
> WebClient.getConfig(api);
>>>>>                 addTLSClientParameters(config.getHttpConduit());

>>>>>                 return api;
>>>>>         }

>>>>> When invoking a method on it (e.g. getApiProxy().createMessage(...))

>> it

>>>> is
>>>>> handled by cxf the class ClientProxyImpl. This uses the method

>>> signature
>>>>> and all annotated 'path' declarations to determine the target
> address.

>>>>> This doesn't happen when I invoke the call through a WebClient, e.g.

>>> (as
>>>>> to your suggestion):

>>>>>                 MultipartBody body = new
>>>>> MultipartBody(attachments,MediaType.MULTIPART_FORM_DATA_TYPE,false);
>>>>>                 WebClient wc = WebClient.fromClient(client)
>>>>>                                 .path("/messages")

>>>> .accept(MediaType.APPLICATION_JSON_TYPE);
>>>>>                 return
>>>>> wc.post(Entity.entity(body,MediaType.MULTIPART_FORM_DATA_TYPE));

>>>>> Here I have to set the path manually. Is there a way to construct it
>>>>> similar to what ClientProxyImpl does?

>>>>> 2.Bean validation
>>>>> ==============
>>>>> I guess there are different bean validation frameworks/libraries.
I'd

>>>> like
>>>>> to keep bean validation active any suggestions on how to
>>>>> resolve/circumvent this issue, e.g.:
>>>>> - using another bean validation library
>>>>> - disabling validation for a specific method (is this possible?)
>>>>> - ....


>>>>> Regards,

>>>>> J.P. Urkens

>>>>> -----Oorspronkelijk bericht-----
>>>>> Van: Jean Pierre URKENS <[email protected]>
>>>>> Verzonden: maandag 18 november 2024 10:20
>>>>> Aan: 'Andriy Redko' <[email protected]>; '[email protected]'
>>>>> <[email protected]>
>>>>> Onderwerp: RE: CXF JAX-RS: working with multipart form-data

>>>>> Validation is done using apache library bval-jsr-2.0.5.jar. So this

>>>> might
>>>>> be well out-of-scope of CXF.



>>>>> -----Oorspronkelijk bericht-----
>>>>> Van: Jean Pierre URKENS <[email protected]>
>>>>> Verzonden: maandag 18 november 2024 10:02
>>>>> Aan: 'Andriy Redko' <[email protected]>; '[email protected]'
>>>>> <[email protected]>
>>>>> Onderwerp: RE: CXF JAX-RS: working with multipart form-data

>>>>> Hi Andriy,

>>>>> Thanks for the example. I tried something similar last week but
since

>>> my
>>>>> method was annotated with @Parameter(required=true,schema =
>>>>> @Schema(implementation=MessageToSend.class)) request parameter
>>>> validation
>>>>> failed on the server side (see server trace below).
>>>>> I have a JAXRSBeanValidationInInterceptor provider active at the

>> server
>>>>> side and somehow matching the multipart request body to the method
>>>>> signature fails.
>>>>> So does it mean that validating request parameters takes place
before
>>>>> handling the multipart body translating each part to a method
>>> parameter?

>>>>> My actual method signature looked like:
>>>>>         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") @NotNull
>>>> @Size(min
>>>>> = 10, max = 36) @Parameter(description="When retrying a failed call,

>>> the
>>>>> retry call should have the same Idempotency Key.") String
>>>> idempotencyKey,
>>>>>                         @FormDataParam(value="messageToSend")
>>>>> @Parameter(required=true,schema =
>>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value =
>>>>> "messageToSend", type="application/json", required= true)

>> MessageToSend
>>>>> messageToSend,
>>>>>                         @FormDataParam(value="upfile1")

>>>> @Parameter(schema
>>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>> "upfile1", type="application/pdf", required = false) InputStream
>>>>> upfile1Detail,
>>>>>                         @FormDataParam(value="upfile2")

>>>> @Parameter(schema
>>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>> "upfile2", type="application/pdf", required = false) InputStream
>>>>> upfile2Detail,
>>>>>                         @FormDataParam(value="upfile3")
>>>> @Parameter(schema
>>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>> "upfile3", type="application/pdf", required = false) InputStream
>>>>> upfile3Detail)
>>>>>         throws GeneralSecurityException, AuthorizationException;


>>>>> Even if I reduce the method signature to:
>>>>>         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") @NotNull
>>>> @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",
>>>>> type="application/json", required= true) MessageToSend
messageToSend,
>>>>>                         @Multipart(value = "upfile1",
>>>>> type="application/pdf", required = false) InputStream upfile1Detail,
>>>>>                         @Multipart(value = "upfile2",
>>>>> type="application/pdf", required = false) InputStream upfile2Detail,
>>>>>                         @Multipart(value = "upfile3",
>>>>> type="application/pdf", required = false) InputStream upfile3Detail)
>>>>>         throws GeneralSecurityException, AuthorizationException;

>>>>> I am still getting a '500 server error' saying that arg0 of

>>>> createMessage
>>>>> may not be null.

>>>>> Here are some extracts from the code:

>>>>> 1.API interface (only createMessage shown)
>>>>> ====================================
>>>>>         @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(schema=@S
>>>>> chema(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(implementatio
>>>>> n=ErrorMessage.class))),
>>>>>                         @ApiResponse(
>>>>>                                         responseCode = "401",
>>>>>                                         description = "Invalid
>>>>> authorization",
>>>>>                                         content =
>
@Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implementatio
>>>>> n=ErrorMessage.class))),
>>>>>                         @ApiResponse(
>>>>>                                         responseCode = "500",
>>>>>                                         description = "Unexpected

>>> Server
>>>>> Error",
>>>>>                                         content =
>
@Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implementatio
>>>>> n=ErrorMessage.class))),
>>>>>                         @ApiResponse(
>>>>>                                         responseCode = "502",
>>>>>                                         description = "Bad Gateway",
>>>>>                                         content =
>
@Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implementatio
>>>>> n=ErrorMessage.class))),
>>>>>                         @ApiResponse(
>>>>>                                         responseCode = "503",
>>>>>                                         description = "Service
>>>>> unavailable",
>>>>>                                         content =
>
@Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implementatio
>>>>> n=ErrorMessage.class))),
>>>>>                         @ApiResponse(
>>>>>                                         responseCode = "504",
>>>>>                                         description = "Gateway

>>> Timeout",
>>>>>                                         content =
>
@Content(mediaType=MediaType.APPLICATION_JSON,schema=@Schema(implementatio
>>>>> n=ErrorMessage.class)))
>>>>>         })
>>>>>         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") @NotNull
>>>> @Size(min
>>>>> = 10, max = 36) @Parameter(description="When retrying a failed call,
>>> the
>>>>> retry call should have the same Idempotency Key.") String
>>>> idempotencyKey,
>>>>>                         @FormDataParam(value="messageToSend")
>>>>> @Parameter(required=true,schema =
>>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value =
>>>>> "messageToSend", type="application/json", required= true)
>> MessageToSend
>>>>> messageToSend,
>>>>>                         @FormDataParam(value="upfile1")

>>>> @Parameter(schema
>>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>> "upfile1", type="application/pdf", required = false) InputStream
>>>>> upfile1Detail,
>>>>>                         @FormDataParam(value="upfile2")

>>>> @Parameter(schema
>>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>> "upfile2", type="application/pdf", required = false) InputStream
>>>>> upfile2Detail,
>>>>>                         @FormDataParam(value="upfile3")
>>>> @Parameter(schema
>>>>> = @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>> "upfile3", type="application/pdf", required = false) InputStream
>>>>> upfile3Detail)
>>>>>         throws GeneralSecurityException, AuthorizationException;


>>>>> 2. Client Invocation (only createMessage)
>>>>> =================================
>>>>>         public Response createMessage(String xCorrelationId,String
>>>>> idempotencyKey,MessageToSend messageToSend,
>>>>>                         InputStream upfile1,
>>>>>                         InputStream upfile2,
>>>>>                         InputStream upfile3)
>>>>>         throws GeneralSecurityException, AuthorizationException {
>>>>>                 //Create a multipartbody
>>>>>                 List<Attachment> attachments = new ArrayList<>();
>>>>>                 attachments.add(new
>
AttachmentBuilder().id("messageToSend").object(messageToSend).contentDispo
>>>>> sition(new ContentDisposition("form-data;
>>>>> name=\"messageToSend\";")).mediaType("application/json").build());
>>>>>                 if (upfile1 != null) {
>>>>>                         attachments.add(new AttachmentBuilder()
>>>>>                                         .id("upfile1")
>>>>>                                         .dataHandler(new

>>> DataHandler(new
>>>>> InputStreamDataSource(upfile1,"application/pdf","upfile1")))
>>>>>                                         .contentDisposition(new
>>>>> ContentDisposition("form-data; name=\"upfile1\";"))
>>>>>                                         .build());
>>>>>                 }
>>>>>                 if (upfile2 != null) {
>>>>>                         attachments.add(new AttachmentBuilder()
>>>>>                                         .id("upfile2")
>>>>>                                         .dataHandler(new
>>> DataHandler(new
>>>>> InputStreamDataSource(upfile2,"application/pdf","upfile2")))
>>>>>                                         .contentDisposition(new
>>>>> ContentDisposition("form-data; name=\"upfile1\";"))
>>>>>                                         .build());
>>>>>                 }
>>>>>                 if (upfile3 != null) {
>>>>>                         attachments.add(new AttachmentBuilder()
>>>>>                                         .id("upfile3")
>>>>>                                         .dataHandler(new
>>> DataHandler(new
>>>>> InputStreamDataSource(upfile3,"application/pdf","upfile3")))
>>>>>                                         .contentDisposition(new
>>>>> ContentDisposition("form-data; name=\"upfile1\";"))
>>>>>                                         .build());
>>>>>                 }
>>>>>                 MultipartBody body = new
>>>>> MultipartBody(attachments,MediaType.MULTIPART_FORM_DATA_TYPE,false);
>>>>>                 //Authorize API client
>>>>>                 Client client = WebClient.client(getApiProxy());
>
authorizationHandler.authorize(client,resourceClientId,consumerClientId,nu
>>>>> ll,consumerPrivKey);
>>>>>                 WebClient wc = WebClient.fromClient(client)
>>>>>                                 .path("/messages") /*UJ: Is there a
>> way
>>>> to
>>>>> construct the path as is done in ClientProxyImpl making use of the
>> path
>>>>> annotations on the method. */

>>>> .accept(MediaType.APPLICATION_JSON_TYPE);
>>>>>                 return
>>>>> wc.post(Entity.entity(body,MediaType.MULTIPART_FORM_DATA_TYPE));
>>>>>         }

>>>>> 3. Server Implementation
>>>>> =====================
>>>>>         /**
>>>>>          * {@inheritDoc}
>>>>>          * @see
>
be.dvtm.aeo.common.magda.documenten.api.MessagesApi#createMessage(java.lan
>>>>> g.String, java.lang.String,
>>>>> be.dvtm.aeo.common.magda.documenten.model.MessageToSend,
>>>>> java.io.InputStream, java.io.InputStream, java.io.InputStream)
>>>>>          */
>>>>>         @Override
>>>>>         public Response createMessage(
>>>>>                         String xCorrelationId,
>>>>>                         String idempotencyKey,
>>>>>                         MessageToSend messageToSend,
>>>>>                         InputStream upfile1,
>>>>>                         InputStream upfile2,
>>>>>                         InputStream upfile3) throws
>>>>> GeneralSecurityException, AuthorizationException {

>>>>>         //NOT REALLY RELEVANT AS IT DOESN'T GET THIS FAR due to

>> failing
>>>>> validation
>>>>>         }

>>>>> 4. Testcase
>>>>> =========
>>>>> //The server is setup as follows:
>>>>>         private Server createMagdadocServer(String baseAddress) {
>>>>>                 //Create a Server instance
>>>>>                 final JAXRSServerFactoryBean factory = new
>>>>> JAXRSServerFactoryBean();
>>>>>                 factory.setAddress(baseAddress);

>>>>>                 //01.Set root resource class and provider

>> factory.setResourceClasses(MagdadocSimulatorApi.class);
>> factory.setResourceProvider(MagdadocSimulatorApi.class,
>>>>> new SingletonResourceProvider(new MagdadocSimulator(), true));

>>>>>                 //02.set Logging feature
>>>>>                 List<Feature> featureList = new
ArrayList<Feature>();
>>>>>                 featureList.add(new LoggingFeature());
>>>>>                 factory.setFeatures(featureList);

>>>>>                 //03.activate wadl generator (just too see what the

>>>> server
>>>>> has deployed)
>>>>>                 WadlGenerator wadlGen = new WadlGenerator();
>>>>>                 wadlGen.setLinkAnyMediaTypeToXmlSchema(true);

>>>>>                 //04.Set Providers
>>>>>                 List<Object> providers = new ArrayList<Object>();
>>>>>                 providers.add(new JacksonJsonProvider(new
>>>>> CustomObjectMapper()));
>>>>>                 providers.add(new MultipartProvider());
>>>>>                 providers.add(wadlGen);
>>>>>                 factory.setProviders(providers);

>>>>>                 //05. Set interceptors
>>>>>                 JAXRSBeanValidationInInterceptor

>>> validationInInterceptor
>>>> =
>>>>> new JAXRSBeanValidationInInterceptor();
>>>>>                 validationInInterceptor.setProvider(new
>>>>> BeanValidationProvider());
>>>>>                 List<Interceptor<? extends Message>> interceptors =

>> new
>>>>> ArrayList<>();
>>>>>                 interceptors.add(validationInInterceptor);
>>>>>                 factory.setInInterceptors(interceptors);

>>>>>                 return factory.create();
>>>>>         }

>>>>> 5.Server LOG
>>>>> ===========
>>>>> [MAGDADOC] 2024-11-18 09:16:10,089 [qtp681015501-59] INFO  $--$
>>>>> (org.apache.cxf.ext.logging.slf4j.Slf4jEventSender:84) - REQ_IN
>>>>>     Address: http://localhost:8091/services/magdadoc/messages
>>>>>     HttpMethod: POST
>>>>>     Content-Type: multipart/form-data;
>>>>> boundary="uuid:2dc8ff1d-c69a-41c4-93ca-0f3b2bc2b190"
>>>>>     ExchangeId: 1eabcefe-eb7b-4d59-af35-2c3e72c8674a
>>>>>     Headers: {transfer-encoding=chunked, Accept=application/json,
>>>>> Cache-Control=no-cache, User-Agent=Apache-CXF/3.5.8,
>>>>> connection=keep-alive, content-type=multipart/form-data;
>>>>> boundary="uuid:2dc8ff1d-c69a-41c4-93ca-0f3b2bc2b190",

>>>> Host=localhost:8091,
>>>>> Pragma=no-cache}
>>>>>     Payload:
>>>>> --uuid:2dc8ff1d-c69a-41c4-93ca-0f3b2bc2b190
>>>>> Content-Type: application/json
>>>>> Content-Transfer-Encoding: binary
>>>>> Content-ID: <messageToSend>
>>>>> Content-Disposition: form-data; name="messageToSend";

>>>>> {
>>>>>   "delivery" : "EBOX",
>>>>>   "eboxDeliveryData" : {
>>>>>     "recipient" : {
>>>>>       "eboxType" : "ENTERPRISE",
>>>>>       "ssin" : null,
>>>>>       "enterpriseNumber" : "0123456789",
>>>>>       "partition" : null,
>>>>>       "eboxIdValue" : "0123456789"
>>>>>     },
>>>>>     "forTheAttentionOf" : null,
>>>>>     "originalMessageId" : null,
>>>>>     "subject" : {
>>>>>       "nl" : "ProjectOnontvankelijkMail Project: 2025-EP-0001",
>>>>>       "fr" : null,
>>>>>       "de" : null
>>>>>     },
>>>>>     "messageTypeId" : null,
>>>>>     "expirationDate" : null,
>>>>>     "senderOrganizationId" : null,
>>>>>     "senderApplicationId" : null,
>>>>>     "registeredMail" : false,
>>>>>     "attachments" : [ {
>>>>>       "attachmentTitle" : null,
>>>>>       "httpPartName" : "upfile1",
>>>>>       "mainContent" : true,
>>>>>       "digest" : null,
>>>>>       "attachmentSigned" : false
>>>>>     }, {
>>>>>       "attachmentTitle" : null,
>>>>>       "httpPartName" : "upfile2",
>>>>>       "mainContent" : false,
>>>>>       "digest" : null,
>>>>>       "attachmentSigned" : false
>>>>>     }, {
>>>>>       "attachmentTitle" : null,
>>>>>       "httpPartName" : "upfile3",
>>>>>       "mainContent" : false,
>>>>>       "digest" : null,
>>>>>       "attachmentSigned" : false
>>>>>     } ],
>>>>>     "bodyMainContent" : false,
>>>>>     "bodyContent" : null,
>>>>>     "businessDataList" : [ ],
>>>>>     "messageData" : null,
>>>>>     "paymentData" : null,
>>>>>     "replyAuthorized" : false,
>>>>>     "replyDueDate" : null,
>>>>>     "messageActions" : [ ],
>>>>>     "erroneousMessageId" : null
>>>>>   },
>>>>>   "paperDeliveryData" : null,
>>>>>   "emailDeliveryData" : null,
>>>>>   "businessData" : [ ]
>>>>> }
>>>>> --uuid:2dc8ff1d-c69a-41c4-93ca-0f3b2bc2b190
>>>>> --- Content suppressed ---

>>>>> --- Content suppressed ---

>>>>> --- Content suppressed ---
>>>>> [MAGDADOC] 2024-11-18 09:16:10,124 [qtp681015501-59] INFO  $--$
>>>>> (org.apache.cxf.ext.logging.slf4j.Slf4jEventSender:84) - FAULT_OUT
>>>>>     Content-Type: application/json
>>>>>     ResponseCode: 500
>>>>>     ExchangeId: 1eabcefe-eb7b-4d59-af35-2c3e72c8674a
>>>>>     Headers: {}
>>>>>     Payload: <ns1:XMLFault
>>>>> xmlns:ns1="http://cxf.apache.org/bindings/xformat";><ns1:faultstring
>
xmlns:ns1="http://cxf.apache.org/bindings/xformat";>javax.validation.Constr
>>>>> aintViolationException: createMessage.arg0: may not be null,
>>>>> createMessage.arg1: may not be null</ns1:faultstring></ns1:XMLFault>



>>>>> -----Oorspronkelijk bericht-----
>>>>> Van: Andriy Redko <[email protected]>
>>>>> Verzonden: maandag 18 november 2024 0:07
>>>>> Aan: Jean Pierre URKENS <[email protected]>;
>>>>> [email protected]
>>>>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>>>>> Hi Jean,

>>>>> So I have been able to spend some time on the issue and it seems
like

>>>> you
>>>>> might not be using the client properly (hence getting the
> exceptions),
>>>>> just a hypothesis.
>>>>> Here I have crafted a version of the API:

>>>>>   @POST
>>>>>   @Path("/multipart")
>>>>>   @Consumes("multipart/form-data")
>>>>>   @Produces("text/xml")
>>>>>   public Response addParts(@Multipart(value = "messageToSend",
>>>>> type="application/xml") MessageToSend messageToSend,
>>>>>                           @Multipart("upfile1Detail") Attachment a1,
>>>>>                           @Multipart("upfile2Detail") Attachment a2,
>>>>>                            @Multipart("upfile3Detail") Attachment
a3)
>>>>>       ...
>>>>>   }


>>>>> And the client invocation sequence:

>>>>>         final Client client = ClientBuilder.newClient();
>>>>>         final MultipartBody builder = new
> MultipartBody(Arrays.asList(
>>>>>             new AttachmentBuilder()
>>>>>                 .mediaType("application/xml")
>>>>>                 .id("messageToSend")
>>>>>                 .object(new MessageToSend())
>>>>>                 .build(),
>>>>>             new AttachmentBuilder()
>>>>>                 .id("upfile1Detail")
>>>>>                 .dataHandler(new DataHandler(new
>
InputStreamDataSource(getClass().getResourceAsStream("/org/apache/cxf/syst
>>>>> est/jaxrs/resources/attachmentData"), "text/xml")))
>>>>>                 .contentDisposition(new
> ContentDisposition("form-data;
>>>>> name=\"field1\";"))
>>>>>                 .build(),
>>>>>             new AttachmentBuilder()
>>>>>                 .id("upfile2Detail")
>>>>>                 .dataHandler(new DataHandler(new

>>>> InputStreamDataSource(new
>>>>> ByteArrayInputStream(new byte[0]), "text/xml")))
>>>>>                 .contentDisposition(new
> ContentDisposition("form-data;
>>>>> name=\"field2\";"))
>>>>>                 .build(),
>>>>>             new AttachmentBuilder()
>>>>>                 .id("upfile3Detail")
>>>>>                 .dataHandler(new DataHandler(new

>>>> InputStreamDataSource(new
>>>>> ByteArrayInputStream(new byte[0]), "text/xml")))
>>>>>                 .contentDisposition(new
> ContentDisposition("form-data;
>>>>> name=\"field3\";"))
>>>>>                 .build()));

>>>>>         final Response response = client
>>>>>                 .target(address)
>>>>>                 .request("text/xml")
>>>>>                 .post(Entity.entity(builder,
"multipart/form-data"));


>>>>> It works perfectly when the unified Attachment body part is used. I

>>> also
>>>>> crafted the test case over
>>>>> here [1], to help you out to get it working or point me out if there

>> is
>>>> a
>>>>> gap here that I missed.
>>>>> Thank you.

>>>>> [1] https://github.com/apache/cxf/pull/2152

>>>>> Best Regards,
>>>>>     Andriy Redko



>>>>>> Hi Andriy,

>>>>>> The option to use a List<Attachment> or a MultipartBody does work,

>>> I've
>>>>>> testcases to confirm this.
>>>>>> But it somehow breaks the original spec since trying to do a round

>>> trip
>>>>>>>> spec),

>>>>>>  the spec generated from the code (based on annotations) no longer
>>>>>> reflects the input spec.

>>>>>> What I find unexpected is that for multipart bodies all input

>>>> parameters
>>>>>> are attempted to be wrapped into Attachment objects,
>>>>>> (cf. method
>
org.apache.cxf.jaxrs.client.ClientProxyImpl#handleMultipart(MultivaluedMap
>>>>>> <ParameterType, Parameter> map,OperationResourceInfo ori,Object[]
>>>>>> params)).
>>>>>> So why doesn't the stack allow to mix request body parameters that
>> are
>>>>>> either @Multipart annotated or are Attachment itself.
>>>>>> Now you can't mix them since
>>>>>>
org.apache.cxf.jaxrs.client.ClientProxyImpl#getParametersInfo(Method
>>>>>> m,Object[] params, OperationResourceInfo ori) will fail
>>>>>> with error "SINGLE_BODY_ONLY". It wouldn't be hard to support the

>>>>> mixture
>>>>>> of both, or even an @Multipart annotated Attachment parameter (you

>>>>> could
>>>>>> just combine what is specified in the annotation with what is
> already
>>>>>> present in the Attachment, giving priority to one of both in case
of
>>>>>> overlapping parameters).

>>>>>> Further, if 'Content-Disposition' is obligatory (at least by
openAPI

>>>>> spec,
>>>>>> however don't know whether this is the industry reference) why

>> doesn't

>>>>> the
>>>>>> @Multipart
>>>>>> annotation allow to specify it? Why i.o. setting header

>>>>> Content-ID=<value>
>>>>>> isn't the header Content-Disposition=form-date:name="value" set
when
>>>>>> wrapping
>>>>>> a @Multipart annotated object into an Attachment object?

>>>>>> Strangely I don't even find a reference to the header Content-ID in
>>>>>> https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers. It is

>>>>> described
>>>>>> in
>>>>>> https://www.rfc-editor.org/rfc/rfc2045#section-7,
>>>>>> https://www.rfc-editor.org/rfc/rfc2392.txt and should have the form
>>>>>> 'url-addr-spec according to RFC822'
>>>>>> enclosed within '<>' and it is used to reference a multipartbody
> part

>>>> in
>>>>>> another part of the message. This doesn't seem to be the context in
>>>>> which
>>>>>> it is used in
>>>>>> JAX-RS messages, further the url-addr-spec actually tells me there
>>>>> should
>>>>>> a ' @' sign in the value of the content-id header which is surely
> not
>>>>> the
>>>>>> case in all examples
>>>>>> I've seen sofar. So why is CXF even using Content-ID?

>>>>>> Regards,

>>>>>> J.P.




>>>>>> -----Oorspronkelijk bericht-----
>>>>>> Van: Andriy Redko <[email protected]>
>>>>>> Verzonden: vrijdag 15 november 2024 21:02
>>>>>> Aan: Jean Pierre URKENS <[email protected]>;
>>>>>> [email protected]
>>>>>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>>>>>> Hi Jean,

>>>>>> Sorry for the delay, just went over through the message thread. So

>>>>> option
>>>>>> 1-2 should
>>>>>> indeed work just fine. And for 1st option, you could indeed set the
>>>>>> headers manually.
>>>>>> And in this case, you will need to craft the OpenAPI spec manually,

>> it
>>>>>> won't be properly
>>>>>> deducted.

>>>>>> I don't think adding more attributes to @Multipart would help since

>> it

>>>>> is
>>>>>> going to
>>>>>> in conflict with File / Attachment that by itself source these

>>>>> attributes.
>>>>>> But gimme
>>>>>> some time to experiment over the weekend, I think, intuitively,
that

>>>>> this
>>>>>> could work
>>>>>> (doesn't right now):

>>>>>>         Response testMessage1(
>>>>>>                         @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") @NotNull

>>>>> @Size(min
>>>>>> = 10, max = 36)
>>>>>> @Parameter(description="When retrying a failed call, the retry call

>>>>> should
>>>>>> have the same Idempotency Key.") String idempotencyKey,
>>>>>>                         @FormDataParam(value="messageToSend")
>>>>>> @Parameter(required=true,schema =
>>>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value =
>>>>>> "messageToSend", type="application/json", required= true)

>>> MessageToSend
>>>>>> messageToSend,
>>>>>>                         @FormDataParam(value="upfile1")

>>>>> @Parameter(schema
>>>>>> = @Schema(type =
>>>>>> "string", format = "binary")) Attachment upfile1Detail,
>>>>>>                         @FormDataParam(value="upfile2")

>>>>> @Parameter(schema
>>>>>> = @Schema(type =
>>>>>> "string", format = "binary")) Attachment upfile2Detail,
>>>>>>                         @FormDataParam(value="upfile3")

>>>>> @Parameter(schema
>>>>>> = @Schema(type =
>>>>>> "string", format = "binary")) Attachment upfile3Detail)

>>>>>> If we could fold it into :

>>>>>>     Response testMessage1(
>>>>>>                         @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") @NotNull

>>>>> @Size(min
>>>>>> = 10, max = 36)
>>>>>> @Parameter(description="When retrying a failed call, the retry call

>>>>> should
>>>>>> have the same Idempotency Key.") String idempotencyKey,
>>>>>>                         @FormDataParam(value="messageToSend")
>>>>>> @Parameter(required=true,schema =
>>>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value =
>>>>>> "messageToSend", type="application/json", required= true)

>>> MessageToSend
>>>>>> messageToSend,
>>>>>>                         List<Attachment> attachments)

>>>>>> This is just rough idea, but I will try look more closely into it.
>>>>>> Thanks.

>>>>>> Best Regards,
>>>>>>     Andriy Redko


>>>>>>> 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 <[email protected]>
>>>>>>> Verzonden: donderdag 14 november 2024 11:29
>>>>>>> Aan: 'Andriy Redko' <[email protected]>; '[email protected]'
>>>>>>> <[email protected]>
>>>>>>> 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 <[email protected]>
>>>>>>> Verzonden: woensdag 13 november 2024 23:42
>>>>>>> Aan: Jean Pierre URKENS <[email protected]>;
>>>>>>> [email protected]
>>>>>>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>>>>>>> Hi Jean,

>>>>>>>> When looking at the classes MultipartProvider and JAXRSUtils (cxf

>>>>>>> v3.5.9)
>>>>>>>> then it shows that only object for which a 'Content-Disposition'

>>>>>>> header will
>>>>>>>> be written is a File Object. The problem is that my application
is
>>>>>>>> generating the file content on the fly, so I have it either as a

>>>>>>> byte[] or
>>>>>>>> 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).

>>>>>>>>> Even passing a List<Attachment> doesn't work as the

>>>>>>> MultiPartProvider will
>>>>>>>> loop through the list and try to create a DataHandler for an

>>>>>>> Attachment
>>>>>>>> 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

>>>>>>>> Hi Andriy,

>>>>>>>> When looking at the classes MultipartProvider and JAXRSUtils (cxf

>>>>>>> v3.5.9)
>>>>>>>> then it shows that only object for which a 'Content-Disposition'

>>>>>>> header will
>>>>>>>> be written is a File Object. The problem is that my application
is
>>>>>>>> generating the file content on the fly, so I have it either as a

>>>>>>> byte[] or
>>>>>>>> InputStream.
>>>>>>>> This surprises me as according to
>
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposit
>>>>>>> ion:
>>>>>>>> "a multipart/form-data body requires a Content-Disposition header
>> to

>>>>>>> provide
>>>>>>>> information about each subpart of the form (e.g., for every form

>>>>>>> field and
>>>>>>>> any files that are part of field data)".
>>>>>>>> Also the Multipart annotation class only allows to specify

>>>>>>> Content-Type,
>>>>>>>> Content-ID so there is no way for me to provide

>>> 'Content-Disposition'
>>>>>>>> information on objects like byte[] or InputStream.

>>>>>>>> Even passing a List<Attachment> doesn't work as the

>>> MultiPartProvider

>>>>>>> will
>>>>>>>> loop through the list and try to create a DataHandler for an

>>>>>>> Attachment
>>>>>>>> object which is also not supported (throws an exception).
>>>>>>>> The only way I see to pass it is to construct Attachment objects

>> for

>>>>>>> each
>>>>>>>> multipart part, with 'Content-Disposition' set, and add them all
> to

>>> a
>>>>>>>> MultipartBody object and pass this as input parameter to my
method
>>>>>>>> signature. But then I loose all swager information for input

>> objects

>>>>>>> that
>>>>>>>> are not byte[] or InputStream.

>>>>>>>> Am I missing something?

>>>>>>>> Regards,

>>>>>>>> J.P.

>>>>>>>> -----Oorspronkelijk bericht-----
>>>>>>>> Van: Andriy Redko <[email protected]>
>>>>>>>> Verzonden: vrijdag 4 oktober 2024 2:52
>>>>>>>> Aan: Jean Pierre URKENS <[email protected]>;
>>>>>>>> [email protected]
>>>>>>>> Onderwerp: Re: CXF JAX-RS: working with multipart form-data

>>>>>>>> Hi Jean,

>>>>>>>> Yeah, I think the @Multipart + Attachment may not work, but you

>>> could

>>>>>>> accept
>>>>>>>> the List<Attachment> instead, right? (since you send many).

>>>>>>>> The logging configuration does not seem right: you use
> interceptors

>>>>>>> AND
>>>>>>>> feature (as per snippet below).

>>>>>>>>                  factory.getOutInterceptors().add(new
>>>>>>>> LoggingOutInterceptor());
>>>>>>>>                  factory.getInInterceptors().add(new
>>>>>>>> LoggingInInterceptor());
>>>>>>>>                  LoggingFeature feature = new LoggingFeature();
>>>>>>>>                  feature.setLogMultipart(true);
>>>>>>>>                  feature.setLogBinary(true);
>>>>>>>>                  ...

>>>>>>>> You only need one of those, either interceptors (please configure
>>>>>>>> setLogBinary & setLogMultipart for them):

>>>>>>>>                  factory.getOutInterceptors().add(new
>>>>>>>> LoggingOutInterceptor());
>>>>>>>>                  factory.getInInterceptors().add(new
>>>>>>>> LoggingInInterceptor());

>>>>>>>> Or feature:
>>>>>>>>                  LoggingFeature feature = new LoggingFeature();
>>>>>>>>                  feature.setLogMultipart(true);
>>>>>>>>                  feature.setLogBinary(true);
>>>>>>>>                  ...

>>>>>>>> Hope it helps, thanks!

>>>>>>>> Best Regards,
>>>>>>>>     Andriy Redko


>>>>>>>>> Hi Andriy,

>>>>>>>>> Thanks for the swift response, but I could still use some

>>>>>>>> clarifications on:

>>>>>>>>> 1) You mention that passing an Attachment object as service
> method
>>>>>>>>> parameter should work.
>>>>>>>>>     My initial test setup did pass an Attachment object as input
>>>>>>>>> parameter
>>>>>>>>>> 1)API interface declaration" in my mail. However when the

>>>>>>>>> client (see code below) tries to send a request with this
>>>>>>>>> signature, the
>>>>>>>>> JAXRSUtils.writeMessageBody(...) method that is called by the
CXF
>>>>>>>>> stack throws an exception on the Attachment parameter saying:

>>>>>>>>>         okt 03, 2024 9:46:54 AM
>>>>>>>>> org.apache.cxf.jaxrs.provider.MultipartProvider
>>>>>>>>> getHandlerForObject SEVERE: No message body writer found for
> class
>>>>>>>>> : class org.apache.cxf.jaxrs.ext.multipart.Attachment.
>>>>>>>>>         okt 03, 2024 9:47:05 AM
>>>>>>>>> org.apache.cxf.jaxrs.utils.JAXRSUtils
>>>>>>>>> logMessageHandlerProblem SEVERE: Problem with writing the data,
>>>>>>>>> class java.util.ArrayList, ContentType: multipart/form-data
>>>>>>>>>         okt 03, 2024 9:47:14 AM
>>>>>>>>> org.apache.cxf.phase.PhaseInterceptorChain
>>>>>>>>> doDefaultLogging WARNING: Interceptor for
>>>>>>>>> {http://api.documenten.magda.common.aeo.dvtm.be/}MessagesApi has
>>>>>>>>> thrown exception, unwinding now
>>>>>>>>>                 org.apache.cxf.interceptor.Fault: Problem with
>>>>>>>>> writing the data, class java.util.ArrayList, ContentType:

>>>>>>>> multipart/form-data
>>>>>>>>>                 at
>
org.apache.cxf.jaxrs.client.ClientProxyImpl$BodyWriter.doWriteBody(ClientP
>>>>>>> roxyImpl.java:1142)
>>>>>>>>>                 at
>> org.apache.cxf.jaxrs.client.AbstractClient$AbstractBodyWriter.handl
>>>>>>>>> eMessage(AbstractClient.java:1223)

>>>>>>>>> The JAXRSUtils.writeMessageBody(...) method takes an 'entity'
>>>>>>>>> Object that is a List<Attachment>. The first Attachment in the

>> list
>>>>>>>>> contains an object of type MessageToSend, while the second one
>>>>>>>>> contains an object of type Attachment for which 'no message body

>>>>>>>> writer' could be found.
>>>>>>>>> The stack creates itself an Attachment object for each parameter

>> of
>>>>>>>>> the multipart body, that is why I though that I can not pass it
> as
>>>>>>>>> a parameter to my service method. I guess I am not allowed to

>>>>>>> annotate
>>>>>>>> an 'Attachment'
>>>>>>>>> parameter with @Multipart annotation as currently done in the
>>>>>>>>> method
>>>>>>>>> signature:

>>>>>>>>>         @FormDataParam(value="upfile1") @Parameter(schema =
>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>> "upfile1", type="application/pdf", required = false) Attachment
>>>>>>>>> upfile1Detail

>>>>>>>>> However leaving the @Multipart annotation for the Attachment
>>>>>>>>> parameter away leads to the error:

>>>>>>>>>         javax.ws.rs.ProcessingException: Resource method
> be.dvtm.aeo.common.magda.documenten.api.MessagesApi.createMessage2
>>>>>>>>> has more than one parameter representing a request body

>>>>>>>>> I.e. now it is no longer clear that the Attachment parameter is
>>>>>>>>> part of the 'multipart'. That's why I switched to using an
>>>>>>>>> InputStream as parameter with @Multipart annotation but then I

>>> loose

>>>>>>>> the Content-Disposition information.
>>>>>>>>> The @Multipart annotation doesn't allow to specify
>>>>>>>>> Content-Disposition information. Is there an alternative here?

>>>>>>>>> 2) Logging of Binary Data. I create my client with:
>>>>>>>>>         private static MessagesApi getThreadsafeProxy(String

>>>>>>>> baseAddress) {
>>>>>>>>>                 JacksonJsonProvider jjProvider = new
>>>>>>>>> JacksonJsonProvider(new CustomObjectMapper());
>>>>>>>>>                 List<Object> providers = Arrays.asList(new
>>>>>>>>> MultipartProvider(), jjProvider);
>>>>>>>>>                 final JAXRSClientFactoryBean factory = new

>>>>>>>> JAXRSClientFactoryBean();
>>>>>>>>>                 factory.setAddress(baseAddress);
>>>>>>>>>                 factory.setServiceClass(MessagesApi.class);
>>>>>>>>>                 factory.setProviders(providers);
>>>>>>>>>                 factory.getOutInterceptors().add(new

>>>>>>>> LoggingOutInterceptor());
>>>>>>>>>                 factory.getInInterceptors().add(new

>>>>>>>> LoggingInInterceptor());
>>>>>>>>>                 factory.setThreadSafe(true);
>>>>>>>>>                 LoggingFeature feature = new LoggingFeature();
>>>>>>>>>                 feature.setLogMultipart(true);
>>>>>>>>>                 feature.setLogBinary(true);

> feature.addBinaryContentMediaTypes(MediaType.APPLICATION_OCTET_STREAM);
>>>>>>> feature.addBinaryContentMediaTypes("application/pdf");
>>>>>>>>>                 factory.setFeatures(Arrays.asList(feature));
>>>>>>>>>                 MessagesApi api =

>>> factory.create(MessagesApi.class);
>>>>>>>>>                 ClientConfiguration config =

>>>>>>> WebClient.getConfig(api);
>>>>>>>>>                 addTLSClientParameters(config.getHttpConduit());
>>>>>>>>>                 return api;
>>>>>>>>>         }
>>>>>>>>>  Here I do activate the logging for multipart and binary and
also
>>>>>>>>> added some mediatypes (although couldn't find what it actually
>>>>>>>>> does). So I was expecting to see the whole message (attachments

>> are
>>>>>>>>> rather small as it is a test).
>>>>>>>>>  Well I used wireshark to get the full message and it doesn't
> show
>>>>>>>>> any Content-Disposition headers for the multipart elements.

>>>>>>>>> Regards,

>>>>>>>>> J.P. Urkens

>>>>>>>>> -----Original Message-----
>>>>>>>>> From: Andriy Redko <[email protected]>
>>>>>>>>> Sent: donderdag 3 oktober 2024 1:01
>>>>>>>>> To: Jean Pierre URKENS <[email protected]>;
>>>>>>>>> [email protected]
>>>>>>>>> Subject: Re: CXF JAX-RS: working with multipart form-data

>>>>>>>>> Hi Jean,

>>>>>>>>>> What is the correct way to annotate a file attachment as part
of

>> a
>>>>>>>>>> mutlipart/form-data content body?

>>>>>>>>> We have many examples in our test suites over here [1], it
really
>>>>>>>>> depends on the problem at hand.

>>>>>>>>>>         -> Question-01: Is this the appropriate way to pass
> files
>>>>>>>>>> (PDF documents) as attachment in a mutlipart/form-data request,
>> or
>>>>>>>>>> are

>>>>>>>>> there better ways?

>>>>>>>>> You would probably better of with "multipart/mixed" [2] as in
you
>>>>>>>>> case, you are sending different data types. But
>>>>>>>>> "multipart/form-data" should be fine as well. The right answer
>>>>>>>>> answer depends on how large the files are. In many cases you are
>>>>>>>>> better off using chunked transfer (no need to read the whole
file

>>> in

>>>>>>>> memory), like you do with InputStream.

>>>>>>>>>>         -> Question-02: When I activate logging, I can't see
>>>>>>>>>> anything about the file attachment, not is content, nor the
>>>>>>>>>> appropriate Content-Disposition settings? I get '--Content

>>>>>>>>> suppressed--', e.g.:

>>>>>>>>> Correct, by default the logging interceptors do not log binary
>>>>>>>>> data, you could checks the docs here [3].

>>>>>>>>>>         -> Question-03: Don't I need to set anything regarding

>> the
>>>>>>>>>> Content-Disposition header? The example here is simplified in a
>>>>>>>>>> sense that I used a test setup with just one file attachment.
In
>>>>>>>>>> the real interface up to
>>>>>>>>>> 20 attachments can be passed. Somehow I need to know which part
>>>>>>>>>> relates

>>>>>>>>> to
>>>>>>>>>> which                   attachment or not?

>>>>>>>>> This is probably caused by the fact you are sending the

>> InputStream
>>>>>>>>> and not an Attachment, if my understanding is correct. I am
> pretty
>>>>>>>>> sure passing the Attachment (as you did initially) should work.

>>>>>>>>>>         -> Question-04: At the server implemtation side, since
>>>>>>>>>> upfile1Detail is passed as a method parameter, who is going to
>>>>>>>>>> close this InputStream at the server side?

>>>>>>>>> The stream should be closed by the service implementation (since
>>>>>>>>> the stream is expected to be consumed). The Apache CXF runtime

>> will
>>>>>>>>> try to close the stream in most cases as well but sometimes it
> may

>>>>>>> not
>>>>>>>> be able to.

>>>>>>>>> Hope it answers your questions. Thanks!

>>>>>>>>> [1]

>> https://github.com/apache/cxf/blob/main/systests/jaxrs/src/test/jav
>>>>>>>>> a/org/apache/cxf/systest/jaxrs/MultipartStore.java
>>>>>>>>> [2]
>> https://learn.microsoft.com/en-us/exchange/troubleshoot/administrat
>>>>>>>>> ion/multipart-mixed-mime-message-format
>>>>>>>>> [3] https://cxf.apache.org/docs/message-logging.html

>>>>>>>>> Best Regards,
>>>>>>>>>     Andriy Redko


>>>>>>>>>> Hi Andriy,

>>>>>>>>>> What is the correct way to annotate a file attachment as part
of

>> a
>>>>>>>>>> mutlipart/form-data content body?
>>>>>>>>>> I currently have the following (only the relevant parts):

>>>>>>>>>> 1)API interface declaration
>>>>>>>>>> ======================
>>>>>>>>>>         @POST
>>>>>>>>>>         @Path("/messages1")
>>>>>>>>>>         @Consumes("multipart/form-data")
>>>>>>>>>>         @Produces({ "application/json" })
>>>>>>>>>>         @Operation(...)
>>>>>>>>>>         @ApiResponses(...)
>>>>>>>>>>         Response createMessage1(
>>>>>>>>>>                         @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")
@NotNull
>>>>>>>>>> @Size(min = 10, max = 36) @Parameter(description="When retrying
> a
>>>>>>>>>> failed call, the retry call should have the same Idempotency
>>>>>>>>>> Key.")

>>>>>>>>> String idempotencyKey,
>>>>>>>>>>                         @FormDataParam(value="messageToSend")
>>>>>>>>>> @Parameter(required=true,schema =
>>>>>>>>>> @Schema(implementation=MessageToSend.class)) @Multipart(value =
>>>>>>>>>> "messageToSend", type="application/json", required= true)
>>>>>>>>>> MessageToSend messageToSend,
>>>>>>>>>>                         @FormDataParam(value="upfile1")
>>>>>>>>>> @Parameter(schema = @Schema(type = "string", format =
"binary"))
>>>>>>>>>> @Multipart(value = "upfile1", type="application/octet-stream",
>>>>>>>>>> required = false) Attachment upfile1Detail);

>>>>>>>>>> So I pass the file to upload as an Attachment object.

>>>>>>>>>> 2)API client test code
>>>>>>>>>> =================
>>>>>>>>>>                 String xCorrelationId =

>>>>>>> UUID.randomUUID().toString();
>>>>>>>>>>                 String idempotencyKey =
>>>>>>>>>> UUID.randomUUID().toString();

>>>>>>>>>>                 //01. Get the attachment to include
>>>>>>>>>>                 String fileName = "test.pdf";
>>>>>>>>>>                 try (InputStream is =
>>>>>>>>>> this.getClass().getClassLoader().getResourceAsStream(fileName);
>>>>>>>>>>                                  BufferedReader reader = new
>>>>>>>>>> BufferedReader(new InputStreamReader(is))) {
>>>>>>>>>>                         if (is == null) {
>>>>>>>>>>                                 Assert.fail("Couldn't load
>>>>>>>>>> test.pdf

>>>>>>>>> from classpath!");
>>>>>>>>>>                         }
>>>>>>>>>>                         DataHandler dataHandler = new
>>>>>>>>>> DataHandler(is,

>>>>>>>>> "application/pdf");
>>>>>>>>>>                         ContentDisposition cd = new
> ContentDisposition("attachment;name=upfile1;filename="+fileName);
>>>>>>>>>>                         Attachment upfile1Detail = new

>>>>>>>>> AttachmentBuilder()
>>>>>>>>>>                                 .id("upfile1")
>>>>>>>>>>                                 .dataHandler(dataHandler)
>>>>>>>>>>                                 .contentDisposition(cd)
>>>>>>>>>>                                 .mediaType("application/pdf")
>>>>>>>>>>                                 .build();

>>>>>>>>>>                 //02. create the message to send
>>>>>>>>>>                 MessageToSend mts = new MessageToSend();

>>>>>>>>>>                 //03. Call the server
>>>>>>>>>>                 Response resp =
>>>>>>>>>> apiClient.createMessage1(xCorrelationId, idempotencyKey, mts,
>>>>>>>>>> upfile1Detail);


>>>>>>>>>> When running the API client test code and getting at '03.' The

>>>>>>> method:
>>>>>>>>>>         JAXRSUtils.writeMessageBody(List<WriterInterceptor>
>>>>>>>>>> writers,Object entity,Class<?> type, Type

>> genericType,Annotation[]
>>>>>>>>>> annotations,MediaType mediaType,MultivaluedMap<String, Object>
>>>>>>>>>> httpHeaders,Message message)

>>>>>>>>>> is called. The 'entity' object is a list of Attachment objects

>>>>>>> where:
>>>>>>>>>>  - the first Attachment object contains an object of type
>>>>>>>>>> MessageToSend
>>>>>>>>>>  - the second Attachment object contains an object of type
>>>>>>>>>> Attachment

>>>>>>>>>> This second object leads to a fatal error within the
>>>>>>>>>> JAXRSUtils.writeMessageBody(...) method:
>>>>>>>>>>         okt 02, 2024 1:36:02 PM
>>>>>>>>>> org.apache.cxf.jaxrs.provider.MultipartProvider
>>>>>>>>>> getHandlerForObject
>>>>>>>>>>         SEVERE: No message body writer found for class : class
>>>>>>>>>> org.apache.cxf.jaxrs.ext.multipart.Attachment.
>>>>>>>>>>         okt 02, 2024 1:36:02 PM
>>>>>>>>>> org.apache.cxf.jaxrs.utils.JAXRSUtils
>>>>>>>>>> logMessageHandlerProblem
>>>>>>>>>>         SEVERE: Problem with writing the data, class
>>>>>>>>>> java.util.ArrayList,
>>>>>>>>>> ContentType: multipart/form-data


>>>>>>>>>> I  modified the interface and implementation classes to use
>>>>>>>>>> 'InputStream upfile1Detail' as type for the input parameter of

>> the
>>>>>>>>>> service method. And in this case my 'dummy' server
> implementation
>>>>>>>>>> can read the file and save it to disk.
>>>>>>>>>>         -> Question-01: Is this the appropriate way to pass
> files
>>>>>>>>>> (PDF documents) as attachment in a mutlipart/form-data request,
>> or
>>>>>>>>>> are

>>>>>>>>> there better ways?
>>>>>>>>>>         -> Question-02: When I activate logging, I can't see
>>>>>>>>>> anything about the file attachment, not is content, nor the
>>>>>>>>>> appropriate Content-Disposition settings? I get '--Content

>>>>>>>>> suppressed--', e.g.:

>>>>>>>>>>                 [MAGDADOC] 2024-10-02 14:29:08,911 [main] INFO
>>>>>>>>>> $--$
>>>>>>>>>> (org.apache.cxf.ext.logging.slf4j.Slf4jEventSender:84) -
REQ_OUT
>>>>>>>>>>                     Address:
> http://localhost:8091/services/magdadoc/api/v1/messages/messages1
>>>>>>>>>>                     HttpMethod: POST
>>>>>>>>>>                     Content-Type: multipart/form-data;
>>>>>>>>>> boundary="uuid:3c3fa9c0-8470-4655-b026-3ed09f79e862"
>>>>>>>>>>                     ExchangeId:

>>>>>>> a583a695-d881-4fa7-b65a-8961cdbbd412
>>>>>>>>>>                     Headers: {Authorization=Bearer
>>>>>>>>>> f4262ccf-3250-4bcf-a1bc-7ee1bf9a56cf,
>>>>>>>>>> Accept=application/json,
>>>>>>>>>> Idempotency-Key=bd06c05d-9fe2-4b60-b8db-5ad1121b74dc,
>>>>>>>>>> x-correlation-id=511c51ba-95fe-4f69-9443-f05c377cffab}
>>>>>>>>>>                     Payload:
>>>>>>>>>>                 --uuid:3c3fa9c0-8470-4655-b026-3ed09f79e862
>>>>>>>>>>                 Content-Type: application/json
>>>>>>>>>>                 Content-Transfer-Encoding: binary
>>>>>>>>>>                 Content-ID: <messageToSend>

>>>>>>>>>>                 {
>>>>>>>>>>                   "delivery" : "AUTOMATIC",
>>>>>>>>>>                   "eboxDeliveryData" : { /* all fine */},
>>>>>>>>>>                   "paperDeliveryData" : {/* all fine */},
>>>>>>>>>>                   "emailDeliveryData" : null,
>>>>>>>>>>                   "businessData" : [ ]
>>>>>>>>>>                 }
>>>>>>>>>>                 --uuid:3c3fa9c0-8470-4655-b026-3ed09f79e862
>>>>>>>>>>                 --- Content suppressed ---

>>>>>>>>>>         -> Question-03: Don't I need to set anything regarding

>> the
>>>>>>>>>> Content-Disposition header? The example here is simplified in a
>>>>>>>>>> sense that I used a test setup with just one file attachment.
In
>>>>>>>>>> the real interface up to
>>>>>>>>>> 20 attachments can be passed. Somehow I need to know which part
>>>>>>>>>> relates

>>>>>>>>> to
>>>>>>>>>> which                   attachment or not?
>>>>>>>>>>         -> Question-04: At the server implemtation side, since
>>>>>>>>>> upfile1Detail is passed as a method parameter, who is going to
>>>>>>>>>> close this InputStream at the server side?

>>>>>>>>>> Regards,

>>>>>>>>>> J.P. Urkens

>>>>>>>>>> P.S.: Is there a migration document describing upgrading

>> CXF-3.5.6
>>>>>>>>>> (my current version) to CXF-3.5.8 (latest JDK8 version). I'd
> like
>>>>>>>>>> to know whether upgrading can happen without too much burden.


>>>>>>>>>> -----Original Message-----
>>>>>>>>>> From: Jean Pierre URKENS <[email protected]>
>>>>>>>>>> Sent: vrijdag 5 juli 2024 13:04
>>>>>>>>>> To: 'Andriy Redko' <[email protected]>; '[email protected]'
>>>>>>>>>> <[email protected]>
>>>>>>>>>> Subject: RE: CXF JAX-RS: working with multipart form-data

>>>>>>>>>> Hi Andriy,

>>>>>>>>>> When searching the net I came along this Jersey annotation but
>>>>>>>>>> since I was not depending on 'Jersey' components I skipped it.
> So
>>>>>>>>>> apparently swagger-core has processing for externally defined
>>>>>>>>>> annotations (like this FormDataParam in Jersey), indeed inside

>>>>>>>>> know-how.

>>>>>>>>>> I included it in my project as
>>>>>>>>>> io.swagger.v3.oas.annotations.FormDataParam,
>>>>>>>>>> since it should somehow be included in the supported  swagger
>>>>>>>>>> annotations (maybe we should submit a request for it to the
>>>>>>>>>> swagger-core team) and this indeed generates an appropriate

>>>>>>>>> openapi.json spec.

>>>>>>>>>> Thanks alot,

>>>>>>>>>> J.P. Urkens



>>>>>>>>>> -----Original Message-----
>>>>>>>>>> From: Andriy Redko <[email protected]>
>>>>>>>>>> Sent: vrijdag 5 juli 2024 2:16
>>>>>>>>>> To: Jean Pierre URKENS <[email protected]>;
>>>>>>>>>> [email protected]
>>>>>>>>>> Subject: Re: CXF JAX-RS: working with multipart form-data

>>>>>>>>>> Hi Jean,

>>>>>>>>>> Here is how you could make it work (there is some magic
> knowledge
>>>>>>>>>> involved sadly). First of all, define such annotation anywhere
> in
>>>>>>>>>> your codebase (where it dims appropriate):

>>>>>>>>>> import java.lang.annotation.ElementType; import
>>>>>>>>>> java.lang.annotation.Retention; import
>>>>>>>>>> java.lang.annotation.RetentionPolicy;
>>>>>>>>>> import java.lang.annotation.Target;

>>>>>>>>>> @Target({ElementType.PARAMETER, ElementType.METHOD,
>>>>>>>>>> ElementType.FIELD})
>>>>>>>>>> @Retention(RetentionPolicy.RUNTIME)
>>>>>>>>>> public @interface FormDataParam {
>>>>>>>>>>     String value();
>>>>>>>>>> }

>>>>>>>>>> Use this annotation on each Attachment parameter:

>>>>>>>>>> /* Skipping other annotations as those are not important here
*/
>>>>>>>>>> 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,
>>>>>>>>>>          @FormDataParam("upfile1") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile1", type="application/octet-stream", required = false)
>>>>>>>>>> InputStream upfile1Detail,
>>>>>>>>>>          @FormDataParam("upfile2") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile2", type="application/octet-stream", required = false)
>>>>>>>>>> InputStream upfile2Detail,
>>>>>>>>>>          @FormDataParam("upfile3") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile3", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile3Detail,
>>>>>>>>>>          @FormDataParam("upfile4") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile4", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile4Detail,
>>>>>>>>>>          @FormDataParam("upfile5") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile5", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile5Detail,
>>>>>>>>>>          @FormDataParam("upfile6") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile6", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile6Detail,
>>>>>>>>>>          @FormDataParam("upfile7") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile7", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile7Detail,
>>>>>>>>>>          @FormDataParam("upfile8") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile8", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile8Detail,
>>>>>>>>>>          @FormDataParam("upfile9") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile9", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment

>>>>>>>>> upfile9Detail,
>>>>>>>>>>          @FormDataParam("upfile10") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile10", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile10Detail,
>>>>>>>>>>          @FormDataParam("upfile11") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile11", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile11Detail,
>>>>>>>>>>          @FormDataParam("upfile12") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile12", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile12Detail,
>>>>>>>>>>          @FormDataParam("upfile13") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile13", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile13Detail,
>>>>>>>>>>          @FormDataParam("upfile14") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile14", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile14Detail,
>>>>>>>>>>          @FormDataParam("upfile15") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile15", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile15Detail,
>>>>>>>>>>          @FormDataParam("upfile16") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile16", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile16Detail,
>>>>>>>>>>          @FormDataParam("upfile17") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile17", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile17Detail,
>>>>>>>>>>          @FormDataParam("upfile18") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile18", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile18Detail,
>>>>>>>>>>          @FormDataParam("upfile19") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile19", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile19Detail,
>>>>>>>>>>          @FormDataParam("upfile20") @Parameter(schema =
>>>>>>>>>> @Schema(type = "string", format = "binary")) @Multipart(value =
>>>>>>>>>> "upfile20", type="application/octet-stream", required = false)
>>>>>>>>>> Attachment upfile20Detail,
>>>>>>>>>>          @FormDataParam("qrfile") @Parameter(schema =

>> @Schema(type
>>>>>>>>>> = "string", format = "binary")) @Multipart(value = "qrfile",
>>>>>>>>>> type="application/octet-stream", required = false) Attachment

>>>>>>>>> qrfileDetail
>>>>>>>>>>      ) {
>>>>>>>>>>  ....
>>>>>>>>>> }

>>>>>>>>>> With that, you will get a nice request body schema (publishing
a
>>>>>>>>>> bit large YAML snippet to preserve the context):

>>>>>>>>>> paths:
>>>>>>>>>>   /sample/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:
>>>>>>>>>>       - name: x-correlation-id
>>>>>>>>>>         in: header
>>>>>>>>>>         description: ID of the transaction. Use this ID for log
>>>>>>>>>> tracing and incident
>>>>>>>>>>           handling.
>>>>>>>>>>         required: true
>>>>>>>>>>         schema:
>>>>>>>>>>           maxLength: 36
>>>>>>>>>>           minLength: 10
>>>>>>>>>>           type: string
>>>>>>>>>>       - name: Idempotency-Key
>>>>>>>>>>         in: header
>>>>>>>>>>         description: "When retrying a failed call, the retry
> call
>>>>>>>>>> should have the\
>>>>>>>>>>           \ same Idempotency Key."
>>>>>>>>>>         schema:
>>>>>>>>>>           maxLength: 36
>>>>>>>>>>           minLength: 10
>>>>>>>>>>           type: string
>>>>>>>>>>       requestBody:
>>>>>>>>>>         content:
>>>>>>>>>>           multipart/form-data:
>>>>>>>>>>             schema:
>>>>>>>>>>               type: object
>>>>>>>>>>               properties:
>>>>>>>>>>                 upfile1:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile2:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile3:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile4:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile5:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile6:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile7:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile8:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile9:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile10:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile11:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile12:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile13:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile14:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile15:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile16:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile17:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile18:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile19:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 upfile20:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary
>>>>>>>>>>                 qrfile:
>>>>>>>>>>                   type: string
>>>>>>>>>>                   format: binary

>>>>>>>>>> The key here is @FormDataParam annotation which (originally)

>> comes
>>>>>>>>>> from Jersey but has special treatment in Swagger Core (but,
>>>>>>>>>> likely, no attribution to Jersey).

>>>>>>>>>> Hope it helps!
>>>>>>>>>> Thank you.

>>>>>>>>>> Best Regards,
>>>>>>>>>>     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 <[email protected]>
>>>>>>>>>>> Sent: donderdag 4 juli 2024 4:44
>>>>>>>>>>> To: Jean Pierre URKENS <[email protected]>;
>>>>>>>>>>> [email protected]
>>>>>>>>>>> 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 <[email protected]>
>>>>>>>>>>>> Sent: woensdag 3 juli 2024 5:57
>>>>>>>>>>>> To: Jean Pierre URKENS <[email protected]>;
>>>>>>>>>>>> [email protected]
>>>>>>>>>>>> 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.

Reply via email to