diff --git a/.changes/next-release/bugfix-AWSSDKforJavav2-c980953.json b/.changes/next-release/bugfix-AWSSDKforJavav2-c980953.json new file mode 100644 index 000000000000..481dce005a82 --- /dev/null +++ b/.changes/next-release/bugfix-AWSSDKforJavav2-c980953.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Allow ResponseBody.toFile option to override file" +} diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/sync/ResponseTransformer.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/sync/ResponseTransformer.java index b2a39e2d12ac..550e917ab1fe 100644 --- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/sync/ResponseTransformer.java +++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/sync/ResponseTransformer.java @@ -24,6 +24,7 @@ import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.ResponseInputStream; @@ -100,10 +101,24 @@ default boolean needsConnectionLeftOpen() { * @return ResponseTransformer instance. */ static ResponseTransformer toFile(Path path) { + return toFile(path, new StandardCopyOption[0]); + } + + /** + * Creates a response transformer that writes all response content to the specified file. Passing + * {@link StandardCopyOption#REPLACE_EXISTING} will prevent a a {@link java.nio.file.FileAlreadyExistsException} to be thrown + * if the file already exists. + * + * @param path Path to file to write to. + * @param Type of unmarshalled response POJO. + * @param copyOptions options to be passed to the file copy + * @return ResponseTransformer instance. + */ + static ResponseTransformer toFile(Path path, StandardCopyOption... copyOptions) { return (resp, in) -> { try { InterruptMonitor.checkInterrupted(); - Files.copy(in, path); + Files.copy(in, path, copyOptions); return resp; } catch (IOException copyException) { String copyError = "Failed to read response into file: " + path; diff --git a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/ResponseTransformerTest.java b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/ResponseTransformerTest.java index ffe38a7a54e4..54d327a09b45 100644 --- a/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/ResponseTransformerTest.java +++ b/test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/ResponseTransformerTest.java @@ -33,6 +33,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.time.Duration; import java.util.UUID; import org.junit.Rule; @@ -122,6 +123,19 @@ public void downloadToOutputStreamDoesNotRetry() throws IOException { .isInstanceOf(SdkClientException.class); } + @Test + public void downloadToExistingFileWithOverwriteSucceeds() throws IOException { + stubForSuccess(); + + Path tmpFile = Files.createTempFile("overwrite-test.", ".tmp"); + tmpFile.toFile().deleteOnExit(); + + testClient().streamingOutputOperation(StreamingOutputOperationRequest.builder().build(), + ResponseTransformer.toFile(tmpFile, StandardCopyOption.REPLACE_EXISTING)); + + assertThat(Files.readAllLines(tmpFile)).containsExactly("test \uD83D\uDE02"); + } + @Test public void streamingCloseActuallyCloses() throws IOException { stubForSuccess();