Skip to content

Commit 6e9f02c

Browse files
hive-botclaude
andcommitted
fix: raise the released exception classes for local file failures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent fadc7fe commit 6e9f02c

6 files changed

Lines changed: 80 additions & 143 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
193193
- `translateText()` sends the language codes with the language part
194194
lower-cased and the rest as given, like document translation, for example
195195
`zh-Hans`; before, the part after the first `-` was upper-cased.
196-
- `translateDocument(File, File, ...)` throws a `DocumentTranslationException`
197-
instead of an `IOException` when the output file exists or a file cannot be
198-
opened, and an `IllegalArgumentException` before any request when the input
199-
file does not exist.
200196
- Text translation accepts a glossary (`setGlossary()`) or glossary list
201197
(`setGlossaryIds()`) without a source language; the API detects the source
202198
language and uses the glossary's dictionary for the detected language pair.
@@ -279,13 +275,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
279275
(`Character.isWhitespace()`) like spoken terms, checks target terms set
280276
through `replaceAll()` or `Map.Entry.setValue()`, and names an invalid
281277
character in hexadecimal (`U+001F`).
282-
- `importTranslationMemoryFromFilepath()` and
283-
`exportTranslationMemoryToFilepath()` now throw `DeepLException`, with the
284-
original exception as cause, for local I/O failures such as an unreadable
285-
input file or a failed write, instead of a raw `IOException`.
286-
- `exportTranslationMemoryToFilepath()` with a `File` now checks that the output
287-
path is free and its directory exists before creating the export job, and
288-
throws `DeepLException` otherwise.
278+
- `exportTranslationMemoryToFilepath()` with a `File` now checks the output
279+
path before it creates the export job: an existing file throws `IOException`
280+
and a missing directory `FileNotFoundException`, the same classes as before.
289281
- `waitUntilTranslationMemoryJobDone()` with a timeout, and the import and
290282
export helpers that use it, now cut the last poll wait short at the timeout
291283
instead of overrunning it by up to 5 seconds.

‎README.md‎

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -341,25 +341,29 @@ class Example { // Continuing class Example from above
341341
try {
342342
client.translateDocument(inputFile, outputFile, "en", "de");
343343
} catch (DocumentTranslationException exception) {
344-
// If an error occurs during document translation after the document was
345-
// already uploaded, a DocumentTranslationException is thrown. The
346-
// document_handle property contains the document handle that may be used to
347-
// later retrieve the document from the server, or contact DeepL support.
344+
// If an error occurs during document translation, a
345+
// DocumentTranslationException is thrown. If the document was already
346+
// uploaded, getHandle() returns the document handle that may be used to
347+
// later retrieve the document from the server, or contact DeepL support;
348+
// otherwise it returns null.
348349
DocumentHandle handle = exception.getHandle();
349-
System.out.printf(
350-
"Error after uploading %s, document handle: id: %s key: %s",
351-
exception.getMessage(),
352-
handle.getDocumentId(),
353-
handle.getDocumentKey());
350+
System.out.printf("Error during document translation: %s%n", exception.getMessage());
351+
if (handle != null) {
352+
System.out.printf(
353+
"Document handle: id: %s key: %s%n",
354+
handle.getDocumentId(),
355+
handle.getDocumentKey());
356+
}
354357
}
355358
}
356359
}
357360
```
358361

359-
If the input file does not exist, `translateDocument()` throws an
360-
`IllegalArgumentException` before sending any request. Every other failure,
361-
including an existing output file or a file that cannot be opened, is thrown as
362-
a `DocumentTranslationException`; `getHttpStatusCode()` and `getShouldRetry()`
362+
If a file already exists at the output path, `translateDocument()` throws an
363+
`IOException` and leaves that file unchanged. A missing or unreadable input file,
364+
or an output file that cannot be created, throws a `FileNotFoundException`. No
365+
request is sent in these cases. Later failures are thrown as a
366+
`DocumentTranslationException`; `getHttpStatusCode()` and `getShouldRetry()`
363367
report those of the underlying `DeepLException`, if any.
364368

365369
`translateDocument()` is a convenience function that wraps multiple API calls:
@@ -1330,9 +1334,8 @@ The optional timeout is the maximum time to wait for the import to finish; omit
13301334
it to wait indefinitely. The job status is polled every 5 seconds, and the last
13311335
wait is cut short at the timeout.
13321336

1333-
A missing input file throws `IllegalArgumentException` before any request is
1334-
sent. Any other local I/O failure, such as an unreadable file, throws
1335-
`DeepLException` with the I/O error as its cause.
1337+
A missing input file throws `IllegalArgumentException` and an unreadable file
1338+
throws `IOException`, both before any request is sent.
13361339

13371340
`ImportTranslationMemoryOptions` groups the import options: `setDisplayName()`,
13381341
`setContentType()` (declared when the job is created and sent with the upload;
@@ -1415,9 +1418,9 @@ class Example { // Continuing class Example from above
14151418
```
14161419

