diff --git a/README.md b/README.md
index 34bb4637b..b2a218874 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,9 @@ The project is very much Work In Progress and will be published on maven central
# Release Notes
BOAT is still under development and subject to change.
+## 0.17.10
+* Boat maven plugin
+ * Fix: When using Multipart, generate with `@RequestPart` instead of `@RequestParam`
## 0.17.9
* Boat Maven plugin
* Fix: [containerDefaultToNull=true is not backward compatible](https://github.com/Backbase/backbase-openapi-tools/issues/604)
diff --git a/boat-scaffold/pom.xml b/boat-scaffold/pom.xml
index 2d15fa43f..38e99542c 100644
--- a/boat-scaffold/pom.xml
+++ b/boat-scaffold/pom.xml
@@ -152,6 +152,13 @@
maven-resolver-transport-http
${maven.resolver.version}
+
+
+ com.github.javaparser
+ javaparser-core
+ 3.24.9
+ test
+
diff --git a/boat-scaffold/src/main/templates/boat-spring/formParams.mustache b/boat-scaffold/src/main/templates/boat-spring/formParams.mustache
index b0819f315..505e5909e 100644
--- a/boat-scaffold/src/main/templates/boat-spring/formParams.mustache
+++ b/boat-scaffold/src/main/templates/boat-spring/formParams.mustache
@@ -1 +1 @@
-{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#isArray}}List<{{/isArray}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{#isArray}}>{{/isArray}} {{paramName}}{{/isFile}}{{/isFormParam}}
\ No newline at end of file
+{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#isMultipart}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{>dateTimeParam}} {{{dataType}}} {{paramName}}{{/isMultipart}}{{^isMultipart}}{{#useBeanValidation}} @Valid{{/useBeanValidation}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{{dataType}}} {{paramName}}{{/isMultipart}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#isArray}}List<{{/isArray}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{#isArray}}>{{/isArray}} {{paramName}}{{/isFile}}{{/isFormParam}}
\ No newline at end of file
diff --git a/boat-scaffold/src/test/java/com/backbase/oss/codegen/java/BoatSpringCodeGenTests.java b/boat-scaffold/src/test/java/com/backbase/oss/codegen/java/BoatSpringCodeGenTests.java
index 1cf3b7bc3..730c92aa4 100644
--- a/boat-scaffold/src/test/java/com/backbase/oss/codegen/java/BoatSpringCodeGenTests.java
+++ b/boat-scaffold/src/test/java/com/backbase/oss/codegen/java/BoatSpringCodeGenTests.java
@@ -3,32 +3,48 @@
import static com.backbase.oss.codegen.java.BoatSpringCodeGen.USE_PROTECTED_FIELDS;
import static java.util.stream.Collectors.groupingBy;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
-import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.backbase.oss.codegen.java.BoatSpringCodeGen.NewLineIndent;
+import com.github.javaparser.StaticJavaParser;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.body.Parameter;
import com.samskivert.mustache.Template.Fragment;
import io.swagger.v3.oas.models.Operation;
+import io.swagger.parser.OpenAPIParser;
+import io.swagger.v3.parser.core.models.ParseOptions;
+import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
import java.util.Map;
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openapitools.codegen.CliOption;
-import org.openapitools.codegen.CodegenModel;
+import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenOperation;
-import org.openapitools.codegen.CodegenParameter;
-import org.openapitools.codegen.CodegenProperty;
-
+import org.openapitools.codegen.DefaultGenerator;
class BoatSpringCodeGenTests {
+ static final String PROP_BASE = BoatSpringCodeGenTests.class.getSimpleName() + ".";
+ static final String TEST_OUTPUT = System.getProperty(PROP_BASE + "output", "target/boat-spring-codegen-tests");
+
+ @BeforeAll
+ static void before() throws IOException {
+ Files.createDirectories(Paths.get(TEST_OUTPUT));
+ FileUtils.deleteDirectory(new File(TEST_OUTPUT, "src"));
+ }
+
@Test
void clientOptsUnicity() {
final BoatSpringCodeGen gen = new BoatSpringCodeGen();
@@ -74,4 +90,37 @@ void addServletRequestTestFromOperation(){
assertEquals("httpServletRequest", co.allParams.get(0).paramName);
assertTrue(Arrays.stream(co.allParams.get(0).getClass().getDeclaredFields()).anyMatch(f -> "isHttpServletRequest".equals(f.getName())));
}
+
+ @Test
+ void multipartWithFileAndObject() throws IOException {
+ var codegen = new BoatSpringCodeGen();
+ var input = new File("src/test/resources/boat-spring/multipart.yaml");
+ codegen.setLibrary("spring-boot");
+ codegen.setInterfaceOnly(true);
+ codegen.setOutputDir(TEST_OUTPUT + "/multipart");
+ codegen.setInputSpec(input.getAbsolutePath());
+
+ var openApiInput = new OpenAPIParser().readLocation(input.getAbsolutePath(), null, new ParseOptions()).getOpenAPI();
+ var clientOptInput = new ClientOptInput();
+ clientOptInput.config(codegen);
+ clientOptInput.openAPI(openApiInput);
+
+ List files = new DefaultGenerator().opts(clientOptInput).generate();
+
+ File testApi = files.stream().filter(file -> file.getName().equals("TestApi.java"))
+ .findFirst()
+ .get();
+ MethodDeclaration testPostMethod = StaticJavaParser.parse(testApi)
+ .findAll(MethodDeclaration.class)
+ .get(1);
+
+ Parameter filesParam = testPostMethod.getParameterByName("files").get();
+ Parameter contentParam = testPostMethod.getParameterByName("content").get();
+
+ assertTrue(filesParam.getAnnotationByName("RequestPart").isPresent());
+ assertTrue(contentParam.getAnnotationByName("RequestPart").isPresent());
+ assertThat(contentParam.getTypeAsString(), equalTo("TestObjectPart"));
+ assertThat(filesParam.getTypeAsString(), equalTo("List"));
+ }
+
}
diff --git a/boat-scaffold/src/test/resources/boat-spring/multipart.yaml b/boat-scaffold/src/test/resources/boat-spring/multipart.yaml
new file mode 100644
index 000000000..f51f70d20
--- /dev/null
+++ b/boat-scaffold/src/test/resources/boat-spring/multipart.yaml
@@ -0,0 +1,39 @@
+openapi: 3.0.2
+info:
+ version: 1.0.0
+ title: test
+
+paths:
+ /test:
+ post:
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ required:
+ - files
+ - content
+ properties:
+ files:
+ type: array
+ items:
+ type: string
+ format: binary
+ content:
+ $ref: "#/components/schemas/testObjectPart"
+ responses:
+ 200:
+ description: OK
+
+components:
+ schemas:
+ testObjectPart:
+ type: object
+ required:
+ - foo
+ properties:
+ foo:
+ type: string
+ bar:
+ type: number
\ No newline at end of file