diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/ApiClient.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/ApiClient.mustache index 3f999481db2c..67b0ca6f0ab9 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/ApiClient.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/ApiClient.mustache @@ -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 returnType, - boolean isBodyNullable) + boolean isBodyNullable, + Map 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,6 +1337,8 @@ 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) { @@ -1340,7 +1346,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { } } throw new ApiException( - response.getStatus(), message, buildResponseHeaders(response), respBody); + response.getStatus(), message, buildResponseHeaders(response), respBody, deserializeErrorEntity(errorTypes, response)); } } finally { try { @@ -1351,6 +1357,30 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { } } } + + /** + * Deserialize the response body into an error entity based on HTTP status code. + * Looks up the error type from the errorTypes map using the response status code, + * or falls back to the "default" error type if no match is found. + * + * @param errorTypes Map of status code strings to GenericType for deserialization + * @param response The HTTP response + * @return The deserialized error entity, or null if not found or deserialization fails + */ + private Object deserializeErrorEntity(Map errorTypes, Response response) { + 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 +1407,7 @@ public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { */ @Deprecated public ApiResponse invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String accept, String contentType, String[] authNames, GenericType 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*/); } /** diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/api.mustache index c663d7580a7e..feb5324dd7e2 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/api.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/api.mustache @@ -195,12 +195,18 @@ public class {{classname}} { {{#hasAuthMethods}} String[] localVarAuthNames = {{=% %=}}new String[] {%#authMethods%"%name%"%^-last%, %/-last%%/authMethods%};%={{ }}=% {{/hasAuthMethods}} + final Map localVarErrorTypes = new HashMap(); + {{#responses}} + {{#dataType}} + localVarErrorTypes.put("{{code}}", new GenericType<{{{dataType}}}>() {}); + {{/dataType}} + {{/responses}} {{#returnType}} GenericType<{{{returnType}}}> localVarReturnType = new GenericType<{{{returnType}}}>() {}; {{/returnType}} return apiClient.invokeAPI("{{classname}}.{{operationId}}", {{#hasPathParams}}localVarPath{{/hasPathParams}}{{^hasPathParams}}"{{{path}}}"{{/hasPathParams}}, "{{httpMethod}}", {{#queryParams}}{{#-first}}localVarQueryParams{{/-first}}{{/queryParams}}{{^queryParams}}new ArrayList<>(){{/queryParams}}, {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}, {{#headerParams}}{{#-first}}localVarHeaderParams{{/-first}}{{/headerParams}}{{^headerParams}}new LinkedHashMap<>(){{/headerParams}}, {{#cookieParams}}{{#-first}}localVarCookieParams{{/-first}}{{/cookieParams}}{{^cookieParams}}new LinkedHashMap<>(){{/cookieParams}}, {{#formParams}}{{#-first}}localVarFormParams{{/-first}}{{/formParams}}{{^formParams}}new LinkedHashMap<>(){{/formParams}}, localVarAccept, localVarContentType, - {{#hasAuthMethods}}localVarAuthNames{{/hasAuthMethods}}{{^hasAuthMethods}}null{{/hasAuthMethods}}, {{#returnType}}localVarReturnType{{/returnType}}{{^returnType}}null{{/returnType}}, {{#bodyParam}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/bodyParam}}{{^bodyParam}}false{{/bodyParam}}); + {{#hasAuthMethods}}localVarAuthNames{{/hasAuthMethods}}{{^hasAuthMethods}}null{{/hasAuthMethods}}, {{#returnType}}localVarReturnType{{/returnType}}{{^returnType}}null{{/returnType}}, {{#bodyParam}}{{#isNullable}}true{{/isNullable}}{{^isNullable}}false{{/isNullable}}{{/bodyParam}}{{^bodyParam}}false{{/bodyParam}}, localVarErrorTypes); } {{#vendorExtensions.x-group-parameters}} diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/apiException.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/apiException.mustache index d957acd81fd1..73548e25abc1 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/apiException.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/jersey3/apiException.mustache @@ -20,6 +20,7 @@ public class ApiException extends{{#useRuntimeException}} RuntimeException {{/us private int code = 0; private Map> responseHeaders = null; private String responseBody = null; + private transient Object errorEntity = null; public ApiException() {} @@ -73,6 +74,11 @@ public class ApiException extends{{#useRuntimeException}} RuntimeException {{/us this.responseBody = responseBody; } + public ApiException(int code, String message, Map> responseHeaders, String responseBody, Object errorEntity) { + this(code, message, responseHeaders, responseBody); + this.errorEntity = errorEntity; + } + /** * Get the HTTP status code. * @@ -99,4 +105,13 @@ public class ApiException extends{{#useRuntimeException}} RuntimeException {{/us public String getResponseBody() { return responseBody; } + + /** + * Get the deserialized error entity (or null if this error doesn't have a model associated). + * + * @return Deserialized error entity + */ + public Object getErrorEntity() { + return errorEntity; + } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jersey3/JavaJersey3ErrorEntityFunctionalTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jersey3/JavaJersey3ErrorEntityFunctionalTest.java new file mode 100644 index 000000000000..6b3610fc8c56 --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jersey3/JavaJersey3ErrorEntityFunctionalTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * 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 (transient for serialization safety) + assertTrue(template.contains("private transient 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 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; + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jersey3/JavaJersey3ErrorEntityTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jersey3/JavaJersey3ErrorEntityTest.java new file mode 100644 index 000000000000..290ea2b251dc --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jersey3/JavaJersey3ErrorEntityTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * 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 static org.testng.Assert.*; + +/** + * Tests for error entity deserialization in jersey3 client + * + * These tests verify that the templates generate the correct code + * for errorEntity feature (issue #4777) + */ +public class JavaJersey3ErrorEntityTest { + + private static final String JERSEY3_TEMPLATE_DIR = + "src/main/resources/Java/libraries/jersey3/"; + + /** + * Test that apiException.mustache contains errorEntity field + */ + @Test + public void testApiExceptionHasErrorEntityField() throws Exception { + String template = readTemplate("apiException.mustache"); + assertNotNull(template, "apiException.mustache should exist"); + assertTrue(template.contains("errorEntity"), + "apiException.mustache should contain 'errorEntity' field"); + } + + /** + * Test that apiException.mustache contains getErrorEntity method + */ + @Test + public void testApiExceptionHasGetErrorEntityMethod() throws Exception { + String template = readTemplate("apiException.mustache"); + assertNotNull(template); + assertTrue(template.contains("getErrorEntity"), + "apiException.mustache should contain 'getErrorEntity()' method"); + } + + /** + * Test that ApiClient.mustache contains deserializeErrorEntity method + */ + @Test + public void testApiClientHasDeserializeErrorEntityMethod() throws Exception { + String template = readTemplate("ApiClient.mustache"); + assertNotNull(template); + assertTrue(template.contains("deserializeErrorEntity"), + "ApiClient.mustache should contain 'deserializeErrorEntity' method"); + } + + /** + * Test that api.mustache contains localVarErrorTypes + */ + @Test + public void testApiGeneratesErrorTypesMap() throws Exception { + String template = readTemplate("api.mustache"); + assertNotNull(template); + assertTrue(template.contains("localVarErrorTypes"), + "api.mustache should contain 'localVarErrorTypes'"); + } + + /** + * Test that invokeAPI accepts errorTypes parameter + */ + @Test + public void testInvokeAPIHasErrorTypesParameter() throws Exception { + String template = readTemplate("ApiClient.mustache"); + assertNotNull(template); + assertTrue(template.contains("errorTypes"), + "ApiClient.mustache should contain 'errorTypes' parameter"); + } + + /** + * Test that template handles "default" response (uses "0" as key) + */ + @Test + public void testDefaultResponseHandling() throws Exception { + String template = readTemplate("ApiClient.mustache"); + assertNotNull(template); + assertTrue(template.contains("\"0\""), + "ApiClient.mustache should handle 'default' response with '0' key"); + } + + /** + * Test error types map building pattern + */ + @Test + public void testErrorTypesMapBuildingPattern() throws Exception { + String template = readTemplate("api.mustache"); + assertNotNull(template); + // Check pattern: localVarErrorTypes.put("code", new GenericType<...>) + assertTrue(template.contains("localVarErrorTypes.put"), + "api.mustache should build error types map using put"); + } + + /** + * Test backward compatibility - null is passed for errorTypes + */ + @Test + public void testBackwardCompatibility() throws Exception { + String template = readTemplate("ApiClient.mustache"); + assertNotNull(template); + // Check that null is passed for backward compatibility + assertTrue(template.contains(", null") || + template.contains("null,") || + template.contains("null/*"), + "Backwards compatibility: null should be passed for errorTypes"); + } + + /** + * 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)) { + // Try alternate path + templatePath = java.nio.file.Paths.get( + "modules/openapi-generator/" + JERSEY3_TEMPLATE_DIR + templateName); + } + if (java.nio.file.Files.exists(templatePath)) { + return java.nio.file.Files.readString(templatePath); + } + // Try classpath + try { + java.io.InputStream is = getClass().getClassLoader() + .getResourceAsStream(JERSEY3_TEMPLATE_DIR + templateName); + if (is != null) { + return new String(is.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8); + } + } catch (Exception ignored) {} + + return null; + } +} \ No newline at end of file diff --git a/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiClient.java index bbebf6553cd2..83834edcf4b2 100644 --- a/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiClient.java @@ -62,6 +62,7 @@ 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; import java.time.OffsetDateTime; @@ -974,6 +975,7 @@ public File prepareDownloadFile(Response response) throws IOException { * @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 */ @@ -990,7 +992,9 @@ public ApiResponse invokeAPI( String contentType, String[] authNames, GenericType returnType, - boolean isBodyNullable) + boolean isBodyNullable, + Map errorTypes + ) throws ApiException { String targetURL; @@ -1001,7 +1005,7 @@ public ApiResponse invokeAPI( 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())); } @@ -1088,6 +1092,8 @@ public ApiResponse invokeAPI( 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) { @@ -1095,7 +1101,7 @@ public ApiResponse invokeAPI( } } throw new ApiException( - response.getStatus(), message, buildResponseHeaders(response), respBody); + response.getStatus(), message, buildResponseHeaders(response), respBody, deserializeErrorEntity(errorTypes, response)); } } finally { try { @@ -1106,6 +1112,30 @@ public ApiResponse invokeAPI( } } } + + /** + * Deserialize the response body into an error entity based on HTTP status code. + * Looks up the error type from the errorTypes map using the response status code, + * or falls back to the "default" error type if no match is found. + * + * @param errorTypes Map of status code strings to GenericType for deserialization + * @param response The HTTP response + * @return The deserialized error entity, or null if not found or deserialization fails + */ + private Object deserializeErrorEntity(Map errorTypes, Response response) { + 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; @@ -1132,7 +1162,7 @@ protected Response sendRequest(String method, Invocation.Builder invocationBuild */ @Deprecated public ApiResponse invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String accept, String contentType, String[] authNames, GenericType 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*/); } /** diff --git a/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiException.java b/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiException.java index 21d1a3d7b956..a5a19aecfb97 100644 --- a/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiException.java +++ b/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/ApiException.java @@ -26,6 +26,7 @@ public class ApiException extends Exception { private int code = 0; private Map> responseHeaders = null; private String responseBody = null; + private transient Object errorEntity = null; public ApiException() {} @@ -67,6 +68,11 @@ public ApiException(int code, String message, Map> response this.responseBody = responseBody; } + public ApiException(int code, String message, Map> responseHeaders, String responseBody, Object errorEntity) { + this(code, message, responseHeaders, responseBody); + this.errorEntity = errorEntity; + } + /** * Get the HTTP status code. * @@ -93,4 +99,13 @@ public Map> getResponseHeaders() { public String getResponseBody() { return responseBody; } + + /** + * Get the deserialized error entity (or null if this error doesn't have a model associated). + * + * @return Deserialized error entity + */ + public Object getErrorEntity() { + return errorEntity; + } } diff --git a/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/api/DefaultApi.java b/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/api/DefaultApi.java index 77eee862c4d9..30e535d164ba 100644 --- a/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/api/DefaultApi.java +++ b/samples/client/petstore/java/jersey3-oneOf/src/main/java/org/openapitools/client/api/DefaultApi.java @@ -78,8 +78,9 @@ public void rootPost(@jakarta.annotation.Nullable PostRequest postRequest) throw public ApiResponse rootPostWithHttpInfo(@jakarta.annotation.Nullable PostRequest postRequest) throws ApiException { String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("DefaultApi.rootPost", "/", "POST", new ArrayList<>(), postRequest, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiClient.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiClient.java index 2d13159dbe2d..8d0deb2d886b 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiClient.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiClient.java @@ -63,6 +63,7 @@ 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; import java.time.OffsetDateTime; @@ -1197,6 +1198,7 @@ public File prepareDownloadFile(Response response) throws IOException { * @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 */ @@ -1213,7 +1215,9 @@ public ApiResponse invokeAPI( String contentType, String[] authNames, GenericType returnType, - boolean isBodyNullable) + boolean isBodyNullable, + Map errorTypes + ) throws ApiException { String targetURL; @@ -1224,7 +1228,7 @@ public ApiResponse invokeAPI( 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())); } @@ -1327,6 +1331,8 @@ public ApiResponse invokeAPI( 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) { @@ -1334,7 +1340,7 @@ public ApiResponse invokeAPI( } } throw new ApiException( - response.getStatus(), message, buildResponseHeaders(response), respBody); + response.getStatus(), message, buildResponseHeaders(response), respBody, deserializeErrorEntity(errorTypes, response)); } } finally { try { @@ -1345,6 +1351,30 @@ public ApiResponse invokeAPI( } } } + + /** + * Deserialize the response body into an error entity based on HTTP status code. + * Looks up the error type from the errorTypes map using the response status code, + * or falls back to the "default" error type if no match is found. + * + * @param errorTypes Map of status code strings to GenericType for deserialization + * @param response The HTTP response + * @return The deserialized error entity, or null if not found or deserialization fails + */ + private Object deserializeErrorEntity(Map errorTypes, Response response) { + 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; @@ -1371,7 +1401,7 @@ protected Response sendRequest(String method, Invocation.Builder invocationBuild */ @Deprecated public ApiResponse invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String accept, String contentType, String[] authNames, GenericType 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*/); } /** diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiException.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiException.java index 70d3b0f5a071..b2b258115f81 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiException.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/ApiException.java @@ -26,6 +26,7 @@ public class ApiException extends Exception { private int code = 0; private Map> responseHeaders = null; private String responseBody = null; + private transient Object errorEntity = null; public ApiException() {} @@ -67,6 +68,11 @@ public ApiException(int code, String message, Map> response this.responseBody = responseBody; } + public ApiException(int code, String message, Map> responseHeaders, String responseBody, Object errorEntity) { + this(code, message, responseHeaders, responseBody); + this.errorEntity = errorEntity; + } + /** * Get the HTTP status code. * @@ -93,4 +99,13 @@ public Map> getResponseHeaders() { public String getResponseBody() { return responseBody; } + + /** + * Get the deserialized error entity (or null if this error doesn't have a model associated). + * + * @return Deserialized error entity + */ + public Object getErrorEntity() { + return errorEntity; + } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/AnotherFakeApi.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/AnotherFakeApi.java index 315aa5a06d8c..18a0dc65779c 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/AnotherFakeApi.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/AnotherFakeApi.java @@ -87,9 +87,11 @@ public ApiResponse call123testSpecialTagsWithHttpInfo(@jakarta.annotatio String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("AnotherFakeApi.call123testSpecialTags", "/another-fake/dummy", "PATCH", new ArrayList<>(), client, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/DefaultApi.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/DefaultApi.java index 8e310f45b0ff..6368effa2aa8 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/DefaultApi.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/DefaultApi.java @@ -80,9 +80,11 @@ public FooGetDefaultResponse fooGet() throws ApiException { public ApiResponse fooGetWithHttpInfo() throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("0", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("DefaultApi.fooGet", "/foo", "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeApi.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeApi.java index 227bae0f78f2..bc7fc058ec1e 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeApi.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeApi.java @@ -90,10 +90,12 @@ public HealthCheckResult fakeHealthGet() throws ApiException { public ApiResponse fakeHealthGetWithHttpInfo() throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeApi.fakeHealthGet", "/fake/health", "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * @@ -128,10 +130,12 @@ public Boolean fakeOuterBooleanSerialize(@jakarta.annotation.Nullable Boolean bo public ApiResponse fakeOuterBooleanSerializeWithHttpInfo(@jakarta.annotation.Nullable Boolean body) throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("*/*"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeApi.fakeOuterBooleanSerialize", "/fake/outer/boolean", "POST", new ArrayList<>(), body, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * @@ -166,10 +170,12 @@ public OuterComposite fakeOuterCompositeSerialize(@jakarta.annotation.Nullable O public ApiResponse fakeOuterCompositeSerializeWithHttpInfo(@jakarta.annotation.Nullable OuterComposite outerComposite) throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("*/*"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeApi.fakeOuterCompositeSerialize", "/fake/outer/composite", "POST", new ArrayList<>(), outerComposite, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * @@ -204,10 +210,12 @@ public BigDecimal fakeOuterNumberSerialize(@jakarta.annotation.Nullable BigDecim public ApiResponse fakeOuterNumberSerializeWithHttpInfo(@jakarta.annotation.Nullable BigDecimal body) throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("*/*"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeApi.fakeOuterNumberSerialize", "/fake/outer/number", "POST", new ArrayList<>(), body, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * @@ -242,10 +250,12 @@ public String fakeOuterStringSerialize(@jakarta.annotation.Nullable String body) public ApiResponse fakeOuterStringSerializeWithHttpInfo(@jakarta.annotation.Nullable String body) throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("*/*"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeApi.fakeOuterStringSerialize", "/fake/outer/string", "POST", new ArrayList<>(), body, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * Array of Enums @@ -278,10 +288,12 @@ public List getArrayOfEnums() throws ApiException { public ApiResponse> getArrayOfEnumsWithHttpInfo() throws ApiException { String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType>() {}); GenericType> localVarReturnType = new GenericType>() {}; return apiClient.invokeAPI("FakeApi.getArrayOfEnums", "/fake/array-of-enums", "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * Array of string @@ -315,9 +327,10 @@ public void postArrayOfString(@jakarta.annotation.Nullable List<@Pattern(regexp public ApiResponse postArrayOfStringWithHttpInfo(@jakarta.annotation.Nullable List<@Pattern(regexp = "[A-Z0-9]+")String> requestBody) throws ApiException { String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.postArrayOfString", "/fake/request-array-string", "POST", new ArrayList<>(), requestBody, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * test referenced additionalProperties @@ -356,9 +369,10 @@ public ApiResponse testAdditionalPropertiesReferenceWithHttpInfo(@jakarta. String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testAdditionalPropertiesReference", "/fake/additionalProperties-reference", "POST", new ArrayList<>(), requestBody, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * @@ -397,9 +411,10 @@ public ApiResponse testBodyWithFileSchemaWithHttpInfo(@jakarta.annotation. String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testBodyWithFileSchema", "/fake/body-with-file-schema", "PUT", new ArrayList<>(), fileSchemaTestClass, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * @@ -448,9 +463,10 @@ public ApiResponse testBodyWithQueryParamsWithHttpInfo(@jakarta.annotation String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testBodyWithQueryParams", "/fake/body-with-query-params", "PUT", localVarQueryParams, user, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * To test \"client\" model @@ -490,10 +506,12 @@ public ApiResponse testClientModelWithHttpInfo(@jakarta.annotation.Nonnu String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeApi.testClientModel", "/fake", "PATCH", new ArrayList<>(), client, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 @@ -607,9 +625,10 @@ public ApiResponse testEndpointParametersWithHttpInfo(@jakarta.annotation. String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/x-www-form-urlencoded"); String[] localVarAuthNames = new String[] {"http_basic_test"}; + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testEndpointParameters", "/fake", "POST", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarFormParams, localVarAccept, localVarContentType, - localVarAuthNames, null, false); + localVarAuthNames, null, false, localVarErrorTypes); } /** * To test enum parameters @@ -685,9 +704,10 @@ public ApiResponse testEnumParametersWithHttpInfo(@jakarta.annotation.Null String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/x-www-form-urlencoded"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testEnumParameters", "/fake", "GET", localVarQueryParams, null, localVarHeaderParams, new LinkedHashMap<>(), localVarFormParams, localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } private ApiResponse testGroupParametersWithHttpInfo(@jakarta.annotation.Nonnull Integer requiredStringGroup, @jakarta.annotation.Nonnull Boolean requiredBooleanGroup, @jakarta.annotation.Nonnull Long requiredInt64Group, @jakarta.annotation.Nullable Integer stringGroup, @jakarta.annotation.Nullable Boolean booleanGroup, @jakarta.annotation.Nullable Long int64Group) throws ApiException { @@ -720,9 +740,10 @@ private ApiResponse testGroupParametersWithHttpInfo(@jakarta.annotation.No String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType(); String[] localVarAuthNames = new String[] {"bearer_test"}; + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testGroupParameters", "/fake", "DELETE", localVarQueryParams, null, localVarHeaderParams, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, null, false); + localVarAuthNames, null, false, localVarErrorTypes); } public class APItestGroupParametersRequest { @@ -884,9 +905,10 @@ public ApiResponse testInlineAdditionalPropertiesWithHttpInfo(@jakarta.ann String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testInlineAdditionalProperties", "/fake/inline-additionalProperties", "POST", new ArrayList<>(), requestBody, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * test inline free-form additionalProperties @@ -925,9 +947,10 @@ public ApiResponse testInlineFreeformAdditionalPropertiesWithHttpInfo(@jak String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testInlineFreeformAdditionalProperties", "/fake/inline-freeform-additionalProperties", "POST", new ArrayList<>(), testInlineFreeformAdditionalPropertiesRequest, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * test json serialization of form data @@ -976,9 +999,10 @@ public ApiResponse testJsonFormDataWithHttpInfo(@jakarta.annotation.Nonnul String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/x-www-form-urlencoded"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testJsonFormData", "/fake/jsonFormData", "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarFormParams, localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * @@ -1046,9 +1070,10 @@ public ApiResponse testQueryParameterCollectionFormatWithHttpInfo(@jakarta String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testQueryParameterCollectionFormat", "/fake/test-query-parameters", "PUT", localVarQueryParams, null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * test referenced string map @@ -1087,8 +1112,9 @@ public ApiResponse testStringMapReferenceWithHttpInfo(@jakarta.annotation. String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("FakeApi.testStringMapReference", "/fake/stringMap-reference", "POST", new ArrayList<>(), requestBody, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeClassnameTags123Api.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeClassnameTags123Api.java index 215ee4d24166..652af53e598a 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeClassnameTags123Api.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/FakeClassnameTags123Api.java @@ -88,9 +88,11 @@ public ApiResponse testClassnameWithHttpInfo(@jakarta.annotation.Nonnull String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); String[] localVarAuthNames = new String[] {"api_key_query"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("FakeClassnameTags123Api.testClassname", "/fake_classname_test", "PATCH", new ArrayList<>(), client, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/PetApi.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/PetApi.java index 21eea42ee48b..767bb1b594df 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/PetApi.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/PetApi.java @@ -89,9 +89,10 @@ public ApiResponse addPetWithHttpInfo(@jakarta.annotation.Nonnull Pet pet) String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json", "application/xml"); String[] localVarAuthNames = new String[] {"petstore_auth", "http_signature_test"}; + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("PetApi.addPet", "/pet", "POST", new ArrayList<>(), pet, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, null, false); + localVarAuthNames, null, false, localVarErrorTypes); } /** * Deletes a pet @@ -143,9 +144,10 @@ public ApiResponse deletePetWithHttpInfo(@jakarta.annotation.Nonnull Long String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType(); String[] localVarAuthNames = new String[] {"petstore_auth"}; + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("PetApi.deletePet", localVarPath, "DELETE", new ArrayList<>(), null, localVarHeaderParams, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, null, false); + localVarAuthNames, null, false, localVarErrorTypes); } /** * Finds Pets by status @@ -193,10 +195,12 @@ public ApiResponse> findPetsByStatusWithHttpInfo(@jakarta.annotation.N String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType(); String[] localVarAuthNames = new String[] {"petstore_auth", "http_signature_test"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType>() {}); GenericType> localVarReturnType = new GenericType>() {}; return apiClient.invokeAPI("PetApi.findPetsByStatus", "/pet/findByStatus", "GET", localVarQueryParams, null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } /** * Finds Pets by tags @@ -248,10 +252,12 @@ public ApiResponse> findPetsByTagsWithHttpInfo(@jakarta.annotation.Non String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType(); String[] localVarAuthNames = new String[] {"petstore_auth", "http_signature_test"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType>() {}); GenericType> localVarReturnType = new GenericType>() {}; return apiClient.invokeAPI("PetApi.findPetsByTags", "/pet/findByTags", "GET", localVarQueryParams, null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } /** * Find pet by ID @@ -300,10 +306,12 @@ public ApiResponse getPetByIdWithHttpInfo(@jakarta.annotation.Nonnull Long String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType(); String[] localVarAuthNames = new String[] {"api_key"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("PetApi.getPetById", localVarPath, "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } /** * Update an existing pet @@ -347,9 +355,10 @@ public ApiResponse updatePetWithHttpInfo(@jakarta.annotation.Nonnull Pet p String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json", "application/xml"); String[] localVarAuthNames = new String[] {"petstore_auth", "http_signature_test"}; + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("PetApi.updatePet", "/pet", "PUT", new ArrayList<>(), pet, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, null, false); + localVarAuthNames, null, false, localVarErrorTypes); } /** * Updates a pet in the store with form data @@ -406,9 +415,10 @@ public ApiResponse updatePetWithFormWithHttpInfo(@jakarta.annotation.Nonnu String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/x-www-form-urlencoded"); String[] localVarAuthNames = new String[] {"petstore_auth"}; + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("PetApi.updatePetWithForm", localVarPath, "POST", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarFormParams, localVarAccept, localVarContentType, - localVarAuthNames, null, false); + localVarAuthNames, null, false, localVarErrorTypes); } /** * uploads an image @@ -466,10 +476,12 @@ public ApiResponse uploadFileWithHttpInfo(@jakarta.annotation. String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType("multipart/form-data"); String[] localVarAuthNames = new String[] {"petstore_auth"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("PetApi.uploadFile", localVarPath, "POST", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarFormParams, localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } /** * uploads an image (required) @@ -528,9 +540,11 @@ public ApiResponse uploadFileWithRequiredFileWithHttpInfo(@jak String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType("multipart/form-data"); String[] localVarAuthNames = new String[] {"petstore_auth"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("PetApi.uploadFileWithRequiredFile", localVarPath, "POST", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), localVarFormParams, localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/StoreApi.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/StoreApi.java index 696ee2619e0b..924bf649754e 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/StoreApi.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/StoreApi.java @@ -92,9 +92,10 @@ public ApiResponse deleteOrderWithHttpInfo(@jakarta.annotation.Nonnull Str String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("StoreApi.deleteOrder", localVarPath, "DELETE", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * Returns pet inventories by status @@ -128,10 +129,12 @@ public ApiResponse> getInventoryWithHttpInfo() throws ApiEx String localVarAccept = apiClient.selectHeaderAccept("application/json"); String localVarContentType = apiClient.selectHeaderContentType(); String[] localVarAuthNames = new String[] {"api_key"}; + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType>() {}); GenericType> localVarReturnType = new GenericType>() {}; return apiClient.invokeAPI("StoreApi.getInventory", "/store/inventory", "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - localVarAuthNames, localVarReturnType, false); + localVarAuthNames, localVarReturnType, false, localVarErrorTypes); } /** * Find purchase order by ID @@ -179,10 +182,12 @@ public ApiResponse getOrderByIdWithHttpInfo(@jakarta.annotation.Nonnull L String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("StoreApi.getOrderById", localVarPath, "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * Place an order for a pet @@ -224,9 +229,11 @@ public ApiResponse placeOrderWithHttpInfo(@jakarta.annotation.Nonnull Ord String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("StoreApi.placeOrder", "/store/order", "POST", new ArrayList<>(), order, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/UserApi.java b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/UserApi.java index e23d2cddac66..9694fec8ad08 100644 --- a/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/UserApi.java +++ b/samples/client/petstore/java/jersey3/src/main/java/org/openapitools/client/api/UserApi.java @@ -87,9 +87,10 @@ public ApiResponse createUserWithHttpInfo(@jakarta.annotation.Nonnull User String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("UserApi.createUser", "/user", "POST", new ArrayList<>(), user, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * Creates list of users with given input array @@ -128,9 +129,10 @@ public ApiResponse createUsersWithArrayInputWithHttpInfo(@jakarta.annotati String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("UserApi.createUsersWithArrayInput", "/user/createWithArray", "POST", new ArrayList<>(), user, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * Creates list of users with given input array @@ -169,9 +171,10 @@ public ApiResponse createUsersWithListInputWithHttpInfo(@jakarta.annotatio String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("UserApi.createUsersWithListInput", "/user/createWithList", "POST", new ArrayList<>(), user, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * Delete user @@ -216,9 +219,10 @@ public ApiResponse deleteUserWithHttpInfo(@jakarta.annotation.Nonnull Stri String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("UserApi.deleteUser", localVarPath, "DELETE", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * Get user by user name @@ -266,10 +270,12 @@ public ApiResponse getUserByNameWithHttpInfo(@jakarta.annotation.Nonnull S String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("UserApi.getUserByName", localVarPath, "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * Logs user into the system @@ -322,10 +328,12 @@ public ApiResponse loginUserWithHttpInfo(@jakarta.annotation.Nonnull Str String localVarAccept = apiClient.selectHeaderAccept("application/xml", "application/json"); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); + localVarErrorTypes.put("200", new GenericType() {}); GenericType localVarReturnType = new GenericType() {}; return apiClient.invokeAPI("UserApi.loginUser", "/user/login", "GET", localVarQueryParams, null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, localVarReturnType, false); + null, localVarReturnType, false, localVarErrorTypes); } /** * Logs out current logged in user session @@ -357,9 +365,10 @@ public void logoutUser() throws ApiException { public ApiResponse logoutUserWithHttpInfo() throws ApiException { String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType(); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("UserApi.logoutUser", "/user/logout", "GET", new ArrayList<>(), null, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } /** * Updated user @@ -409,8 +418,9 @@ public ApiResponse updateUserWithHttpInfo(@jakarta.annotation.Nonnull Stri String localVarAccept = apiClient.selectHeaderAccept(); String localVarContentType = apiClient.selectHeaderContentType("application/json"); + final Map localVarErrorTypes = new HashMap(); return apiClient.invokeAPI("UserApi.updateUser", localVarPath, "PUT", new ArrayList<>(), user, new LinkedHashMap<>(), new LinkedHashMap<>(), new LinkedHashMap<>(), localVarAccept, localVarContentType, - null, null, false); + null, null, false, localVarErrorTypes); } } diff --git a/samples/client/petstore/java/jersey3/src/test/java/org/openapitools/client/ErrorEntityIntegrationTest.java b/samples/client/petstore/java/jersey3/src/test/java/org/openapitools/client/ErrorEntityIntegrationTest.java new file mode 100644 index 000000000000..c3664007e4c7 --- /dev/null +++ b/samples/client/petstore/java/jersey3/src/test/java/org/openapitools/client/ErrorEntityIntegrationTest.java @@ -0,0 +1,150 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * Copyright 2018 SmartBear Software + * + * 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.client; + +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration test for errorEntity feature. + * + * This test verifies that the ApiException class with errorEntity + * works correctly without requiring a live server. + */ +public class ErrorEntityIntegrationTest { + + /** + * Test errorEntity is correctly populated in ApiException + */ + @Test + public void testErrorEntityIsCorrectlyPopulated() { + // Simulate error response from server + Map errorResponse = new HashMap<>(); + errorResponse.put("code", 400); + errorResponse.put("message", "Bad Request"); + errorResponse.put("details", List.of("Field 'name' is required")); + + // Create ApiException as if it came from a 400 response + Map> headers = new HashMap<>(); + headers.put("Content-Type", List.of("application/json")); + headers.put("X-Request-Id", List.of("abc-123")); + + String responseBody = "{\"code\":400,\"message\":\"Bad Request\",\"details\":[\"Field 'name' is required\"]}"; + + ApiException exception = new ApiException( + 400, + "Bad Request", + headers, + responseBody, + errorResponse + ); + + // Verify basic properties + assertEquals(400, exception.getCode()); + assertEquals("Bad Request", exception.getMessage()); + + // Verify headers are preserved + assertEquals("application/json", exception.getResponseHeaders().get("Content-Type").get(0)); + assertEquals("abc-123", exception.getResponseHeaders().get("X-Request-Id").get(0)); + + // Verify raw response body is preserved + assertEquals(responseBody, exception.getResponseBody()); + + // Verify errorEntity is correctly deserialized + assertNotNull(exception.getErrorEntity()); + assertTrue(exception.getErrorEntity() instanceof Map); + + Map errorEntity = (Map) exception.getErrorEntity(); + assertEquals(400, errorEntity.get("code")); + assertEquals("Bad Request", errorEntity.get("message")); + assertNotNull(errorEntity.get("details")); + } + + /** + * Test errorEntity is null when not provided (backward compatibility) + */ + @Test + public void testErrorEntityIsNullWhenNotProvided() { + Map> headers = new HashMap<>(); + + ApiException exception = new ApiException( + 500, + "Internal Server Error", + headers, + "Server error occurred" + // No errorEntity passed + ); + + assertEquals(500, exception.getCode()); + assertEquals("Internal Server Error", exception.getMessage()); + assertEquals("Server error occurred", exception.getResponseBody()); + assertNull(exception.getErrorEntity(), "errorEntity should be null when not provided"); + } + + /** + * Test errorEntity is null when deserialization fails + */ + @Test + public void testErrorEntityIsNullOnDeserializationFailure() { + Map> headers = new HashMap<>(); + + // Simulate case where deserialization failed and returned null + ApiException exception = new ApiException( + 500, + "Internal Server Error", + headers, + "invalid json{", + null // errorEntity is null because deserialization failed + ); + + assertEquals(500, exception.getCode()); + assertNull(exception.getErrorEntity(), "errorEntity should be null on deserialization failure"); + } + + /** + * Test that errorEntity can hold any type of object + */ + @Test + public void testErrorEntitySupportsAnyType() { + // Test with a custom error wrapper object structure + Map customError = new HashMap<>(); + Map innerError = new HashMap<>(); + innerError.put("code", "VALIDATION_ERROR"); + innerError.put("message", "Validation failed"); + innerError.put("fields", List.of("email", "password")); + customError.put("error", innerError); + + Map> headers = new HashMap<>(); + + ApiException exception = new ApiException( + 422, + "Validation Error", + headers, + "{}", + customError + ); + + assertNotNull(exception.getErrorEntity()); + assertTrue(exception.getErrorEntity() instanceof Map); + } +} \ No newline at end of file