14171420
As with import, the timeout is optional; omit it to wait indefinitely. The output
1418-
path is checked before the export job is created: if a file already exists there
1419-
or its directory does not exist, `DeepLException` is thrown. A failure while
1420-
writing the file also throws `DeepLException`, with the I/O error as its cause.
1421+
path is checked before the export job is created: if a file already exists there,
1422+
`IOException` is thrown, and if its directory does not exist,
1423+
`FileNotFoundException`. A failure while writing the file throws `IOException`.
14211424
Instead of a `File`, you can pass an `OutputStream`, which is not closed:
14221425

14231426
```java

‎deepl-java/src/main/java/com/deepl/api/DeepLClient.java‎

Lines changed: 24 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,11 +2606,10 @@ public void downloadTranslationMemoryExport(TranslationMemoryJob job, OutputStre
26062606
* @return {@link TranslationMemoryJob} object for the completed import; its result carries the ID
26072607
* of the new translation memory.
26082608
* @throws IllegalArgumentException If the input file does not exist.
2609-
* @throws IOException Not thrown; local I/O failures are reported as {@link DeepLException}.
2610-
* Declared for source compatibility.
2609+
* @throws IOException If the input file cannot be read.
26112610
* @throws InterruptedException If the thread is interrupted during execution of this function.
2612-
* @throws DeepLException If the input file cannot be read (with the I/O error as cause), the
2613-
* import fails, or any error occurs while communicating with the DeepL API.
2611+
* @throws DeepLException If the import fails, or any error occurs while communicating with the
2612+
* DeepL API.
26142613
*/
26152614
public TranslationMemoryJob importTranslationMemoryFromFilepath(
26162615
File inputFile, @Nullable String displayName)
@@ -2631,12 +2630,10 @@ public TranslationMemoryJob importTranslationMemoryFromFilepath(
26312630
* @return {@link TranslationMemoryJob} object for the completed import; its result carries the ID
26322631
* of the new translation memory.
26332632
* @throws IllegalArgumentException If the input file does not exist.
2634-
* @throws IOException Not thrown; local I/O failures are reported as {@link DeepLException}.
2635-
* Declared for source compatibility.
2633+
* @throws IOException If the input file cannot be read.
26362634
* @throws InterruptedException If the thread is interrupted during execution of this function.
2637-
* @throws DeepLException If the input file cannot be read (with the I/O error as cause), the
2638-
* timeout is exceeded, the import fails, or any error occurs while communicating with the
2639-
* DeepL API.
2635+
* @throws DeepLException If the timeout is exceeded, the import fails, or any error occurs while
2636+
* communicating with the DeepL API.
26402637
* @see DeepLClient#importTranslationMemoryFromFilepath(File, String)
26412638
*/
26422639
public TranslationMemoryJob importTranslationMemoryFromFilepath(
@@ -2659,12 +2656,10 @@ public TranslationMemoryJob importTranslationMemoryFromFilepath(
26592656
* @return {@link TranslationMemoryJob} object for the completed import; its result carries the ID
26602657
* of the new translation memory.
26612658
* @throws IllegalArgumentException If the input file does not exist.
2662-
* @throws IOException Not thrown; local I/O failures are reported as {@link DeepLException}.
2663-
* Declared for source compatibility.
2659+
* @throws IOException If the input file cannot be read.
26642660
* @throws InterruptedException If the thread is interrupted during execution of this function.
2665-
* @throws DeepLException If the input file cannot be read (with the I/O error as cause), the
2666-
* timeout is exceeded, the import fails, or any error occurs while communicating with the
2667-
* DeepL API.
2661+
* @throws DeepLException If the timeout is exceeded, the import fails, or any error occurs while
2662+
* communicating with the DeepL API.
26682663
*/
26692664
public TranslationMemoryJob importTranslationMemoryFromFilepath(
26702665
File inputFile, @Nullable ImportTranslationMemoryOptions options)
@@ -2737,12 +2732,11 @@ public TranslationMemoryJob importTranslationMemoryFromFilepath(File inputFile)
27372732
* @param translationMemoryId ID of the translation memory to export.
27382733
* @param outputFile File to write the exported translation memory to.
27392734
* @return {@link TranslationMemoryJob} object for the completed export.
2740-
* @throws IOException Not thrown; local I/O failures are reported as {@link DeepLException}.
2741-
* Declared for source compatibility.
2735+
* @throws IOException If the output path is occupied or its directory does not exist (checked
2736+
* before the export job is created), or writing the file fails.
27422737
* @throws InterruptedException If the thread is interrupted during execution of this function.
2743-
* @throws DeepLException If the output path is occupied or its directory does not exist (checked
2744-
* before the export job is created), writing the file fails (with the I/O error as cause),
2745-
* the export fails, or any error occurs while communicating with the DeepL API.
2738+
* @throws DeepLException If the export fails, or any error occurs while communicating with the
2739+
* DeepL API.
27462740
*/
27472741
public TranslationMemoryJob exportTranslationMemoryToFilepath(
27482742
String translationMemoryId, File outputFile)
@@ -2760,13 +2754,11 @@ public TranslationMemoryJob exportTranslationMemoryToFilepath(
27602754
* indefinitely. The job status is polled every 5 seconds; the last wait is cut short at the
27612755
* timeout.
27622756
* @return {@link TranslationMemoryJob} object for the completed export.
2763-
* @throws IOException Not thrown; local I/O failures are reported as {@link DeepLException}.
2764-
* Declared for source compatibility.
2757+
* @throws IOException If the output path is occupied or its directory does not exist (checked
2758+
* before the export job is created), or writing the file fails.
27652759
* @throws InterruptedException If the thread is interrupted during execution of this function.
2766-
* @throws DeepLException If the output path is occupied or its directory does not exist (checked
2767-
* before the export job is created), writing the file fails (with the I/O error as cause),
2768-
* the timeout is exceeded, the export fails, or any error occurs while communicating with the
2769-
* DeepL API.
2760+
* @throws DeepLException If the timeout is exceeded, the export fails, or any error occurs while
2761+
* communicating with the DeepL API.
27702762
* @see DeepLClient#exportTranslationMemoryToFilepath(String, File)
27712763
*/
27722764
public TranslationMemoryJob exportTranslationMemoryToFilepath(
@@ -2777,11 +2769,7 @@ public TranslationMemoryJob exportTranslationMemoryToFilepath(
27772769
createTranslationMemoryExport(translationMemoryId);
27782770
TranslationMemoryJob job =
27792771
waitUntilTranslationMemoryJobDone(translationMemoryExport.getJobId(), timeout);
2780-
try {
2781-
downloadTranslationMemoryExport(job, outputFile);
2782-
} catch (IOException exception) {
2783-
throw wrapLocalIOException("Failed to write translation memory export", exception);
2784-
}
2772+
downloadTranslationMemoryExport(job, outputFile);
27852773
return job;
27862774
}
27872775

@@ -2831,11 +2819,7 @@ public TranslationMemoryJob exportTranslationMemoryToFilepath(
28312819
createTranslationMemoryExport(translationMemoryId);
28322820
TranslationMemoryJob job =
28332821
waitUntilTranslationMemoryJobDone(translationMemoryExport.getJobId(), timeout);
2834-
try {
2835-
downloadTranslationMemoryExport(job, outputStream);
2836-
} catch (IOException exception) {
2837-
throw wrapLocalIOException("Failed to write translation memory export", exception);
2838-
}
2822+
downloadTranslationMemoryExport(job, outputStream);
28392823
return job;
28402824
}
28412825

@@ -2922,48 +2906,25 @@ private static String translationMemoryJobId(TranslationMemoryJob job)
29222906
/**
29232907
* Reads a TMX file for import; a missing file is an argument error, raised before any request.
29242908
*/
2925-
private static byte[] readTranslationMemoryFile(@Nullable File inputFile)
2926-
throws DeepLException, InterruptedException {
2909+
private static byte[] readTranslationMemoryFile(@Nullable File inputFile) throws IOException {
29272910
if (inputFile == null || !inputFile.exists()) {
29282911
throw new IllegalArgumentException("inputFile must be an existing file");
29292912
}
2930-
try {
2931-
return Files.readAllBytes(inputFile.toPath());
2932-
} catch (IOException exception) {
2933-
throw wrapLocalIOException("Failed to read translation memory file", exception);
2934-
}
2913+
return Files.readAllBytes(inputFile.toPath());
29352914
}
29362915

29372916
/** Checks the output file of an export so a bad path fails before the export job is created. */
2938-
private static void checkExportOutputFile(@Nullable File outputFile) throws DeepLException {
2917+
private static void checkExportOutputFile(@Nullable File outputFile) throws IOException {
29392918
if (outputFile == null) {
29402919
throw new IllegalArgumentException("outputFile must not be null");
29412920
}
29422921
if (outputFile.exists()) {
2943-
throw new DeepLException("File already exists at output path");
2922+
throw new IOException("File already exists at output path");
29442923
}
29452924
File directory = outputFile.getAbsoluteFile().getParentFile();
29462925
if (directory == null || !directory.isDirectory()) {
2947-
throw new DeepLException("Directory of output path does not exist");
2948-
}
2949-
}
2950-
2951-
/**
2952-
* Wraps a local I/O failure in a {@link DeepLException}; an interrupted I/O operation is reported
2953-
* as {@link InterruptedException} instead, as caller cancellation is never wrapped.
2954-
*/
2955-
private static DeepLException wrapLocalIOException(String message, IOException exception)
2956-
throws InterruptedException {
2957-
boolean interrupted =
2958-
exception instanceof java.nio.channels.ClosedByInterruptException
2959-
|| (exception instanceof InterruptedIOException
2960-
&& !(exception instanceof java.net.SocketTimeoutException));
2961-
if (interrupted) {
2962-
InterruptedException interruptedException = new InterruptedException(exception.getMessage());
2963-
interruptedException.initCause(exception);
2964-
throw interruptedException;
2926+
throw new FileNotFoundException("Directory of output path does not exist");
29652927
}
2966-
return new DeepLException(message + ": " + exception.getMessage(), exception);
29672928
}
29682929

29692930
/** Extracts the ID of the given Spoken Terms collection. */

‎deepl-java/src/main/java/com/deepl/api/Translator.java‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,10 @@ public List<GlossaryLanguagePair> getGlossaryLanguages()
330330
* @param options Options influencing translation.
331331
* @return Status when document translation completed, this allows the number of billed characters
332332
* to be queried.
333-
* @throws IllegalArgumentException If the input file does not exist; no request is sent.
334-
* @throws DocumentTranslationException If the output path is occupied, a file cannot be opened,
335-
* any error occurs while communicating with the DeepL API, or the thread is interrupted
336-
* during execution of this function. The exception includes the document handle that may be
337-
* used to retrieve the document, if the document was uploaded.
338-
* @throws IOException Not thrown; declared for compatibility.
333+
* @throws IOException If the output path is occupied or the input file does not exist.
334+
* @throws DocumentTranslationException If any error occurs while communicating with the DeepL
335+
* API, or if the thread is interrupted during execution of this function. The exception
336+
* includes the document handle that may be used to retrieve the document.
339337
*/
340338
public DocumentStatus translateDocument(
341339
File inputFile,
@@ -344,25 +342,17 @@ public DocumentStatus translateDocument(
344342
String targetLang,
345343
@Nullable DocumentTranslationOptions options)
346344
throws DocumentTranslationException, IOException {
347-
if (!inputFile.exists()) {
348-
throw new IllegalArgumentException("Input file does not exist: " + inputFile.getPath());
349-
}
350345
// Checked before the try block: its handler deletes the output file.
351346
if (outputFile.exists()) {
352-
throw new DocumentTranslationException(
353-
"File already exists at output path: " + outputFile.getPath(), null, null);
347+
throw new IOException("File already exists at output path");
354348
}
355349
try (InputStream inputStream = new FileInputStream(inputFile);
356350
OutputStream outputStream = new FileOutputStream(outputFile)) {
357351
return translateDocument(
358352
inputStream, inputFile.getName(), outputStream, sourceLang, targetLang, options);
359-
} catch (DocumentTranslationException exception) {
353+
} catch (Exception exception) {
360354
outputFile.delete();
361355
throw exception;
362-
} catch (IOException exception) {
363-
outputFile.delete();
364-
throw new DocumentTranslationException(
365-
"Error occurred during document translation: " + exception.getMessage(), exception, null);
366356
}
367357
}
368358

0 commit comments

Comments
 (0)