Skip to content

Commit 3c62cc4

Browse files
authored
Fix multi-part binary form parameters for jaxrs-jersey templates (#7363)
* Fix [jaxrs-jersey][java][jersey] multipart/form-data file array issue on generating jaxrs-jersey. This commit aims to fix #7330 with described solution 'choice C'. * add test code [jaxrs-jersey][java][jersey] for multipart/form-data file on generating * update test code [jaxrs-jersey][java][jersey] for multipart/form-data file on generating followed latest master branch of OpenAPITools/openapi-generator * update samples/* by executing ./bin/generate-samples.sh * update mustaches for JavaJaxxRS/libraries/jersey1/* and samples/* to resolve failure of CI test on PR.
1 parent c0e36b3 commit 3c62cc4

File tree

121 files changed

+389
-656
lines changed

Some content is hidden

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

121 files changed

+389
-656
lines changed

modules/openapi-generator/src/main/resources/JavaJaxRS/api.mustache

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {{package}}.NotFoundException;
1616

1717
import java.io.InputStream;
1818

19-
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
2019
import org.glassfish.jersey.media.multipart.FormDataParam;
20+
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
2121

2222
import javax.servlet.ServletConfig;
2323
import javax.ws.rs.core.Context;
@@ -76,7 +76,7 @@ public class {{classname}} {
7676
{{/hasMore}}{{/responses}} })
7777
public Response {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},{{/allParams}}@Context SecurityContext securityContext)
7878
throws NotFoundException {
79-
return delegate.{{nickname}}({{#allParams}}{{#isFormParam}}{{#isFile}}{{paramName}}InputStream, {{paramName}}Detail{{/isFile}}{{/isFormParam}}{{^isFile}}{{paramName}}{{/isFile}}{{^isFormParam}}{{#isFile}}{{paramName}}{{/isFile}}{{/isFormParam}}, {{/allParams}}securityContext);
79+
return delegate.{{nickname}}({{#allParams}}{{#isFormParam}}{{#isFile}}{{paramName}}Bodypart{{/isFile}}{{/isFormParam}}{{^isFile}}{{paramName}}{{/isFile}}{{^isFormParam}}{{#isFile}}{{paramName}}{{/isFile}}{{/isFormParam}}, {{/allParams}}securityContext);
8080
}
8181
{{/operation}}
8282
}

modules/openapi-generator/src/main/resources/JavaJaxRS/apiService.mustache

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package {{package}};
33
import {{package}}.*;
44
import {{modelPackage}}.*;
55

6-
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
6+
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
77

88
{{#imports}}import {{import}};
99
{{/imports}}

modules/openapi-generator/src/main/resources/JavaJaxRS/apiServiceImpl.mustache

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {{package}}.NotFoundException;
1111

1212
import java.io.InputStream;
1313

14-
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
14+
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
1515

1616
import javax.ws.rs.core.Response;
1717
import javax.ws.rs.core.SecurityContext;
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
{{#isFormParam}}{{^isFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/isFile}}{{#isFile}}
2-
@FormDataParam("{{baseName}}") InputStream {{paramName}}InputStream,
3-
@FormDataParam("{{baseName}}") FormDataContentDisposition {{paramName}}Detail{{/isFile}}{{/isFormParam}}
2+
{{^isListContainer}} @FormDataParam("{{baseName}}") FormDataBodyPart {{paramName}}Bodypart {{/isListContainer}}{{#isListContainer}} @FormDataParam("{{baseName}}") List<FormDataBodyPart> {{paramName}}Bodypart {{/isListContainer}}{{/isFile}}{{/isFormParam}}

modules/openapi-generator/src/main/resources/JavaJaxRS/libraries/jersey1/api.mustache

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {{package}}.NotFoundException;
1616

1717
import java.io.InputStream;
1818

19-
import com.sun.jersey.core.header.FormDataContentDisposition;
2019
import com.sun.jersey.multipart.FormDataParam;
20+
import com.sun.jersey.multipart.FormDataBodyPart;
2121

2222
import javax.ws.rs.core.Context;
2323
import javax.ws.rs.core.Response;
@@ -55,7 +55,7 @@ public class {{classname}} {
5555
{{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},
5656
{{/allParams}}@Context SecurityContext securityContext)
5757
throws NotFoundException {
58-
return delegate.{{nickname}}({{#allParams}}{{#isFile}}inputStream, fileDetail{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}},{{/allParams}}securityContext);
58+
return delegate.{{nickname}}({{#allParams}}{{#isFile}}{{paramName}}Bodypart{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}},{{/allParams}}securityContext);
5959
}
6060
{{/operation}}
6161
}

modules/openapi-generator/src/main/resources/JavaJaxRS/libraries/jersey1/apiService.mustache

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import {{package}}.NotFoundException;
1313

1414
import java.io.InputStream;
1515

16-
import com.sun.jersey.core.header.FormDataContentDisposition;
1716
import com.sun.jersey.multipart.FormDataParam;
17+
import com.sun.jersey.multipart.FormDataBodyPart;
1818

1919
import javax.ws.rs.core.Response;
2020
import javax.ws.rs.core.SecurityContext;

modules/openapi-generator/src/main/resources/JavaJaxRS/libraries/jersey1/apiServiceImpl.mustache

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import {{package}}.NotFoundException;
1313

1414
import java.io.InputStream;
1515

16-
import com.sun.jersey.core.header.FormDataContentDisposition;
1716
import com.sun.jersey.multipart.FormDataParam;
17+
import com.sun.jersey.multipart.FormDataBodyPart;
1818

1919
import javax.ws.rs.core.Response;
2020
import javax.ws.rs.core.SecurityContext;
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
{{#isFormParam}}{{^isFile}}{{^vendorExtensions.x-multipart}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/vendorExtensions.x-multipart}}{{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/isFile}}{{#isFile}}@FormDataParam("{{baseName}}") InputStream inputStream,
2-
@FormDataParam("{{baseName}}") FormDataContentDisposition fileDetail{{/isFile}}{{/isFormParam}}
1+
{{#isFormParam}}{{^isFile}}{{^vendorExtensions.x-multipart}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/vendorExtensions.x-multipart}}{{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/isFile}}{{#isFile}}{{^isListContainer}}@FormDataParam("{{baseName}}") FormDataBodyPart {{paramName}}Bodypart{{/isListContainer}}{{#isListContainer}}@FormDataParam("{{baseName}}") List<FormDataBodyPart> {{paramName}}Bodypart{{/isListContainer}}{{/isFile}}{{/isFormParam}}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#isFormParam}}{{^isFile}}{{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}}InputStream {{paramName}}InputStream, FormDataContentDisposition {{paramName}}Detail{{/isFile}}{{/isFormParam}}
1+
{{#isFormParam}}{{^isFile}}{{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}}{{^isListContainer}}FormDataBodyPart {{paramName}}Bodypart{{/isListContainer}}{{#isListContainer}}List<FormDataBodyPart> {{paramName}}Bodypart{{/isListContainer}}{{/isFile}}{{/isFormParam}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJerseyServerCodegenTest.java

+55
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
11
package org.openapitools.codegen.java.jaxrs;
22

3+
import io.swagger.parser.OpenAPIParser;
34
import io.swagger.v3.oas.models.OpenAPI;
45
import io.swagger.v3.oas.models.servers.Server;
6+
import io.swagger.v3.oas.models.Operation;
7+
import io.swagger.v3.oas.models.info.Info;
8+
import io.swagger.v3.oas.models.media.Schema;
9+
import io.swagger.v3.parser.core.models.ParseOptions;
10+
511
import org.openapitools.codegen.ClientOptInput;
612
import org.openapitools.codegen.CodegenConstants;
713
import org.openapitools.codegen.CodegenOperation;
14+
import org.openapitools.codegen.DefaultCodegen;
815
import org.openapitools.codegen.MockDefaultGenerator;
916
import org.openapitools.codegen.MockDefaultGenerator.WrittenTemplateBasedFile;
1017
import org.openapitools.codegen.TestUtils;
1118
import org.openapitools.codegen.languages.JavaJerseyServerCodegen;
19+
import org.openapitools.codegen.languages.features.CXFServerFeatures;
1220
import org.openapitools.codegen.templating.MustacheEngineAdapter;
21+
import org.openapitools.codegen.DefaultGenerator;
1322
import org.testng.Assert;
1423
import org.testng.annotations.BeforeMethod;
1524
import org.testng.annotations.Test;
1625

26+
import static org.openapitools.codegen.TestUtils.assertFileContains;
27+
1728
import java.io.File;
29+
import java.io.IOException;
1830
import java.nio.file.Files;
1931
import java.util.List;
2032
import java.util.Map;
33+
import java.util.stream.Collectors;
2134

2235
public class JavaJerseyServerCodegenTest extends JavaJaxrsBaseTest {
2336

@@ -87,4 +100,46 @@ public void testAdditionalPropertiesPutForConfigValues() throws Exception {
87100
Assert.assertEquals(codegen.additionalProperties().get(JavaJerseyServerCodegen.SERVER_PORT), "8088");
88101
}
89102

103+
// Helper function, intended to reduce boilerplate @ copied from ../spring/SpringCodegenTest.java
104+
private Map<String, File> generateFiles(DefaultCodegen codegen, String filePath) throws IOException {
105+
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
106+
output.deleteOnExit();
107+
final String outputPath = output.getAbsolutePath().replace('\\', '/');
108+
109+
codegen.setOutputDir(output.getAbsolutePath());
110+
codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true");
111+
112+
final ClientOptInput input = new ClientOptInput();
113+
final OpenAPI openAPI = new OpenAPIParser().readLocation(filePath, null, new ParseOptions()).getOpenAPI();
114+
input.openAPI(openAPI);
115+
input.config(codegen);
116+
117+
final DefaultGenerator generator = new DefaultGenerator();
118+
List<File> files = generator.opts(input).generate();
119+
120+
return files.stream().collect(Collectors.toMap(e -> e.getName().replace(outputPath, ""), i -> i));
121+
}
122+
123+
// almost same test as issue #3139 on Spring
124+
@Test
125+
public void testMultipartJerseyServer() throws Exception {
126+
127+
final Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/form-multipart-binary-array.yaml");
128+
129+
// Check files for Single, Mixed
130+
String[] fileS = new String[] {
131+
"MultipartSingleApi.java", "MultipartSingleApiService.java", "MultipartSingleApiServiceImpl.java",
132+
"MultipartMixedApi.java", "MultipartMixedApiService.java", "MultipartMixedApiServiceImpl.java" };
133+
for (String f : fileS){
134+
assertFileContains( files.get(f).toPath(), "FormDataBodyPart file" );
135+
}
136+
137+
// Check files for Array
138+
final String[] fileA = new String[] { "MultipartArrayApiService.java", "MultipartArrayApi.java", "MultipartArrayApiServiceImpl.java"};
139+
for (String f : fileA) {
140+
assertFileContains( files.get(f).toPath(), "List<FormDataBodyPart> files");
141+
}
142+
143+
}
144+
90145
}

samples/server/petstore/jaxrs-datelib-j8/src/gen/java/org/openapitools/api/AnotherFakeApi.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
import java.io.InputStream;
1717

18-
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
1918
import org.glassfish.jersey.media.multipart.FormDataParam;
19+
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
2020

2121
import javax.servlet.ServletConfig;
2222
import javax.ws.rs.core.Context;
@@ -62,8 +62,7 @@ public AnotherFakeApi(@Context ServletConfig servletContext) {
6262
@io.swagger.annotations.ApiOperation(value = "To test special tags", notes = "To test special tags and operation ID starting with number", response = Client.class, tags={ "$another-fake?", })
6363
@io.swagger.annotations.ApiResponses(value = {
6464
@io.swagger.annotations.ApiResponse(code = 200, message = "successful operation", response = Client.class) })
65-
public Response call123testSpecialTags(@ApiParam(value = "client model", required = true) @NotNull @Valid Client body
66-
,@Context SecurityContext securityContext)
65+
public Response call123testSpecialTags(@ApiParam(value = "client model", required = true) @NotNull @Valid Client body,@Context SecurityContext securityContext)
6766
throws NotFoundException {
6867
return delegate.call123testSpecialTags(body, securityContext);
6968
}

samples/server/petstore/jaxrs-datelib-j8/src/gen/java/org/openapitools/api/AnotherFakeApiService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import org.openapitools.api.*;
44
import org.openapitools.model.*;
55

6-
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
6+
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
77

88
import org.openapitools.model.Client;
99

0 commit comments

Comments
 (0)