Hi Jean,
 
Thank you for the issue. As per my understanding, the deprecation 
applies to multipart/form-data only, not others. Thank you.
 
Best Regards,
    Andriy Redko 
 
 
 
> 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