diff --git a/docs/generators/jaxrs-cxf-client.md b/docs/generators/jaxrs-cxf-client.md index 5f7d804345f..ee6f46499da 100644 --- a/docs/generators/jaxrs-cxf-client.md +++ b/docs/generators/jaxrs-cxf-client.md @@ -65,6 +65,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |sourceFolder|source folder for generated code| |src/gen/java| |testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi| +|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk.| |false| |useBeanValidation|Use BeanValidation API annotations| |false| |useGenericResponse|Use generic response| |false| |useGzipFeatureForTests|Use Gzip Feature for tests| |false| diff --git a/docs/generators/jaxrs-cxf-extended.md b/docs/generators/jaxrs-cxf-extended.md index 1e6553ff5c1..88bad1716bc 100644 --- a/docs/generators/jaxrs-cxf-extended.md +++ b/docs/generators/jaxrs-cxf-extended.md @@ -78,6 +78,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |testDataFile|JSON file to contain generated test data| |null| |testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi| |title|a title describing the application| |OpenAPI Server| +|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk.| |false| |useAnnotatedBasePath|Use @Path annotations for basePath| |false| |useBeanValidation|Use BeanValidation API annotations| |true| |useBeanValidationFeature|Use BeanValidation Feature| |false| diff --git a/docs/generators/jaxrs-cxf.md b/docs/generators/jaxrs-cxf.md index 47d0ec6e8db..414843f9b37 100644 --- a/docs/generators/jaxrs-cxf.md +++ b/docs/generators/jaxrs-cxf.md @@ -73,6 +73,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |sourceFolder|source folder for generated code| |src/gen/java| |testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi| |title|a title describing the application| |OpenAPI Server| +|useAbstractionForFiles|Use alternative types instead of java.io.File to allow passing bytes without a file on disk.| |false| |useAnnotatedBasePath|Use @Path annotations for basePath| |false| |useBeanValidation|Use BeanValidation API annotations| |true| |useBeanValidationFeature|Use BeanValidation Feature| |false| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFClientCodegen.java index e83224d9995..032668cee00 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFClientCodegen.java @@ -43,6 +43,8 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen */ protected static final String JAXRS_TEMPLATE_DIRECTORY_NAME = "JavaJaxRS"; + public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles"; + protected boolean useBeanValidation = false; protected boolean useGenericResponse = false; @@ -53,6 +55,8 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen private boolean useJackson = false; + protected boolean useAbstractionForFiles = false; + public JavaCXFClientCodegen() { super(); @@ -90,6 +94,7 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen cliOptions.add(CliOption.newBoolean(USE_GZIP_FEATURE_FOR_TESTS, "Use Gzip Feature for tests")); cliOptions.add(CliOption.newBoolean(USE_LOGGING_FEATURE_FOR_TESTS, "Use Logging Feature for tests")); cliOptions.add(CliOption.newBoolean(USE_GENERIC_RESPONSE, "Use generic response")); + cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk.")); } @Override @@ -116,6 +121,10 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen useJackson = convertPropertyToBooleanAndWriteBack(JACKSON); } + if (additionalProperties.containsKey(USE_ABSTRACTION_FOR_FILES)) { + this.setUseAbstractionForFiles(convertPropertyToBooleanAndWriteBack(USE_ABSTRACTION_FOR_FILES)); + } + supportingFiles.clear(); // Don't need extra files provided by AbstractJAX-RS & Java Codegen supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml") @@ -218,4 +227,8 @@ public class JavaCXFClientCodegen extends AbstractJavaCodegen public boolean isUseJackson() { return useJackson; } + + public void setUseAbstractionForFiles(boolean useAbstractionForFiles) { + this.useAbstractionForFiles = useAbstractionForFiles; + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFServerCodegen.java index 54c1c0e6c0b..0bd87011cb1 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaCXFServerCodegen.java @@ -36,6 +36,8 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen implements CXFServerFeatures, GzipTestFeatures, LoggingTestFeatures, UseGenericResponseFeatures { private final Logger LOGGER = LoggerFactory.getLogger(JavaCXFServerCodegen.class); + public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles"; + protected boolean addConsumesProducesJson = true; protected boolean generateSpringApplication = false; @@ -70,6 +72,8 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen protected boolean useGenericResponse = false; + protected boolean useAbstractionForFiles = false; + public JavaCXFServerCodegen() { super(); @@ -126,6 +130,7 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen cliOptions.add(CliOption.newBoolean(GENERATE_NON_SPRING_APPLICATION, "Generate non-Spring application")); cliOptions.add(CliOption.newBoolean(USE_GENERIC_RESPONSE, "Use generic response")); + cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk.")); } @@ -184,6 +189,10 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen this.setGenerateNonSpringApplication(generateNonSpringApplication); } + if (additionalProperties.containsKey(USE_ABSTRACTION_FOR_FILES)) { + this.setUseAbstractionForFiles(convertPropertyToBooleanAndWriteBack(USE_ABSTRACTION_FOR_FILES)); + } + supportingFiles.clear(); // Don't need extra files provided by AbstractJAX-RS & Java Codegen supportingFiles.add(new SupportingFile("server/pom.mustache", "", "pom.xml") @@ -332,6 +341,10 @@ public class JavaCXFServerCodegen extends AbstractJavaJAXRSServerCodegen this.useGenericResponse = useGenericResponse; } + public void setUseAbstractionForFiles(boolean useAbstractionForFiles) { + this.useAbstractionForFiles = useAbstractionForFiles; + } + @Override protected void updateModelForObject(CodegenModel m, Schema schema) { /** diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api.mustache index b628097f588..40dbce32d8f 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api.mustache @@ -69,7 +69,7 @@ public interface {{classname}} { }) {{/implicitHeadersParams.0}} @ApiResponses(value = { {{#responses}} - @ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, response = {{{baseType}}}.class{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{^-last}},{{/-last}}{{/responses}} }) + @ApiResponse(code = {{{code}}}, message = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, response = {{#isFile}}{{#useAbstractionForFiles}}InputStream{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{baseType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{baseType}}}{{/isFile}}.class{{#containerType}}, responseContainer = "{{{.}}}"{{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{^-last}},{{/-last}}{{/responses}} }) public {{>returnTypes}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}}); {{/operation}} } diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api_test.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api_test.mustache index ce0d3517a1e..1b2c3fc1b23 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api_test.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/api_test.mustache @@ -113,7 +113,7 @@ public class {{classname}}Test { @Test public void {{operationId}}Test() { {{#allParams}} - {{^isFile}}{{{dataType}}} {{paramName}} = null;{{/isFile}}{{#isFile}}org.apache.cxf.jaxrs.ext.multipart.Attachment {{paramName}} = null;{{/isFile}} + {{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}} {{paramName}} = null;{{/isFile}}{{^isFile}}{{{dataType}}} {{paramName}} = null;{{/isFile}} {{/allParams}} //{{^vendorExtensions.x-java-is-response-void}}{{>returnTypes}} response = {{/vendorExtensions.x-java-is-response-void}}api.{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); {{^vendorExtensions.x-java-is-response-void}}//assertNotNull(response);{{/vendorExtensions.x-java-is-response-void}} diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParams.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParams.mustache index f938cb5b6be..ced2fd398f1 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParams.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParams.mustache @@ -1 +1 @@ -{{#isBodyParam}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file +{{#isBodyParam}}{{#useBeanValidation}}@Valid {{#required}}{{^isNullable}}@NotNull {{/isNullable}}{{/required}}{{/useBeanValidation}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParamsImpl.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParamsImpl.mustache index c7d1abfe527..24e0ce8c4f4 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParamsImpl.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/bodyParamsImpl.mustache @@ -1 +1 @@ -{{#isBodyParam}}{{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file +{{#isBodyParam}}{{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/returnTypes.mustache b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/returnTypes.mustache index 32f96a90472..9c668cd9908 100644 --- a/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/returnTypes.mustache +++ b/modules/openapi-generator/src/main/resources/JavaJaxRS/cxf/returnTypes.mustache @@ -1,4 +1,4 @@ {{#useGenericResponse}}Response{{/useGenericResponse}}{{! non-generic response: }}{{^useGenericResponse}}{{! -}}{{{returnType}}}{{! +}}{{#isResponseFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection{{/collectionFormat}}{{^collectionFormat}}InputStream{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{returnType}}}{{/useAbstractionForFiles}}{{/isResponseFile}}{{^isResponseFile}}{{{returnType}}}{{/isResponseFile}}{{! }}{{/useGenericResponse}} \ No newline at end of file diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaCXFClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaCXFClientCodegenTest.java index b2e7cf66993..0f1b2315f2a 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaCXFClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaCXFClientCodegenTest.java @@ -23,6 +23,7 @@ import io.swagger.v3.oas.models.media.*; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; import org.openapitools.codegen.*; +import org.openapitools.codegen.config.CodegenConfigurator; import org.openapitools.codegen.languages.AbstractJavaCodegen; import org.openapitools.codegen.languages.JavaCXFClientCodegen; import org.openapitools.codegen.languages.features.BeanValidationFeatures; @@ -34,10 +35,18 @@ import org.openapitools.codegen.model.OperationsMap; import org.testng.Assert; import org.testng.annotations.Test; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; +import static org.openapitools.codegen.TestUtils.validateJavaSourceFiles; + public class JavaCXFClientCodegenTest { @Test @@ -299,4 +308,41 @@ public class JavaCXFClientCodegenTest { Assert.assertEquals(codegen.additionalProperties().get(AbstractJavaCodegen.JACKSON), Boolean.TRUE); Assert.assertTrue(codegen.isUseJackson()); } + + @Test + public void testUseAbstractionForFiles() throws Exception { + + Map properties = new HashMap<>(); + properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api"); + properties.put(CodegenConstants.MODEL_PACKAGE, "xyz.abcdef.api"); + + properties.put(JavaCXFClientCodegen.USE_ABSTRACTION_FOR_FILES, true); + + + File output = Files.createTempDirectory("test").toFile(); + output.deleteOnExit(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName("jaxrs-cxf-client") + .setAdditionalProperties(properties) + .setInputSpec("src/test/resources/3_0/issue8792.yaml") + .setOutputDir(output.getAbsolutePath().replace("\\", "/")); + + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(configurator.toClientOptInput()).generate(); + files.forEach(File::deleteOnExit); + + validateJavaSourceFiles(files); + + Path defaultApi = Paths.get(output + "/src/gen/java/xyz/abcdef/api/DefaultApi.java"); + TestUtils.assertFileContains(defaultApi, + //get file + "@ApiResponse(code = 200, message = \"File content\", response = InputStream.class)", + "public InputStream filesIdGet(@PathParam(\"id\") String id);", + + //upload + "public FilesUploadPost200Response filesUploadPost(InputStream body);" + ); + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/issue8792.yaml b/modules/openapi-generator/src/test/resources/3_0/issue8792.yaml new file mode 100644 index 00000000000..71056d9391f --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/issue8792.yaml @@ -0,0 +1,52 @@ +openapi: 3.0.0 +info: + title: test useAbstractionForFiles for jaxrs-cxf + version: 0.0.1 +servers: + - url: "http://localhost" +paths: + /files/{id}: + get: + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + 200: + description: File content + content: + application/octet-stream: + schema: + type: string + format: binary + 500: + description: error message + content: + application/json: + schema: + type: object + properties: + errormsg: + type: string + /files/upload: + post: + requestBody: + required: true + description: The file content to upload + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + 200: + description: id + content: + application/json: + schema: + type: object + properties: + id: + type: string