28
28
import io .clientcore .core .http .models .HttpHeaderName ;
29
29
import io .clientcore .core .http .models .HttpMethod ;
30
30
import io .clientcore .core .http .models .HttpRequest ;
31
+ import io .clientcore .core .http .models .HttpResponseException ;
31
32
import io .clientcore .core .http .models .Response ;
32
33
import io .clientcore .core .http .pipeline .HttpPipeline ;
33
34
import io .clientcore .core .implementation .utils .UriEscapers ;
38
39
import java .io .IOException ;
39
40
import java .io .Writer ;
40
41
import java .lang .reflect .Field ;
42
+ import java .nio .charset .StandardCharsets ;
41
43
import java .util .Arrays ;
42
44
import java .util .HashMap ;
43
45
import java .util .LinkedHashMap ;
47
49
import java .util .Optional ;
48
50
import java .util .stream .Collectors ;
49
51
import javax .annotation .processing .ProcessingEnvironment ;
52
+ import javax .lang .model .element .TypeElement ;
53
+ import javax .lang .model .type .DeclaredType ;
50
54
import javax .lang .model .type .TypeKind ;
51
55
import javax .lang .model .type .TypeMirror ;
52
56
@@ -141,6 +145,34 @@ void createClass(String serviceInterfaceImplShortName, String serviceInterfaceSh
141
145
processingEnv );
142
146
}
143
147
}
148
+
149
+ addInstantiateExceptionHelperMethod (classBuilder .addMethod ("instantiateUnexpectedException" ,
150
+ Modifier .Keyword .PRIVATE , Modifier .Keyword .STATIC ));
151
+ }
152
+
153
+ private void addInstantiateExceptionHelperMethod (MethodDeclaration instantiateUnexpectedException ) {
154
+ instantiateUnexpectedException .setType ("HttpResponseException" )
155
+ .addParameter ("int" , "responseCode" )
156
+ .addParameter ("Response<BinaryData>" , "response" )
157
+ .addParameter ("BinaryData" , "data" )
158
+ .addParameter ("Object" , "decodedValue" );
159
+ instantiateUnexpectedException .setBody (StaticJavaParser .parseBlock ("{\n "
160
+ + " StringBuilder exceptionMessage = new StringBuilder(\" Status code \" )\n "
161
+ + " .append(responseCode).append(\" , \" );\n "
162
+ + " String contentType = response.getHeaders().getValue(HttpHeaderName.CONTENT_TYPE);\n "
163
+ + " if (\" application/octet-stream\" .equalsIgnoreCase(contentType)) {\n "
164
+ + " String contentLength = response.getHeaders().getValue(HttpHeaderName.CONTENT_LENGTH);\n "
165
+ + " exceptionMessage.append(\" (\" ).append(contentLength).append(\" -byte body)\" );\n "
166
+ + " } else if (data == null || data.toBytes().length == 0) {\n "
167
+ + " exceptionMessage.append(\" (empty body)\" );\n " + " } else {\n "
168
+ + " exceptionMessage.append('\" ').append(new String(data.toBytes(), StandardCharsets.UTF_8)).append('\" ');\n "
169
+ + " }\n "
170
+ + " if (decodedValue instanceof IOException || decodedValue instanceof IllegalStateException) {\n "
171
+ + " return new HttpResponseException(exceptionMessage.toString(), response, (Throwable) decodedValue);\n "
172
+ + " }\n " + " return new HttpResponseException(exceptionMessage.toString(), response, decodedValue);\n "
173
+ + "}" ));
174
+ instantiateUnexpectedException .tryAddImportToParentCompilationUnit (HttpResponseException .class );
175
+ instantiateUnexpectedException .tryAddImportToParentCompilationUnit (StandardCharsets .class );
144
176
}
145
177
146
178
private void addLoggerField (String serviceInterfaceShortName ) {
@@ -402,17 +434,14 @@ private void appendQueryParams(BlockStmt body, HttpRequestContext method) {
402
434
}
403
435
404
436
/**
405
- * Adds headers to the HttpRequest using the provided HttpRequestContext.
406
- * Handles both static and dynamic headers, and applies correct quoting logic for static values.
437
+ * Adds headers to the HttpRequest using the provided HttpRequestContext. Handles both static and dynamic headers,
438
+ * and applies correct quoting logic for static values.
407
439
* <p>
408
- * Quoting logic:
409
- * - If value starts and ends with ", use as-is.
410
- * - If starts with ", append trailing ".
411
- * - If ends with ", prepend leading ".
412
- * - Otherwise, wrap value in quotes.
440
+ * Quoting logic: - If value starts and ends with ", use as-is. - If starts with ", append trailing ". - If ends
441
+ * with ", prepend leading ". - Otherwise, wrap value in quotes.
413
442
* <p>
414
- * For dynamic headers (parameter-based), values are not quoted.
415
- * For static headers (literal values), quoting is always applied.
443
+ * For dynamic headers (parameter-based), values are not quoted. For static headers (literal values), quoting is
444
+ * always applied.
416
445
* <p>
417
446
*/
418
447
private void addHeadersToRequest (BlockStmt body , HttpRequestContext method ) {
@@ -506,21 +535,17 @@ private void finalizeHttpRequest(BlockStmt body, TypeMirror returnTypeName, Http
506
535
statement .setLineComment ("\n Send the request through the httpPipeline" );
507
536
body .addStatement (statement );
508
537
509
- if (!method .getExpectedStatusCodes ().isEmpty ()) {
510
- validateResponseStatus (body , method );
511
- }
538
+ validateResponseStatus (body , method );
512
539
513
540
generateResponseHandling (body , returnTypeName , method , serializationFormatSet );
514
541
}
515
542
516
543
private void validateResponseStatus (BlockStmt body , HttpRequestContext method ) {
517
- if (method .getExpectedStatusCodes ().isEmpty ()) {
518
- return ;
519
- }
520
-
521
544
body .addStatement (StaticJavaParser .parseStatement ("int responseCode = networkResponse.getStatusCode();" ));
522
545
String expectedResponseCheck ;
523
- if (method .getExpectedStatusCodes ().size () == 1 ) {
546
+ if (CoreUtils .isNullOrEmpty (method .getExpectedStatusCodes ())) {
547
+ expectedResponseCheck = "responseCode < 400;" ;
548
+ } else if (method .getExpectedStatusCodes ().size () == 1 ) {
524
549
expectedResponseCheck = "responseCode == " + method .getExpectedStatusCodes ().get (0 ) + ";" ;
525
550
} else {
526
551
String statusCodes = method .getExpectedStatusCodes ()
@@ -530,9 +555,64 @@ private void validateResponseStatus(BlockStmt body, HttpRequestContext method) {
530
555
expectedResponseCheck = "(" + statusCodes + ");" ;
531
556
}
532
557
body .addStatement (StaticJavaParser .parseStatement ("boolean expectedResponse = " + expectedResponseCheck ));
558
+ // Generate the error handling block with dynamic ParameterizedType creation
559
+ StringBuilder errorBlock = new StringBuilder ();
560
+ errorBlock .append ("if (!expectedResponse) {\n " )
561
+ .append (
562
+ " if (networkResponse.getValue() == null || networkResponse.getValue().toBytes().length == 0) {\n " )
563
+ .append (" throw instantiateUnexpectedException(responseCode, networkResponse, null, null);\n " )
564
+ .append (" } else {\n " );
565
+
566
+ // Dynamically generate ParameterizedType if return type is declared
567
+ TypeMirror returnType = method .getMethodReturnType ();
568
+ if (returnType .getKind () == TypeKind .DECLARED ) {
569
+ DeclaredType declaredType = (DeclaredType ) returnType ;
570
+ TypeElement typeElement = (TypeElement ) declaredType .asElement ();
571
+ body .tryAddImportToParentCompilationUnit (CoreUtils .class );
572
+ StringBuilder paramTypeBuilder = new StringBuilder ();
573
+ paramTypeBuilder .append (typeElement .getQualifiedName ().toString ()).append (".class" );
574
+
575
+ if (!declaredType .getTypeArguments ().isEmpty ()) {
576
+ TypeMirror firstGenericType = declaredType .getTypeArguments ().get (0 );
577
+
578
+ if (firstGenericType instanceof DeclaredType ) {
579
+ DeclaredType genericDeclaredType = (DeclaredType ) firstGenericType ;
580
+ TypeElement genericTypeElement = (TypeElement ) genericDeclaredType .asElement ();
581
+
582
+ body .findCompilationUnit ()
583
+ .ifPresent (compilationUnit -> compilationUnit
584
+ .addImport (genericTypeElement .getQualifiedName ().toString ()));
585
+
586
+ if (genericTypeElement .getQualifiedName ().contentEquals (List .class .getCanonicalName ())) {
587
+ if (!genericDeclaredType .getTypeArguments ().isEmpty ()) {
588
+ String innerType
589
+ = ((DeclaredType ) genericDeclaredType .getTypeArguments ().get (0 )).asElement ()
590
+ .getSimpleName ()
591
+ .toString ();
592
+ paramTypeBuilder .append (", " ).append (innerType ).append (".class" );
593
+ }
594
+ } else {
595
+ String genericType = ((DeclaredType ) declaredType .getTypeArguments ().get (0 )).asElement ()
596
+ .getSimpleName ()
597
+ .toString ();
598
+ paramTypeBuilder .append (", " ).append (genericType ).append (".class" );
599
+
600
+ }
601
+ }
602
+ }
603
+ errorBlock .append (" ParameterizedType returnType = CoreUtils.createParameterizedType(" )
604
+ .append (paramTypeBuilder )
605
+ .append (");\n " );
606
+ } else {
607
+ errorBlock .append (" ParameterizedType returnType = null;\n " );
608
+
609
+ }
533
610
534
- body .tryAddImportToParentCompilationUnit (RuntimeException .class );
535
- body .addStatement (StaticJavaParser .parseStatement ("if (!expectedResponse) {"
536
- + " throw new RuntimeException(\" Unexpected response code: \" + responseCode); }" ));
611
+ errorBlock .append (
612
+ " throw instantiateUnexpectedException(responseCode, networkResponse, networkResponse.getValue(), " )
613
+ .append ("decodeNetworkResponse(networkResponse.getValue(), jsonSerializer, returnType));\n " )
614
+ .append (" }\n " )
615
+ .append ("}\n " );
616
+ body .addStatement (StaticJavaParser .parseStatement (errorBlock .toString ()));
537
617
}
538
618
}
0 commit comments