-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
[Java][jersey3] Add error entity deserialization to ApiException #23542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 8 commits
8791c1b
b959b91
be83c27
3ec7cc4
1acccd6
c43dea8
48ad522
6ac9def
4c9242f
370875b
3dbdad6
f719489
5bc693d
a967b51
5dedcc8
7275384
b20c211
75b7418
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,6 +54,7 @@ import java.util.List; | |
| import java.util.Arrays; | ||
| import java.util.ArrayList; | ||
| import java.util.Date; | ||
| import java.util.Locale; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.Stream; | ||
| {{#jsr310}} | ||
|
|
@@ -1196,6 +1197,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { | |
| * @param authNames The authentications to apply | ||
| * @param returnType The return type into which to deserialize the response | ||
| * @param isBodyNullable True if the body is nullable | ||
| * @param errorTypes Mapping of error codes to types into which to deserialize the response | ||
| * @return The response body in type of string | ||
| * @throws ApiException API exception | ||
| */ | ||
|
|
@@ -1212,7 +1214,9 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { | |
| String contentType, | ||
| String[] authNames, | ||
| GenericType<T> returnType, | ||
| boolean isBodyNullable) | ||
| boolean isBodyNullable, | ||
| Map<String, GenericType> errorTypes | ||
| ) | ||
| throws ApiException { | ||
|
|
||
| String targetURL; | ||
|
|
@@ -1223,7 +1227,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { | |
| if (index < 0 || index >= serverConfigurations.size()) { | ||
| throw new ArrayIndexOutOfBoundsException( | ||
| String.format( | ||
| java.util.Locale.ROOT, | ||
| Locale.ROOT, | ||
| "Invalid index %d when selecting the host settings. Must be less than %d", | ||
| index, serverConfigurations.size())); | ||
| } | ||
|
|
@@ -1333,14 +1337,16 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { | |
| String respBody = null; | ||
| if (response.hasEntity()) { | ||
| try { | ||
| // call bufferEntity, so that a subsequent call to `readEntity` in `deserialize` doesn't fail | ||
| response.bufferEntity(); | ||
| respBody = String.valueOf(response.readEntity(String.class)); | ||
| message = respBody; | ||
| } catch (RuntimeException e) { | ||
| // e.printStackTrace(); | ||
| } | ||
| } | ||
| throw new ApiException( | ||
| response.getStatus(), message, buildResponseHeaders(response), respBody); | ||
| response.getStatus(), message, buildResponseHeaders(response), respBody, deserializeErrorEntity(errorTypes, response)); | ||
| } | ||
| } finally { | ||
| try { | ||
|
|
@@ -1351,6 +1357,21 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { | |
| } | ||
| } | ||
| } | ||
|
|
||
| private Object deserializeErrorEntity(Map<String, GenericType> errorTypes, Response response) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add a docstring explaining what this function does
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| if (errorTypes == null) { | ||
| return null; | ||
| } | ||
| GenericType errorType = errorTypes.get(String.valueOf(response.getStatus())); | ||
| if (errorType == null) { | ||
| errorType = errorTypes.get("0"); // "0" is the "default" response | ||
| } | ||
| try { | ||
| return deserialize(response, errorType); | ||
| } catch (Exception e) { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| protected Response sendRequest(String method, Invocation.Builder invocationBuilder, Entity<?> entity) { | ||
| Response response; | ||
|
|
@@ -1377,7 +1398,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { | |
| */ | ||
| @Deprecated | ||
| public <T> ApiResponse<T> invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> cookieParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType, boolean isBodyNullable) throws ApiException { | ||
| return invokeAPI(null, path, method, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames, returnType, isBodyNullable); | ||
| return invokeAPI(null, path, method, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames, returnType, isBodyNullable, null/*TODO SME manage*/); | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| /* | ||
| * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) | ||
| * Copyright 2018 SmartBear Software | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please remove line 3
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @wing328 done |
||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.openapitools.codegen.java.jersey3; | ||
|
|
||
| import org.testng.annotations.Test; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| import static org.testng.Assert.*; | ||
|
|
||
| /** | ||
| * Functional test for errorEntity deserialization feature. | ||
| * | ||
| * This test verifies that the generated code includes the errorEntity | ||
| * field and getErrorEntity() method by examining the generated templates. | ||
| * | ||
| * Full integration tests would require: | ||
| * 1. A running mock HTTP server | ||
| * 2. Generated client code compiled and executed | ||
| * 3. Actual API calls to verify runtime behavior | ||
| * | ||
| * The client's original project (BudgetApiTest) provides this type of | ||
| * functional testing. This test verifies the template structure is correct. | ||
| */ | ||
| public class JavaJersey3ErrorEntityFunctionalTest { | ||
|
|
||
| private static final String JERSEY3_TEMPLATE_DIR = | ||
| "src/main/resources/Java/libraries/jersey3/"; | ||
|
|
||
| /** | ||
| * Verify generated code includes errorEntity field in ApiException | ||
| */ | ||
| @Test | ||
| public void testGeneratedApiExceptionHasErrorEntity() throws Exception { | ||
| String template = readTemplate("apiException.mustache"); | ||
| assertNotNull(template); | ||
|
|
||
| // Verify errorEntity field exists | ||
| assertTrue(template.contains("private Object errorEntity = null"), | ||
| "Generated ApiException should have errorEntity field"); | ||
|
|
||
| // Verify getErrorEntity() method exists | ||
| assertTrue(template.contains("public Object getErrorEntity()"), | ||
| "Generated ApiException should have getErrorEntity() method"); | ||
|
|
||
| // Verify constructor with errorEntity parameter | ||
| assertTrue(template.contains("Object errorEntity"), | ||
| "Generated ApiException should accept errorEntity in constructor"); | ||
| } | ||
|
|
||
| /** | ||
| * Verify generated code includes deserializeErrorEntity method | ||
| */ | ||
| @Test | ||
| public void testGeneratedApiClientHasDeserializeErrorEntity() throws Exception { | ||
| String template = readTemplate("ApiClient.mustache"); | ||
| assertNotNull(template); | ||
|
|
||
| // Verify deserializeErrorEntity method exists | ||
| assertTrue(template.contains("deserializeErrorEntity"), | ||
| "Generated ApiClient should have deserializeErrorEntity method"); | ||
|
|
||
| // Verify errorTypes parameter handling | ||
| assertTrue(template.contains("Map<String, GenericType> errorTypes"), | ||
| "Generated ApiClient should handle errorTypes parameter"); | ||
| } | ||
|
|
||
| /** | ||
| * Verify generated API methods build error types map | ||
| */ | ||
| @Test | ||
| public void testGeneratedApiMethodsBuildErrorTypesMap() throws Exception { | ||
| String template = readTemplate("api.mustache"); | ||
| assertNotNull(template); | ||
|
|
||
| // Verify localVarErrorTypes is built | ||
| assertTrue(template.contains("localVarErrorTypes"), | ||
| "Generated API methods should build localVarErrorTypes"); | ||
|
|
||
| // Verify error types are put into the map | ||
| assertTrue(template.contains("localVarErrorTypes.put"), | ||
| "Generated API methods should put error types into map"); | ||
| } | ||
|
|
||
| /** | ||
| * Verify null is returned when deserialization fails | ||
| */ | ||
| @Test | ||
| public void testDeserializationReturnsNullOnFailure() throws Exception { | ||
| String template = readTemplate("ApiClient.mustache"); | ||
| assertNotNull(template); | ||
|
|
||
| // Verify that on exception, null is returned (not error message) | ||
| // This is the fix we applied for the P2 issue | ||
| assertFalse(template.contains("String.format(\"Failed deserializing"), | ||
| "deserializeErrorEntity should return null, not error message string"); | ||
| } | ||
|
|
||
| /** | ||
| * Helper method to read template files | ||
| */ | ||
| private String readTemplate(String templateName) throws Exception { | ||
| java.nio.file.Path templatePath = java.nio.file.Paths.get(JERSEY3_TEMPLATE_DIR + templateName); | ||
| if (java.nio.file.Files.exists(templatePath)) { | ||
| return java.nio.file.Files.readString(templatePath); | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Public operation-aware
invokeAPIsignature was changed without preserving the previous overload, causing source compatibility break for existing callers/overrides.Prompt for AI agents