1414
1515import static com .sap .cloud .sdk .services .openapi .apache .apiclient .DefaultApiResponseHandler .isJsonMime ;
1616import static lombok .AccessLevel .PRIVATE ;
17+ import static org .apache .hc .core5 .http .HttpHeaders .CONTENT_ENCODING ;
1718
19+ import java .io .ByteArrayOutputStream ;
1820import java .io .File ;
1921import java .io .IOException ;
2022import java .net .URLEncoder ;
2830import java .util .Map ;
2931import java .util .Map .Entry ;
3032import java .util .Set ;
33+ import java .util .zip .GZIPOutputStream ;
3134
3235import javax .annotation .Nonnull ;
3336import javax .annotation .Nullable ;
6871import lombok .Getter ;
6972import lombok .ToString ;
7073import lombok .With ;
74+ import lombok .val ;
7175
7276/**
7377 * API client for executing HTTP requests using Apache HttpClient 5.
@@ -348,77 +352,6 @@ private ContentType getContentType( @Nonnull final String headerValue )
348352 }
349353 }
350354
351- /**
352- * Serialize the given Java object into string according the given Content-Type (only JSON is supported for now).
353- *
354- * @param obj
355- * Object
356- * @param contentType
357- * Content type
358- * @param formParams
359- * Form parameters
360- * @return Object
361- * @throws OpenApiRequestException
362- * API exception
363- */
364- @ Nonnull
365- private HttpEntity serialize (
366- @ Nullable final Object obj ,
367- @ Nonnull final Map <String , Object > formParams ,
368- @ Nonnull final ContentType contentType )
369- throws OpenApiRequestException
370- {
371- final String mimeType = contentType .getMimeType ();
372- if ( isJsonMime (mimeType ) ) {
373- try {
374- return new StringEntity (
375- objectMapper .writeValueAsString (obj ),
376- contentType .withCharset (StandardCharsets .UTF_8 ));
377- }
378- catch ( JsonProcessingException e ) {
379- throw new OpenApiRequestException (e );
380- }
381- } else if ( mimeType .equals (ContentType .MULTIPART_FORM_DATA .getMimeType ()) ) {
382- final MultipartEntityBuilder multiPartBuilder = MultipartEntityBuilder .create ();
383- for ( final Entry <String , Object > paramEntry : formParams .entrySet () ) {
384- final Object value = paramEntry .getValue ();
385- if ( value instanceof File file ) {
386- multiPartBuilder .addBinaryBody (paramEntry .getKey (), file );
387- } else if ( value instanceof byte [] byteArray ) {
388- multiPartBuilder .addBinaryBody (paramEntry .getKey (), byteArray );
389- } else {
390- final Charset charset = contentType .getCharset ();
391- if ( charset != null ) {
392- final ContentType customContentType =
393- ContentType .create (ContentType .TEXT_PLAIN .getMimeType (), charset );
394- multiPartBuilder
395- .addTextBody (
396- paramEntry .getKey (),
397- parameterToString (paramEntry .getValue ()),
398- customContentType );
399- } else {
400- multiPartBuilder .addTextBody (paramEntry .getKey (), parameterToString (paramEntry .getValue ()));
401- }
402- }
403- }
404- return multiPartBuilder .build ();
405- } else if ( mimeType .equals (ContentType .APPLICATION_FORM_URLENCODED .getMimeType ()) ) {
406- final List <NameValuePair > formValues = new ArrayList <>();
407- for ( final Entry <String , Object > paramEntry : formParams .entrySet () ) {
408- formValues .add (new BasicNameValuePair (paramEntry .getKey (), parameterToString (paramEntry .getValue ())));
409- }
410- return new UrlEncodedFormEntity (formValues , contentType .getCharset ());
411- } else {
412- // Handle files with unknown content type
413- if ( obj instanceof File file ) {
414- return new FileEntity (file , contentType );
415- } else if ( obj instanceof byte [] byteArray ) {
416- return new ByteArrayEntity (byteArray , contentType );
417- }
418- throw new OpenApiRequestException ("Serialization for content type '" + contentType + "' not supported" );
419- }
420- }
421-
422355 /**
423356 * Build full URL by concatenating base URL, the given sub path and query parameters.
424357 *
@@ -560,7 +493,7 @@ public <T> T invokeAPI(
560493 if ( body != null || !formParams .isEmpty () ) {
561494 if ( isBodyAllowed (Method .valueOf (method )) ) {
562495 // Add entity if we have content and a valid method
563- builder .setEntity (serialize (body , formParams , contentTypeObj ));
496+ builder .setEntity (serialize (body , formParams , contentTypeObj , headerParams ));
564497 } else {
565498 throw new OpenApiRequestException ("method " + method + " does not support a request body" );
566499 }
@@ -578,4 +511,118 @@ public <T> T invokeAPI(
578511 throw new OpenApiRequestException (e );
579512 }
580513 }
514+
515+ /**
516+ * Serialize the given Java object into string according the given Content-Type (only JSON is supported for now).
517+ *
518+ * @param body
519+ * Object
520+ * @param contentType
521+ * Content type
522+ * @param formParams
523+ * Form parameters
524+ * @param headerParams
525+ * Header parameters, used to check content encoding for JSON serialization
526+ * @return Object
527+ * @throws OpenApiRequestException
528+ * API exception
529+ */
530+ @ Nonnull
531+ private HttpEntity serialize (
532+ @ Nullable final Object body ,
533+ @ Nonnull final Map <String , Object > formParams ,
534+ @ Nonnull final ContentType contentType ,
535+ @ Nonnull final Map <String , String > headerParams )
536+ throws OpenApiRequestException
537+ {
538+ final String mimeType = contentType .getMimeType ();
539+ if ( isJsonMime (mimeType ) ) {
540+ return serializeJson (body , contentType , headerParams );
541+ } else if ( mimeType .equals (ContentType .MULTIPART_FORM_DATA .getMimeType ()) ) {
542+ return serializeMultipart (formParams , contentType );
543+ } else if ( mimeType .equals (ContentType .APPLICATION_FORM_URLENCODED .getMimeType ()) ) {
544+ return serializeFormUrlEncoded (formParams , contentType );
545+ } else if ( body instanceof File file ) {
546+ return new FileEntity (file , contentType );
547+ } else if ( body instanceof byte [] byteArray ) {
548+ return new ByteArrayEntity (byteArray , contentType );
549+ }
550+ throw new OpenApiRequestException ("Serialization for content type '" + contentType + "' not supported" );
551+ }
552+
553+ @ Nonnull
554+ private HttpEntity serializeJson (
555+ @ Nullable final Object body ,
556+ @ Nonnull final ContentType contentType ,
557+ @ Nonnull final Map <String , String > headerParams )
558+ throws OpenApiRequestException
559+ {
560+ if ( "gzip" .equalsIgnoreCase (headerParams .get (CONTENT_ENCODING ))
561+ || "gzip" .equalsIgnoreCase (headerParams .get (CONTENT_ENCODING .toLowerCase ())) ) {
562+ val outputStream = new ByteArrayOutputStream ();
563+ try ( val gzip = new GZIPOutputStream (outputStream ) ) {
564+ gzip .write (objectMapper .writeValueAsBytes (body ));
565+ }
566+ catch ( IOException e ) {
567+ throw new OpenApiRequestException ("Failed to GZIP compress request body" , e );
568+ }
569+ return new ByteArrayEntity (
570+ outputStream .toByteArray (),
571+ contentType .withCharset (StandardCharsets .UTF_8 ),
572+ "gzip" );
573+ }
574+ try {
575+ return new StringEntity (
576+ objectMapper .writeValueAsString (body ),
577+ contentType .withCharset (StandardCharsets .UTF_8 ));
578+ }
579+ catch ( JsonProcessingException e ) {
580+ throw new OpenApiRequestException (e );
581+ }
582+ }
583+
584+ @ Nonnull
585+ private
586+ HttpEntity
587+ serializeMultipart ( @ Nonnull final Map <String , Object > formParams , @ Nonnull final ContentType contentType )
588+ {
589+ final MultipartEntityBuilder builder = MultipartEntityBuilder .create ();
590+ for ( final Entry <String , Object > entry : formParams .entrySet () ) {
591+ final Object value = entry .getValue ();
592+ if ( value instanceof File file ) {
593+ builder .addBinaryBody (entry .getKey (), file );
594+ } else if ( value instanceof byte [] byteArray ) {
595+ builder .addBinaryBody (entry .getKey (), byteArray );
596+ } else {
597+ addMultipartTextField (builder , entry , contentType );
598+ }
599+ }
600+ return builder .build ();
601+ }
602+
603+ private void addMultipartTextField (
604+ @ Nonnull final MultipartEntityBuilder builder ,
605+ @ Nonnull final Entry <String , Object > entry ,
606+ @ Nonnull final ContentType contentType )
607+ {
608+ final Charset charset = contentType .getCharset ();
609+ if ( charset != null ) {
610+ final ContentType textContentType = ContentType .create (ContentType .TEXT_PLAIN .getMimeType (), charset );
611+ builder .addTextBody (entry .getKey (), parameterToString (entry .getValue ()), textContentType );
612+ } else {
613+ builder .addTextBody (entry .getKey (), parameterToString (entry .getValue ()));
614+ }
615+ }
616+
617+ @ Nonnull
618+ private
619+ HttpEntity
620+ serializeFormUrlEncoded ( @ Nonnull final Map <String , Object > formParams , @ Nonnull final ContentType contentType )
621+ {
622+ final List <NameValuePair > formValues = new ArrayList <>();
623+ for ( final Entry <String , Object > entry : formParams .entrySet () ) {
624+ formValues .add (new BasicNameValuePair (entry .getKey (), parameterToString (entry .getValue ())));
625+ }
626+ return new UrlEncodedFormEntity (formValues , contentType .getCharset ());
627+ }
581628}
0 commit comments