Skip to content

Commit 41e7411

Browse files
author
Liudmila Molkova
authored
Clientcore: add base exception type, use unchecked exceptions on BinaryData and high-level APIs (Azure#44892)
* Add base CoreException
1 parent 51a3f69 commit 41e7411

File tree

63 files changed

+1078
-607
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1078
-607
lines changed

sdk/clientcore/annotation-processor-test/src/test/java/io/clientcore/annotation/processor/test/LocalHttpClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public Response<BinaryData> send(HttpRequest request) {
3434

3535
return new Response<BinaryData>(request, success ? 200 : 400, new HttpHeaders(), BinaryData.empty()) {
3636
@Override
37-
public void close() throws IOException {
37+
public void close() {
3838
closeCalledOnResponse = true;
3939

4040
super.close();

sdk/clientcore/annotation-processor-test/src/test/java/io/clientcore/annotation/processor/test/http/TestInterfaceGenerationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ public Response<BinaryData> send(HttpRequest request) {
181181

182182
return new Response<BinaryData>(request, success ? 200 : 400, new HttpHeaders(), BinaryData.empty()) {
183183
@Override
184-
public void close() throws IOException {
184+
public void close() {
185185
closeCalledOnResponse = true;
186186

187187
super.close();

sdk/clientcore/annotation-processor/README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,7 @@ The client-core annotation processor for introducing compile-time code generatio
120120
throw new RuntimeException("Unexpected response code: " + responseCode);
121121
}
122122

123-
try {
124-
networkResponse.close();
125-
} catch (IOException e) {
126-
throw LOGGER.logThrowableAsError(new UncheckedIOException(e));
127-
}
128-
123+
networkResponse.close();
129124
return networkResponse;
130125
}
131126
}

sdk/clientcore/annotation-processor/src/main/java/io/clientcore/annotation/processor/templating/JavaParserTemplateProcessor.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import io.clientcore.core.serialization.json.JsonSerializer;
3535
import io.clientcore.core.serialization.xml.XmlSerializer;
3636
import java.io.IOException;
37-
import java.io.UncheckedIOException;
3837
import java.io.Writer;
3938
import java.lang.reflect.Field;
4039
import java.lang.reflect.ParameterizedType;
@@ -194,15 +193,14 @@ private void addDeserializeHelperMethod(MethodDeclaration deserializeHelperMetho
194193
.addParameter(ObjectSerializer.class, "serializer")
195194
.addParameter("ParameterizedType", "returnType");
196195
deserializeHelperMethod.tryAddImportToParentCompilationUnit(IOException.class);
197-
deserializeHelperMethod.tryAddImportToParentCompilationUnit(UncheckedIOException.class);
198196
deserializeHelperMethod.tryAddImportToParentCompilationUnit(ParameterizedType.class);
199197
deserializeHelperMethod.tryAddImportToParentCompilationUnit(Type.class);
200198
deserializeHelperMethod.tryAddImportToParentCompilationUnit(List.class);
201199
deserializeHelperMethod
202200
.setJavadocComment("Decodes the body of an {@link Response} into the type returned by the called API.\n"
203201
+ "@param data The BinaryData to decode.\n" + "@param serializer The serializer to use.\n"
204202
+ "@param returnType The type of the ParameterizedType return value.\n" + "@return The decoded value.\n"
205-
+ "@throws IOException If the deserialization fails.");
203+
+ "@throws CoreException If the deserialization fails.");
206204

207205
deserializeHelperMethod.setBody(new BlockStmt()
208206
.addStatement(StaticJavaParser.parseStatement("if (data == null) { return null; }"))
@@ -212,7 +210,7 @@ private void addDeserializeHelperMethod(MethodDeclaration deserializeHelperMetho
212210
+ "Type token = returnType.getRawType(); if (Response.class.isAssignableFrom((Class<?>) token)) { "
213211
+ " token = returnType.getActualTypeArguments()[0]; } "
214212
+ "return serializer.deserializeFromBytes(data.toBytes(), token); } catch (IOException e) { "
215-
+ " throw LOGGER.logThrowableAsError(new UncheckedIOException(e)); }")));
213+
+ " throw LOGGER.logThrowableAsError(CoreException.from(e)); }")));
216214

217215
}
218216

sdk/clientcore/annotation-processor/src/main/java/io/clientcore/annotation/processor/utils/ResponseHandler.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.clientcore.annotation.processor.models.HttpRequestContext;
1212
import io.clientcore.core.http.models.HttpMethod;
1313
import io.clientcore.core.implementation.TypeUtil;
14+
import io.clientcore.core.models.CoreException;
1415
import io.clientcore.core.models.binarydata.BinaryData;
1516
import io.clientcore.core.serialization.SerializationFormat;
1617
import io.clientcore.core.utils.CoreUtils;
@@ -21,7 +22,6 @@
2122
import javax.lang.model.type.TypeMirror;
2223
import java.io.IOException;
2324
import java.io.InputStream;
24-
import java.io.UncheckedIOException;
2525
import java.util.List;
2626
import java.util.stream.Collectors;
2727

@@ -262,9 +262,8 @@ private static void handleInputStreamResponse(BlockStmt body) {
262262

263263
private static void closeResponse(BlockStmt body) {
264264
body.tryAddImportToParentCompilationUnit(IOException.class);
265-
body.tryAddImportToParentCompilationUnit(UncheckedIOException.class);
266-
body.addStatement(StaticJavaParser.parseStatement("try { networkResponse.close(); } catch (IOException e) { "
267-
+ "throw LOGGER.logThrowableAsError(new UncheckedIOException(e)); }"));
265+
body.tryAddImportToParentCompilationUnit(CoreException.class);
266+
body.addStatement(StaticJavaParser.parseStatement("networkResponse.close();"));
268267
}
269268

270269
/**

sdk/clientcore/core/spotbugs-exclude.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<Class name="io.clientcore.core.implementation.utils.SliceInputStream" />
3232
<Class name="io.clientcore.core.implementation.utils.StreamUtil" />
3333
<Class name="io.clientcore.core.models.CloudEvent" />
34+
<Class name="io.clientcore.core.models.binarydata.BinaryData" />
3435
<Class name="io.clientcore.core.models.binarydata.FileBinaryData" />
3536
<Class name="io.clientcore.core.models.binarydata.InputStreamBinaryData" />
3637
<Class name="io.clientcore.core.models.binarydata.ListByteBufferBinaryData" />

sdk/clientcore/core/src/main/java/io/clientcore/core/http/client/HttpClient.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
import io.clientcore.core.http.models.HttpRequest;
77
import io.clientcore.core.http.models.Response;
88
import io.clientcore.core.implementation.http.client.GlobalJdkHttpClient;
9+
import io.clientcore.core.models.CoreException;
910
import io.clientcore.core.models.binarydata.BinaryData;
1011

11-
import java.io.IOException;
12-
1312
/**
1413
* A generic interface for sending HTTP requests and getting responses.
1514
*/
@@ -19,9 +18,9 @@ public interface HttpClient {
1918
*
2019
* @param request The HTTP request to send.
2120
* @return The response.
22-
* @throws IOException If an I/O error occurs during sending the request or receiving the response.
21+
* @throws CoreException If any error occurs during sending the request or receiving the response.
2322
*/
24-
Response<BinaryData> send(HttpRequest request) throws IOException;
23+
Response<BinaryData> send(HttpRequest request);
2524

2625
/**
2726
* Get a new instance of the {@link HttpClient} that the {@link HttpClientProvider} loaded from the classpath is

sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/HttpResponseException.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55

66
import io.clientcore.core.annotations.Metadata;
77
import io.clientcore.core.annotations.MetadataProperties;
8+
import io.clientcore.core.implementation.http.RetryUtils;
9+
import io.clientcore.core.models.CoreException;
810
import io.clientcore.core.models.binarydata.BinaryData;
911

1012
/**
1113
* The exception thrown when an unsuccessful response is received with http status code (e.g. {@code 3XX}, {@code 4XX},
1214
* {@code 5XX}) from the service request.
1315
*/
1416
@Metadata(properties = MetadataProperties.IMMUTABLE)
15-
public class HttpResponseException extends RuntimeException {
17+
public class HttpResponseException extends CoreException {
1618
/**
1719
* The HTTP response value.
1820
*/
@@ -23,6 +25,11 @@ public class HttpResponseException extends RuntimeException {
2325
*/
2426
private final Response<BinaryData> response;
2527

28+
/**
29+
* Indicates whether the exception is retryable.
30+
*/
31+
private final boolean isRetryable;
32+
2633
/**
2734
* Initializes a new instance of the HttpResponseException class.
2835
*
@@ -31,10 +38,11 @@ public class HttpResponseException extends RuntimeException {
3138
* @param value The deserialized response value.
3239
*/
3340
public HttpResponseException(final String message, final Response<BinaryData> response, final Object value) {
34-
super(message);
41+
super(message, null);
3542

3643
this.value = value;
3744
this.response = response;
45+
this.isRetryable = response == null || RetryUtils.isRetryable(response.getStatusCode());
3846
}
3947

4048
/**
@@ -49,6 +57,8 @@ public HttpResponseException(final String message, final Response<BinaryData> re
4957

5058
this.value = null;
5159
this.response = response;
60+
this.isRetryable
61+
= response != null ? RetryUtils.isRetryable(response.getStatusCode()) : RetryUtils.isRetryable(cause);
5262
}
5363

5464
/**
@@ -68,4 +78,9 @@ public Response<BinaryData> getResponse() {
6878
public Object getValue() {
6979
return value;
7080
}
81+
82+
@Override
83+
public boolean isRetryable() {
84+
return isRetryable;
85+
}
7186
}

sdk/clientcore/core/src/main/java/io/clientcore/core/http/models/Response.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
package io.clientcore.core.http.models;
55

6+
import io.clientcore.core.instrumentation.logging.ClientLogger;
7+
import io.clientcore.core.models.CoreException;
8+
69
import java.io.Closeable;
710
import java.io.IOException;
811

@@ -12,6 +15,7 @@
1215
* @param <T> The deserialized type of the response content, available from {@link #getValue()}.
1316
*/
1417
public class Response<T> implements Closeable {
18+
private static final ClientLogger LOGGER = new ClientLogger(Response.class);
1519
private final HttpHeaders headers;
1620
private final HttpRequest request;
1721
private final int statusCode;
@@ -71,12 +75,16 @@ public T getValue() {
7175
/**
7276
* If {@link #getValue()} is a {@link Closeable} type, this method will close it.
7377
*
74-
* @throws IOException If an error occurs while closing the response.
78+
* @throws CoreException If an error occurs while closing the response.
7579
*/
7680
@Override
77-
public void close() throws IOException {
81+
public void close() {
7882
if (value instanceof Closeable) {
79-
((Closeable) value).close();
83+
try {
84+
((Closeable) value).close();
85+
} catch (IOException e) {
86+
throw LOGGER.logThrowableAsError(CoreException.from(e, false));
87+
}
8088
}
8189
}
8290
}

sdk/clientcore/core/src/main/java/io/clientcore/core/http/pipeline/HttpInstrumentationPolicy.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,7 @@ private double getDurationMs(long startNs, long endNs) {
521521
* @return A flag indicating if the request or response body should be logged.
522522
*/
523523
private static boolean canLogBody(BinaryData data) {
524-
// TODO (limolkova) we might want to filter out binary data, but
525-
// if somebody enabled logging it - why not log it?
524+
// TODO (limolkova) we might want to filter out binary data, but if somebody enabled logging it - why not log it?
526525
return data != null && data.getLength() != null && data.getLength() > 0 && data.getLength() < MAX_BODY_LOG_SIZE;
527526
}
528527

@@ -619,7 +618,7 @@ public BinaryData getValue() {
619618
}
620619

621620
@Override
622-
public void close() throws IOException {
621+
public void close() {
623622
if (bufferedBody == null) {
624623
getValue();
625624
}

0 commit comments

Comments
 (0)