From 3c7f7d380c6e78a45c1d4d5a0d0f343feb5cf5a5 Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Tue, 2 Apr 2024 18:03:16 +0200 Subject: [PATCH 1/7] Introduce MultipartBody filename directive --- .../com/microsoft/kiota/MultipartBody.java | 75 +++++++++++++++---- .../microsoft/kiota/MultiPartBodyTest.java | 21 ++++++ 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index 89fe6b854..e35fa6670 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -48,6 +48,20 @@ public MultipartBody() { */ public void addOrReplacePart( @Nonnull final String name, @Nonnull final String contentType, @Nonnull final T value) { + addOrReplacePart(name, contentType, value, null); + } + + /** + * Adds or replaces a part in the multipart body. + * + * @param the type of the part to add or replace. + * @param name the name of the part to add or replace. + * @param contentType the content type of the part to add or replace. + * @param value the value of the part to add or replace. + * @param filename the value of the filename directive. + */ + public void addOrReplacePart( + @Nonnull final String name, @Nonnull final String contentType, @Nonnull final T value, @Nullable String filename) { Objects.requireNonNull(value); if (Compatibility.isBlank(contentType)) throw new IllegalArgumentException("contentType cannot be blank or empty"); @@ -55,12 +69,11 @@ public void addOrReplacePart( throw new IllegalArgumentException("name cannot be blank or empty"); final String normalizedName = normalizePartName(name); - originalNames.put(normalizedName, name); - parts.put(normalizedName, new AbstractMap.SimpleEntry<>(contentType, value)); + Part part = new Part(name, value, contentType, filename); + parts.put(normalizedName, part); } - private final Map> parts = new HashMap<>(); - private final Map originalNames = new HashMap<>(); + private final Map parts = new HashMap<>(); private String normalizePartName(@Nonnull final String original) { return original.toLowerCase(Locale.ROOT); @@ -75,7 +88,7 @@ private String normalizePartName(@Nonnull final String original) { if (Compatibility.isBlank(partName)) throw new IllegalArgumentException("partName cannot be blank or empty"); final String normalizedName = normalizePartName(partName); - final Map.Entry candidate = parts.get(normalizedName); + final Part candidate = parts.get(normalizedName); if (candidate == null) return null; return candidate.getValue(); } @@ -90,10 +103,7 @@ public boolean removePart(@Nonnull final String partName) { throw new IllegalArgumentException("partName cannot be blank or empty"); final String normalizedName = normalizePartName(partName); final Object candidate = parts.remove(normalizedName); - if (candidate == null) return false; - - originalNames.remove(normalizedName); - return true; + return candidate != null; } /** {@inheritDoc} */ @@ -111,18 +121,23 @@ public void serialize(@Nonnull final SerializationWriter writer) { if (parts.isEmpty()) throw new IllegalStateException("multipart body cannot be empty"); final SerializationWriterFactory serializationFactory = ra.getSerializationWriterFactory(); boolean isFirst = true; - for (final Map.Entry> partEntry : parts.entrySet()) { + for (final Map.Entry partEntry : parts.entrySet()) { try { + Part part = partEntry.getValue(); if (isFirst) isFirst = false; else writer.writeStringValue("", ""); writer.writeStringValue("", "--" + getBoundary()); - final String partContentType = partEntry.getValue().getKey(); + final String partContentType = part.getContentType(); writer.writeStringValue("Content-Type", partContentType); - writer.writeStringValue( - "Content-Disposition", - "form-data; name=\"" + originalNames.get(partEntry.getKey()) + "\""); + + String contentDisposition = "form-data; name=\"" + part.getName() + "\""; + if (part.getFilename() != null && !part.getFilename().trim().isEmpty()) { + contentDisposition += "; filename=\"" + part.getFilename() + "\""; + } + writer.writeStringValue("Content-Disposition", contentDisposition); + writer.writeStringValue("", ""); - final Object objectValue = partEntry.getValue().getValue(); + final Object objectValue = part.getValue(); if (objectValue instanceof Parsable) { try (final SerializationWriter partWriter = serializationFactory.getSerializationWriter(partContentType)) { @@ -151,4 +166,34 @@ public void serialize(@Nonnull final SerializationWriter writer) { writer.writeStringValue("", ""); writer.writeStringValue("", "--" + boundary + "--"); } + + private static class Part { + private final String name; + private final Object value; + private final String contentType; + private final String filename; + + private Part(String name, Object value, String contentType, String filename) { + this.name = name; + this.value = value; + this.contentType = contentType; + this.filename = filename; + } + + public String getName() { + return name; + } + + public Object getValue() { + return value; + } + + public String getContentType() { + return contentType; + } + + public String getFilename() { + return filename; + } + } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java index f5b5f1933..81dede210 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import com.microsoft.kiota.serialization.SerializationWriter; @@ -67,5 +68,25 @@ void removesPart() { final Object result = multipartBody.getPartValue("foo"); assertNull(result); } + + @Test + void notAddFilename() { + final MultipartBody multipartBody = new MultipartBody(); + final SerializationWriter writer = mock(SerializationWriter.class); + multipartBody.requestAdapter = mock(RequestAdapter.class); + multipartBody.addOrReplacePart("foo", "bar", "baz"); + multipartBody.serialize(writer); + verify(writer).writeStringValue("Content-Disposition", "form-data; name=\"foo\""); + } + + @Test + void addFilename() { + final MultipartBody multipartBody = new MultipartBody(); + final SerializationWriter writer = mock(SerializationWriter.class); + multipartBody.requestAdapter = mock(RequestAdapter.class); + multipartBody.addOrReplacePart("foo", "bar", "baz", "image.png"); + multipartBody.serialize(writer); + verify(writer).writeStringValue("Content-Disposition", "form-data; name=\"foo\"; filename=\"image.png\""); + } // serialize method is being tested in the serialization library } From 51802935e002def3703b602057ffe002a6f5b0d7 Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Wed, 3 Apr 2024 11:08:54 +0200 Subject: [PATCH 2/7] Apply spotless --- .../src/main/java/com/microsoft/kiota/MultipartBody.java | 5 ++++- .../src/test/java/com/microsoft/kiota/MultiPartBodyTest.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index e35fa6670..b5de5532b 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -61,7 +61,10 @@ public void addOrReplacePart( * @param filename the value of the filename directive. */ public void addOrReplacePart( - @Nonnull final String name, @Nonnull final String contentType, @Nonnull final T value, @Nullable String filename) { + @Nonnull final String name, + @Nonnull final String contentType, + @Nonnull final T value, + @Nullable String filename) { Objects.requireNonNull(value); if (Compatibility.isBlank(contentType)) throw new IllegalArgumentException("contentType cannot be blank or empty"); diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java index 81dede210..94a527d64 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/MultiPartBodyTest.java @@ -86,7 +86,9 @@ void addFilename() { multipartBody.requestAdapter = mock(RequestAdapter.class); multipartBody.addOrReplacePart("foo", "bar", "baz", "image.png"); multipartBody.serialize(writer); - verify(writer).writeStringValue("Content-Disposition", "form-data; name=\"foo\"; filename=\"image.png\""); + verify(writer) + .writeStringValue( + "Content-Disposition", "form-data; name=\"foo\"; filename=\"image.png\""); } // serialize method is being tested in the serialization library } From 3739d54805edfcaba854d006b1653f65f7589d8a Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Wed, 3 Apr 2024 11:12:30 +0200 Subject: [PATCH 3/7] Add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46b8c3b8b..a96370067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +* Introduces a `filename` directive in the `MultipartBody`. + ### Changed ## [1.1.2] - 2024-03-26 From 3bd4cc840bf51caa2463b495df4a433e944efab2 Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Wed, 3 Apr 2024 11:14:26 +0200 Subject: [PATCH 4/7] Cleanup --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a96370067..c6f48763e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -* Introduces a `filename` directive in the `MultipartBody`. +- Introduces a `filename` directive in the `MultipartBody`. ### Changed From d2f2306c8dc52dce13709ffd18b831d7987bfa47 Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Wed, 3 Apr 2024 22:12:28 +0200 Subject: [PATCH 5/7] Make Part class as non-static --- .../src/main/java/com/microsoft/kiota/MultipartBody.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index b5de5532b..e7debf3d2 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -170,7 +170,7 @@ public void serialize(@Nonnull final SerializationWriter writer) { writer.writeStringValue("", "--" + boundary + "--"); } - private static class Part { + private class Part { private final String name; private final Object value; private final String contentType; From 978110428d7365add583ad8c6827dbcfc093fac8 Mon Sep 17 00:00:00 2001 From: Andrew Omondi Date: Thu, 4 Apr 2024 11:21:32 +0300 Subject: [PATCH 6/7] Bump version for release --- CHANGELOG.md | 2 ++ components/abstractions/spotBugsExcludeFilter.xml | 4 ++++ gradle.properties | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee0784863..1459dd08e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.1.4] - 2024-04-04 + ### Added - Introduces a `filename` directive in the `MultipartBody`. diff --git a/components/abstractions/spotBugsExcludeFilter.xml b/components/abstractions/spotBugsExcludeFilter.xml index 4db33b49d..86b46a1ac 100644 --- a/components/abstractions/spotBugsExcludeFilter.xml +++ b/components/abstractions/spotBugsExcludeFilter.xml @@ -58,4 +58,8 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu + + + + diff --git a/gradle.properties b/gradle.properties index 8cb2e80e0..38409fd06 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ org.gradle.caching=true mavenGroupId = com.microsoft.kiota mavenMajorVersion = 1 mavenMinorVersion = 1 -mavenPatchVersion = 3 +mavenPatchVersion = 4 mavenArtifactSuffix = #These values are used to run functional tests From 97da359f210da8b3a4fe5f6b1a1282ce1e2557c6 Mon Sep 17 00:00:00 2001 From: Piotr Olaszewski Date: Thu, 4 Apr 2024 11:04:51 +0200 Subject: [PATCH 7/7] Change Part constructor as package-scoped --- .../src/main/java/com/microsoft/kiota/MultipartBody.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java index e7debf3d2..6ee0f3355 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/MultipartBody.java @@ -176,7 +176,7 @@ private class Part { private final String contentType; private final String filename; - private Part(String name, Object value, String contentType, String filename) { + Part(String name, Object value, String contentType, String filename) { this.name = name; this.value = value; this.contentType = contentType;