diff --git a/README.md b/README.md
index b8c13a1b0..1af0bd330 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,14 @@ 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.14.4
+
+* *Boat Marina*
+ * Added a now BOAT Scaffold template called Marina, as that is where the models hang out. The Boat Marina template outputs a single JSON file that is used to offer a rich user interface built from the specs including search, page per operation and many more features!
+
+* *Maven Plugin*
+ * The boat:doc goal now recursively search OpenAPI specs in a directory to generate docs for each found spec.
+
## 0.14.3
* *Maven Plugin*
diff --git a/boat-engine/pom.xml b/boat-engine/pom.xml
index 26e01e723..7b72c7e2b 100644
--- a/boat-engine/pom.xml
+++ b/boat-engine/pom.xml
@@ -5,7 +5,7 @@
com.backbase.oss
backbase-openapi-tools
- 0.14.3
+ 0.14.4-SNAPSHOT
boat-engine
jar
diff --git a/boat-engine/src/main/java/com/backbase/oss/boat/XmlSchemaToOpenApi.java b/boat-engine/src/main/java/com/backbase/oss/boat/XmlSchemaToOpenApi.java
index 8dbf6bde5..e3aee360b 100644
--- a/boat-engine/src/main/java/com/backbase/oss/boat/XmlSchemaToOpenApi.java
+++ b/boat-engine/src/main/java/com/backbase/oss/boat/XmlSchemaToOpenApi.java
@@ -21,7 +21,7 @@
import java.nio.charset.StandardCharsets;
@Log
-@SuppressWarnings({"java:S3740", "rawtypes"})
+@SuppressWarnings({"java:S3740", "rawtypes", "java:S2755"})
public class XmlSchemaToOpenApi {
public static final String NAME = "name";
public static final String TYPE = "type";
diff --git a/boat-engine/src/main/java/com/backbase/oss/boat/transformers/bundler/ExamplesProcessor.java b/boat-engine/src/main/java/com/backbase/oss/boat/transformers/bundler/ExamplesProcessor.java
index 6c0e9bd49..98b8a4708 100644
--- a/boat-engine/src/main/java/com/backbase/oss/boat/transformers/bundler/ExamplesProcessor.java
+++ b/boat-engine/src/main/java/com/backbase/oss/boat/transformers/bundler/ExamplesProcessor.java
@@ -253,7 +253,7 @@ private void dereferenceExample(ExampleHolder exampleHolder) {
private Object convertExampleContent(ExampleHolder exampleHolder, String refPath) {
try {
if (exampleHolder.getRef().endsWith("json") || refPath.endsWith("json")) {
- return Json.mapper().readValue(exampleHolder.getContent(), Object.class);
+ return Json.mapper().readValue(exampleHolder.getContent(), JsonNode.class);
}
return exampleHolder.getContent();
} catch (JsonProcessingException | RuntimeException e) {
diff --git a/boat-maven-plugin/README.md b/boat-maven-plugin/README.md
index baa931737..0e340c274 100644
--- a/boat-maven-plugin/README.md
+++ b/boat-maven-plugin/README.md
@@ -23,6 +23,8 @@ defined on openapi-generator-maven-plugin can be applied here too.
Boat maven plugin uses slightly modified templates for html, java and webclient that help generate specs and clients that work best in a Backbase projects.
+All inputSpec parameters for this goal may additionally be configured as an artifact. See [Example inputMavenArtifact parameter](#example-inputMavenArtifact-parameter) or [integration tests](https://github.com/Backbase/backbase-openapi-tools/tree/main/boat-maven-plugin/src/it/example/boat-artifact-input) for examples.
+
## boat:generate-spring-boot-embedded
Same with `generate` but with opinionated defaults for Spring
@@ -152,7 +154,11 @@ Available parameters:
inputSpec
Required: true
Input spec directory or file.
-
+ Optionaly inputMavenArtifact parameter can be used instead to configure an artifact input.
+
+ inputMavenArtifact
+ Input spec artifact
+
output (Default: ${project.build.directory}/boat-lint-reports)
Output directory for lint reports.
@@ -171,12 +177,15 @@ Example:
${ignored-lint-rules}
true
+
+To see details and an example of inputMavenArtifact:
+ [Example inputMavenArtifact parameter](#example-inputMavenArtifact-parameter)
To see details about this goal:
mvn help:describe -DgroupId=com.backbase.oss -DartifactId=boat-maven-plugin -Dgoal=lint -Ddetail`
-
-
+
+
## boat:bundle
Bundles a spec by resolving external references.
@@ -321,3 +330,47 @@ Configuration example
```
+
+## Example inputMavenArtifact parameter
+
+Example:
+
+```$xml
+
+ com.backbase.oss.boat.example
+ openapi-zips
+ 1.0.0-SNAPSHOT
+ api
+ zip
+ presentation-client-api/openapi.yaml
+
+```
+
+Parameters:
+
+ groupId
+ Required: true
+ Input artifacts groupId
+ artifactId
+ Required: true
+ Input artifacts artifactId
+ version
+ Required: true
+ Input artifacts version
+ classifier
+ Required: true
+ Input artifacts classifier (must be api)
+ type
+ Required: true
+ Input artifacts type (must be zip)
+ fileName
+ Required: true
+ directory or file in artifact to be processed by goal
+
+
+This parameter is available as a replacement for the inputSpec parameter in goals [generate](#boat:generate) and [lint](#boat:lint).
+
+It downloads a copy of the artifact if it is not already present, and uses a specified spec (or directory of specs)
+from the artifact as the inputSpec for the goal.
+
+More examples can be found in integration tests.
\ No newline at end of file
diff --git a/boat-maven-plugin/pom.xml b/boat-maven-plugin/pom.xml
index fcb2b0b63..597e18157 100644
--- a/boat-maven-plugin/pom.xml
+++ b/boat-maven-plugin/pom.xml
@@ -6,7 +6,7 @@
com.backbase.oss
backbase-openapi-tools
- 0.14.3
+ 0.14.4-SNAPSHOT
boat-maven-plugin
@@ -239,7 +239,7 @@
${project.build.directory}/local-repo
src/it/settings.xml
- org.jacoco:org.jacoco.agent:0.8.4:jar:runtime
+ org.jacoco:org.jacoco.agent:${jacoco-maven-plugin.version}:jar:runtime
diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateDocMojo.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateDocMojo.java
index 1b16ae73b..cc0ebeef8 100644
--- a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateDocMojo.java
+++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateDocMojo.java
@@ -7,12 +7,14 @@
@Mojo(name = "doc", threadSafe = true)
@Slf4j
-public class GenerateDocMojo extends GenerateFromDirectoryDocMojo {
+public class GenerateDocMojo extends GenerateFromDirectoryDocMojo {
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("Generating Boat Docs");
- generatorName = "boat-docs";
+ if (generatorName == null) {
+ generatorName = "boat-docs";
+ }
super.execute();
}
}
diff --git a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateFromDirectoryDocMojo.java b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateFromDirectoryDocMojo.java
index dbb31e553..01324b2e1 100644
--- a/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateFromDirectoryDocMojo.java
+++ b/boat-maven-plugin/src/main/java/com/backbase/oss/boat/GenerateFromDirectoryDocMojo.java
@@ -3,8 +3,12 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.plexus.util.DirectoryScanner;
import java.io.File;
+import java.util.Arrays;
+import java.util.stream.Collectors;
/**
* Allows generate::Doc to accept inputSpec as a directory
@@ -13,6 +17,9 @@
@Slf4j
public class GenerateFromDirectoryDocMojo extends GenerateMojo {
+ @Parameter(defaultValue = "**/*-api-*.yaml")
+ protected String openApiFileFilters;
+
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
@@ -33,22 +40,26 @@ private void fileInputExecute(File inputSpecFile) throws MojoExecutionException,
File[] inputSpecs;
File outPutDirectory = output;
- inputSpecs = inputSpecFile.listFiles(pathname -> pathname.getName().endsWith(".yaml"));
+ inputSpecs = findAllOpenApiSpecs(inputSpecFile);
- if (inputSpecs == null || inputSpecs.length == 0) {
+ if (inputSpecs.length == 0) {
throw new MojoExecutionException("No OpenAPI specs found in: " + inputSpec);
}
for (File f : inputSpecs) {
inputSpec = f.getPath();
- output = new File(outPutDirectory.getPath(), f.getName().substring(0, f.getName().lastIndexOf(".")).concat("-docs"));
+ output = new File(outPutDirectory.getPath(), f.getName().substring(0, f.getName().lastIndexOf(".")));
if (!output.exists()) {
output.mkdir();
}
log.info(" Generating docs for spec {} in directory", f.getName());
- super.execute();
+ try {
+ super.execute();
+ } catch (MojoExecutionException | MojoFailureException e) {
+ log.error("Failed to generate doc for spec: {}", inputSpec);
+ }
}
} else {
@@ -58,4 +69,15 @@ private void fileInputExecute(File inputSpecFile) throws MojoExecutionException,
}
}
+
+ private File[] findAllOpenApiSpecs(File specDirectory) {
+ DirectoryScanner directoryScanner = new DirectoryScanner();
+ directoryScanner.setBasedir(specDirectory);
+ directoryScanner.setIncludes(openApiFileFilters.replace(" ", "").split(","));
+ directoryScanner.scan();
+
+ String[] includedFiles = directoryScanner.getIncludedFiles();
+ return Arrays.stream(includedFiles).map(pathname -> new File(specDirectory, pathname))
+ .collect(Collectors.toList()).toArray(new File[]{});
+ }
}
diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/ExportBomMojoTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/ExportBomMojoTests.java
index 9b800a078..80dade2a9 100644
--- a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/ExportBomMojoTests.java
+++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/ExportBomMojoTests.java
@@ -45,16 +45,12 @@ class ExportBomMojoTests {
@Mock
Metadata metadatamock;
- @Captor
- ArgumentCaptor argCaptor;
-
@Test
- void testExportBomEmptyMeta() throws MojoFailureException, MojoExecutionException, ArtifactResolutionException {
+ void testExportBomEmptyMeta() throws MojoExecutionException {
artifactResolver = mock(ArtifactResolver.class);
artifactResult = mock( ArtifactResult.class);
metadataResolver = mock(MetadataResolver.class);
- org.eclipse.aether.artifact.Artifact artifact = mock(org.eclipse.aether.artifact.Artifact.class);
when(metadataResolver.resolveMetadata(any(),any())).thenReturn(Collections.singletonList(metadataResult));
@@ -77,13 +73,14 @@ void testExportBomEmptyMeta() throws MojoFailureException, MojoExecutionExceptio
build.setDirectory("target");
MavenProject project = new MavenProject();
- mojo.remoteRepositories = Collections.EMPTY_LIST;
+ mojo.remoteRepositories = Collections.emptyList();
project.setBuild(build);
mojo.project = project;
mojo.repositorySession = mock(RepositorySystemSession.class);
mojo.execute();
- assertThat(output.list()).isEmpty();
+ assertThat(output).isEmptyDirectory();
+
}
@Test
@@ -98,7 +95,7 @@ void testExportBomUseOfArtifactResolver() throws MojoFailureException, MojoExecu
artifactResolver = mock(ArtifactResolver.class);
artifactResult = mock( ArtifactResult.class);
org.eclipse.aether.artifact.Artifact artifact; //= mock(org.eclipse.aether.artifact.Artifact.class);
- artifact = new DefaultArtifact(groupId, artifactId, "", type, version,Collections.EMPTY_MAP, pomFile);
+ artifact = new DefaultArtifact(groupId, artifactId, "", type, version,Collections.emptyMap(), pomFile);
when(artifactResolver.resolveArtifact(any(),any())).thenReturn(artifactResult);
@@ -138,14 +135,14 @@ void testExportBomUseOfArtifactResolver() throws MojoFailureException, MojoExecu
build.setDirectory("target");
MavenProject project = new MavenProject();
- mojo.remoteRepositories = Collections.EMPTY_LIST;
+ mojo.remoteRepositories = Collections.emptyList();
project.setBuild(build);
mojo.project = project;
mojo.repositorySession = mock(RepositorySystemSession.class);
mojo.execute();
- assertThat(output.list()).isEmpty();
+ assertThat(output).isEmptyDirectory();
}
private File getFile(String fileName) {
diff --git a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java
index ed8cbd38f..9e9848e82 100644
--- a/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java
+++ b/boat-maven-plugin/src/test/java/com/backbase/oss/boat/GeneratorTests.java
@@ -111,8 +111,9 @@ void testBoatDocsWithDirectory() throws MojoExecutionException, MojoFailureExcep
mojo.skipIfSpecIsUnchanged = false;
mojo.bundleSpecs = true;
mojo.dereferenceComponents = true;
+ mojo.openApiFileFilters = "**/*.yaml";
mojo.execute();
- assertThat(output.list()).containsExactlyInAnyOrder("link-docs", "petstore-docs", "petstore-new-non-breaking-docs", "upto-docs");
+ assertThat(output.list()).contains("link", "petstore", "petstore-new-non-breaking", "upto");
}
@Test
diff --git a/boat-quay/boat-quay-lint/pom.xml b/boat-quay/boat-quay-lint/pom.xml
index 2dee91d22..3967741b5 100644
--- a/boat-quay/boat-quay-lint/pom.xml
+++ b/boat-quay/boat-quay-lint/pom.xml
@@ -5,7 +5,7 @@
com.backbase.oss
boat-quay
- 0.14.3
+ 0.14.4-SNAPSHOT
boat-quay-lint
jar
diff --git a/boat-quay/boat-quay-rules/pom.xml b/boat-quay/boat-quay-rules/pom.xml
index 397a468a9..2d13fd3d5 100644
--- a/boat-quay/boat-quay-rules/pom.xml
+++ b/boat-quay/boat-quay-rules/pom.xml
@@ -5,7 +5,7 @@
com.backbase.oss
boat-quay
- 0.14.3
+ 0.14.4-SNAPSHOT
boat-quay-rules
jar
diff --git a/boat-quay/boat-quay-rules/src/main/resources/boat.conf b/boat-quay/boat-quay-rules/src/main/resources/boat.conf
index 294fd29a2..3d9b22014 100644
--- a/boat-quay/boat-quay-rules/src/main/resources/boat.conf
+++ b/boat-quay/boat-quay-rules/src/main/resources/boat.conf
@@ -63,7 +63,7 @@ StringPropertyLengthBoundsRule {
}
OpenApiVersionRule {
- openApiVersions: [ 3.1.0 ]
+ openApiVersions: [ 3.0.3, 3.0.4 ]
}
ExtraRuleAnnotations {
diff --git a/boat-quay/pom.xml b/boat-quay/pom.xml
index 27b9d4674..dcf02d835 100644
--- a/boat-quay/pom.xml
+++ b/boat-quay/pom.xml
@@ -5,7 +5,7 @@
com.backbase.oss
backbase-openapi-tools
- 0.14.3
+ 0.14.4-SNAPSHOT
diff --git a/boat-scaffold/pom.xml b/boat-scaffold/pom.xml
index 3b4436e24..f195aca86 100644
--- a/boat-scaffold/pom.xml
+++ b/boat-scaffold/pom.xml
@@ -5,7 +5,7 @@
com.backbase.oss
backbase-openapi-tools
- 0.14.3
+ 0.14.4-SNAPSHOT
boat-scaffold
@@ -86,7 +86,7 @@
com.backbase.oss
boat-trail-resources
- 0.14.3
+ 0.14.4-SNAPSHOT
test
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/BoatDefaultGenerator.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/BoatDefaultGenerator.java
new file mode 100644
index 000000000..956e8e00d
--- /dev/null
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/BoatDefaultGenerator.java
@@ -0,0 +1,6 @@
+package com.backbase.oss.codegen;
+
+import org.openapitools.codegen.DefaultGenerator;
+
+public class BoatDefaultGenerator extends DefaultGenerator {
+}
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/BoatStaticDocsGenerator.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/BoatStaticDocsGenerator.java
new file mode 100644
index 000000000..f801e35fe
--- /dev/null
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/BoatStaticDocsGenerator.java
@@ -0,0 +1,189 @@
+package com.backbase.oss.codegen;
+
+import com.backbase.oss.codegen.doc.BoatCodegenParameter;
+import com.backbase.oss.codegen.doc.BoatCodegenResponse;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.parameters.Parameter;
+import io.swagger.v3.oas.models.parameters.RequestBody;
+import io.swagger.v3.oas.models.responses.ApiResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.message.BasicNameValuePair;
+import org.openapitools.codegen.CodegenModel;
+import org.openapitools.codegen.CodegenParameter;
+import org.openapitools.codegen.CodegenResponse;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Slf4j
+@SuppressWarnings("common-java:DuplicatedBlocks")
+public class BoatStaticDocsGenerator extends org.openapitools.codegen.languages.StaticHtml2Generator {
+
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+ private static final ObjectReader paramReader = BoatStaticDocsGenerator.objectMapper.readerFor(new TypeReference>() {
+ });
+ public BoatStaticDocsGenerator() {
+ super();
+ }
+
+ @Override
+ public void preprocessOpenAPI(OpenAPI openAPI) {
+ super.preprocessOpenAPI(openAPI);
+
+ // Add responses to additional properties
+ if (openAPI.getComponents().getResponses() != null) {
+ additionalProperties.put("responses", openAPI.getComponents().getResponses().entrySet().stream()
+ .map(this::mapCodegenResponse)
+ .collect(Collectors.toList()));
+ }
+
+ // Add parameters to additonal properties
+ if (openAPI.getComponents().getParameters() != null) {
+ Set imports = new HashSet<>();
+ additionalProperties.put("parameters", openAPI.getComponents().getParameters().entrySet().stream()
+ .map(nameParameter -> mapComponentParameter(imports, nameParameter))
+ .collect(Collectors.toList()));
+ }
+
+ // Add requests to addtional properties
+ if (openAPI.getComponents().getRequestBodies() != null) {
+ Set imports = new HashSet<>();
+ additionalProperties.put("requestBodies", openAPI.getComponents().getRequestBodies().entrySet().stream()
+ .map(namedRequestBody -> mapComponentRequestBody(imports, namedRequestBody))
+ .collect(Collectors.toList()));
+ }
+
+ if (openAPI.getPaths() != null)
+ // Ensure single tags for operations
+ openAPI.getPaths().forEach((path, pathItem) ->
+ pathItem.readOperations().forEach(operation -> {
+ if (operation.getTags() != null && operation.getTags().size() > 1) {
+ String tag = operation.getTags().get(operation.getTags().size() - 1);
+ log.warn("Operation: {} contains multiple tags {} which hinders rendering documentation. Rep" +
+ "lacing it with a single tag: {}", operation.getOperationId(), operation.getTags(), tag);
+ operation.tags(Collections.singletonList(tag));
+ }
+ }));
+ }
+
+ private CodegenParameter mapComponentRequestBody(Set imports, java.util.Map.Entry namedRequestBody) {
+ String name = namedRequestBody.getKey();
+ RequestBody requestBody = namedRequestBody.getValue();
+ return fromRequestBody(requestBody, imports, name);
+ }
+
+ private CodegenParameter mapComponentParameter(Set imports, java.util.Map.Entry nameParameter) {
+ Parameter parameter = nameParameter.getValue();
+ return fromParameter(parameter, imports);
+ }
+
+ private CodegenResponse mapCodegenResponse(java.util.Map.Entry codeResponse) {
+ String responseCode = codeResponse.getKey();
+ // try to resolve response code from key. otherwise use default
+ responseCode = responseCode.replaceAll("\\D+", "");
+ if (responseCode.length() != 3) {
+ responseCode = "default";
+ }
+ ApiResponse response = codeResponse.getValue();
+ return fromResponse(responseCode, response);
+ }
+
+ @Override
+ public String toModelName(String name) {
+ String modelName = super.toModelName(name);
+ if (!name.equals(modelName)) {
+ log.debug("NOT converting toModelName: {} to: {}", name, modelName);
+ }
+ return name;
+ }
+
+ @Override
+ public String toVarName(String name) {
+ String varName = super.toVarName(name);
+ if (!name.equals(varName)) {
+ log.debug("NOT converting varName: {} to: {}", name, varName);
+ }
+ return name;
+ }
+
+ @Override
+ public String toApiVarName(String name) {
+ String apiVarName = super.toApiVarName(name);
+ if (!name.equals(apiVarName)) {
+ log.debug("NOT converting apiVarName: {} to: {}", name, apiVarName);
+ }
+ return name;
+ }
+
+ @Override
+ public String toParamName(String name) {
+ String paramName = super.toParamName(name);
+ if (!name.equals(paramName)) {
+ log.debug("NOT converting apiVarName: {} to: {}", name, paramName);
+ }
+ return name;
+ }
+
+ @Override
+ public CodegenParameter fromParameter(Parameter parameter, Set imports) {
+ CodegenParameter codegenParameter = super.fromParameter(parameter, imports);
+ log.debug("Created CodegenParameter model for parameter: {}", parameter.getName());
+ return BoatCodegenParameter.fromCodegenParameter(parameter, codegenParameter, openAPI);
+ }
+
+ @Override
+ public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) {
+ CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName);
+ log.debug("Created CodegenParameter model for request body: {} with bodyParameterName: {}", codegenParameter.baseName, bodyParameterName);
+ return BoatCodegenParameter.fromCodegenParameter(codegenParameter, body, openAPI);
+ }
+
+ @Override
+ public CodegenResponse fromResponse(String responseCode, ApiResponse response) {
+ CodegenResponse r = super.fromResponse(responseCode, response);
+ r.message = StringUtils.replace(r.message, "`", "\\`");
+
+ return new BoatCodegenResponse(r, responseCode, response, openAPI);
+ }
+
+ @Override
+ public CodegenModel fromModel(String name, Schema schema) {
+ CodegenModel codegenModel = super.fromModel(name, schema);
+ log.debug("Created CodegenModel for name: {}, schema: {} resulting in: {}", name, schema.getName(), codegenModel.getName());
+ codegenModel.isAlias = false;
+ return codegenModel;
+ }
+
+ @Override
+ public void setParameterExampleValue(CodegenParameter codegenParameter, Parameter parameter) {
+ super.setParameterExampleValue(codegenParameter, parameter);
+
+ Object example = parameter.getExample();
+
+ if (parameter.getStyle() != null
+ && parameter.getStyle() == Parameter.StyleEnum.FORM
+ && example instanceof ArrayNode && codegenParameter.isQueryParam) {
+ try {
+ List values = BoatStaticDocsGenerator.paramReader.readValue((ArrayNode) example);
+ List params = values.stream()
+ .map(value -> new BasicNameValuePair(codegenParameter.paramName, value))
+ .collect(Collectors.toList());
+ codegenParameter.example = URLEncodedUtils.format(params, Charset.defaultCharset());
+ } catch (IOException e) {
+ log.warn("Failed to format query string parameter: {}", codegenParameter.example);
+ }
+ }
+ }
+}
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/angular/BoatAngularGenerator.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/angular/BoatAngularGenerator.java
index 562a25f3e..01ed5558b 100644
--- a/boat-scaffold/src/main/java/com/backbase/oss/codegen/angular/BoatAngularGenerator.java
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/angular/BoatAngularGenerator.java
@@ -149,7 +149,7 @@ public void processOpts() {
addSupportingFiles();
processOpt(NG_VERSION,
- value -> applyAngularVersion(value),
+ this::applyAngularVersion,
() -> applyAngularVersion(this.ngVersion)
);
@@ -197,7 +197,7 @@ private void applyAngularVersion(String versionRange) {
.map(value -> value.replace("^", ""))
.map(value -> value.replace("~", ""))
// Sorting versions via SemVer compareTo
- .map(value -> new SemVer(value))
+ .map(SemVer::new)
.sorted(SemVer::compareTo)
.toArray(SemVer[]::new);
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatDocsGenerator.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatDocsGenerator.java
index 526c3fcc0..b676b6dcc 100644
--- a/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatDocsGenerator.java
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatDocsGenerator.java
@@ -1,48 +1,21 @@
package com.backbase.oss.codegen.doc;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectReader;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.media.Schema;
-import io.swagger.v3.oas.models.parameters.Parameter;
-import io.swagger.v3.oas.models.parameters.RequestBody;
-import io.swagger.v3.oas.models.responses.ApiResponse;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.message.BasicNameValuePair;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
-import org.openapitools.codegen.CodegenModel;
-import org.openapitools.codegen.CodegenParameter;
-import org.openapitools.codegen.CodegenResponse;
+
+import java.util.HashMap;
@Slf4j
-public class BoatDocsGenerator extends org.openapitools.codegen.languages.StaticHtml2Generator {
+public class BoatDocsGenerator extends com.backbase.oss.codegen.BoatStaticDocsGenerator {
public static final String NAME = "boat-docs";
- protected Boolean generateAliasModel = true;
-
- private static final ObjectMapper objectMapper = new ObjectMapper();
- private static final ObjectReader paramReader = objectMapper.readerFor(new TypeReference>() {
- });
-
public BoatDocsGenerator() {
super();
embeddedTemplateDir = templateDir = NAME;
cliOptions.add(new CliOption(CodegenConstants.GENERATE_ALIAS_AS_MODEL, CodegenConstants.GENERATE_ALIAS_AS_MODEL));
- additionalProperties.put(CodegenConstants.GENERATE_ALIAS_AS_MODEL, generateAliasModel);
+ additionalProperties.put(CodegenConstants.GENERATE_ALIAS_AS_MODEL, false);
additionalProperties.put("appName", "OpenAPI Sample");
additionalProperties.put("appDescription", "A sample OpenAPI server");
additionalProperties.put("infoUrl", "https://backbase.github.io/backbase-openapi-tools/");
@@ -53,156 +26,6 @@ public BoatDocsGenerator() {
}
- @Override
- public void preprocessOpenAPI(OpenAPI openAPI) {
- super.preprocessOpenAPI(openAPI);
-
- // Add responses to additional properties
- if (openAPI.getComponents().getResponses() != null) {
- additionalProperties.put("responses", openAPI.getComponents().getResponses().entrySet().stream()
- .map(this::mapCodegenResponse)
- .collect(Collectors.toList()));
- }
-
- // Add parameters to additonal properties
- if (openAPI.getComponents().getParameters() != null) {
- Set imports = new HashSet<>();
- additionalProperties.put("parameters", openAPI.getComponents().getParameters().entrySet().stream()
- .map(nameParameter -> mapComponentParameter(imports, nameParameter))
- .collect(Collectors.toList()));
- }
-
- // Add requests to addtional properties
- if (openAPI.getComponents().getRequestBodies() != null) {
- Set imports = new HashSet<>();
- additionalProperties.put("requestBodies", openAPI.getComponents().getRequestBodies().entrySet().stream()
- .map(namedRequestBody -> mapComponentRequestBody(imports, namedRequestBody))
- .collect(Collectors.toList()));
- }
-
- if (openAPI.getPaths() != null)
- // Ensure single tags for operations
- openAPI.getPaths().forEach((path, pathItem) ->
- pathItem.readOperations().forEach(operation -> {
- if (operation.getTags() != null && operation.getTags().size() > 1) {
- String tag = operation.getTags().get(operation.getTags().size() -1 );
- log.warn("Operation: {} contains multiple tags {} which hinders rendering documentation. Rep" +
- "lacing it with a single tag: {}", operation.getOperationId(), operation.getTags(), tag);
- operation.tags(Collections.singletonList(tag));
- }
- }));
- }
-
- private CodegenParameter mapComponentRequestBody(Set imports, java.util.Map.Entry namedRequestBody) {
- String name = namedRequestBody.getKey();
- RequestBody requestBody = namedRequestBody.getValue();
- return fromRequestBody(requestBody, imports, name);
- }
-
- private CodegenParameter mapComponentParameter(Set imports, java.util.Map.Entry nameParameter) {
- Parameter parameter = nameParameter.getValue();
- return fromParameter(parameter, imports);
- }
-
- private CodegenResponse mapCodegenResponse(java.util.Map.Entry codeResponse) {
- String responseCode = codeResponse.getKey();
- // try to resolve response code from key. otherwise use default
- responseCode = responseCode.replaceAll("\\D+", "");
- if (responseCode.length() != 3) {
- responseCode = "default";
- }
- ApiResponse response = codeResponse.getValue();
- return fromResponse(responseCode, response);
- }
-
-
- @Override
- public String toModelName(String name) {
- String modelName = super.toModelName(name);
- if (!name.equals(modelName)) {
- log.debug("NOT converting toModelName: {} to: {}", name, modelName);
- }
- return name;
- }
-
- @Override
- public String toVarName(String name) {
- String varName = super.toVarName(name);
- if (!name.equals(varName)) {
- log.debug("NOT converting varName: {} to: {}", name, varName);
- }
- return name;
- }
-
- @Override
- public String toApiVarName(String name) {
- String apiVarName = super.toApiVarName(name);
- if (!name.equals(apiVarName)) {
- log.debug("NOT converting apiVarName: {} to: {}", name, apiVarName);
- }
- return name;
- }
-
- @Override
- public String toParamName(String name) {
- String paramName = super.toParamName(name);
- if (!name.equals(paramName)) {
- log.debug("NOT converting apiVarName: {} to: {}", name, paramName);
- }
- return name;
- }
-
- @Override
- public CodegenParameter fromParameter(Parameter parameter, Set imports) {
- CodegenParameter codegenParameter = super.fromParameter(parameter, imports);
- log.debug("Created CodegenParameter model for parameter: {}", parameter.getName());
- return BoatCodegenParameter.fromCodegenParameter(parameter, codegenParameter, openAPI);
- }
-
- @Override
- public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) {
- CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName);
- log.debug("Created CodegenParameter model for request body: {} with bodyParameterName: {}", codegenParameter.baseName, bodyParameterName);
- return BoatCodegenParameter.fromCodegenParameter(codegenParameter, body, openAPI);
- }
-
- @Override
- public CodegenResponse fromResponse(String responseCode, ApiResponse response) {
- CodegenResponse r = super.fromResponse(responseCode, response);
- r.message = StringUtils.replace(r.message, "`", "\\`");
-
- return new BoatCodegenResponse(r, responseCode, response, openAPI);
- }
-
- @Override
- public CodegenModel fromModel(String name, Schema schema) {
- CodegenModel codegenModel = super.fromModel(name, schema);
- log.debug("Created CodegenModel for name: {}, schema: {} resulting in: {}", name, schema.getName(), codegenModel.getName());
- codegenModel.isAlias = false;
- return codegenModel;
- }
-
- @Override
- public void setParameterExampleValue(CodegenParameter codegenParameter, Parameter parameter) {
- super.setParameterExampleValue(codegenParameter, parameter);
-
- Object example = parameter.getExample();
-
- if (parameter.getStyle() != null
- && parameter.getStyle() == Parameter.StyleEnum.FORM
- && example instanceof ArrayNode && codegenParameter.isQueryParam) {
- try {
- List values = paramReader.readValue((ArrayNode) example);
- List params = values.stream()
- .map(value -> new BasicNameValuePair(codegenParameter.paramName, value))
- .collect(Collectors.toList());
- codegenParameter.example = URLEncodedUtils.format(params, Charset.defaultCharset());
- } catch (IOException e) {
- log.warn("Failed to format query string parameter: {}", codegenParameter.example);
- }
- }
- }
-
@Override
public String getName() {
return NAME;
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatExample.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatExample.java
index 5e21f86b1..57bce77ba 100644
--- a/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatExample.java
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/doc/BoatExample.java
@@ -38,8 +38,14 @@ public String getPrettyPrintValue() {
if (example.getValue() instanceof JsonNode
|| example.getValue() instanceof HashMap) {
return Json.pretty(example.getValue());
+ } else if (example.getValue() == null) {
+ return "";
} else {
- return example.getValue().toString();
+ if (example.getValue() != null) {
+ return example.getValue().toString();
+ } else {
+ return null;
+ }
}
}
}
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatJavaCodeGen.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatJavaCodeGen.java
index 48fec14e6..5965fb1c6 100644
--- a/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatJavaCodeGen.java
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatJavaCodeGen.java
@@ -103,30 +103,7 @@ public void processOpts() {
}
if (RESTTEMPLATE.equals(getLibrary())) {
- if (this.additionalProperties.containsKey(USE_CLASS_LEVEL_BEAN_VALIDATION)) {
- this.useClassLevelBeanValidation = convertPropertyToBoolean(USE_CLASS_LEVEL_BEAN_VALIDATION);
- }
- writePropertyBack(USE_CLASS_LEVEL_BEAN_VALIDATION, this.useClassLevelBeanValidation);
-
- if (this.additionalProperties.containsKey(USE_JACKSON_CONVERSION)) {
- this.useJacksonConversion = convertPropertyToBoolean(USE_JACKSON_CONVERSION);
- }
- writePropertyBack(USE_JACKSON_CONVERSION, this.useJacksonConversion);
- if (this.useJacksonConversion) {
- this.supportingFiles.removeIf(f -> f.templateFile.equals("RFC3339DateFormat.mustache"));
- }
-
- if (this.additionalProperties.containsKey(USE_DEFAULT_API_CLIENT)) {
- this.useDefaultApiClient = convertPropertyToBoolean(USE_DEFAULT_API_CLIENT);
- }
- writePropertyBack(USE_DEFAULT_API_CLIENT, this.useDefaultApiClient);
-
- this.restTemplateBeanName = (String) this.additionalProperties.get(REST_TEMPLATE_BEAN_NAME);
-
- if (this.additionalProperties.containsKey(CREATE_API_COMPONENT)) {
- this.createApiComponent = convertPropertyToBoolean(CREATE_API_COMPONENT);
- }
- writePropertyBack(CREATE_API_COMPONENT, this.createApiComponent);
+ processRestTemplateOpts();
}
if (this.additionalProperties.containsKey(USE_PROTECTED_FIELDS)) {
this.additionalProperties.put("modelFieldsVisibility", "protected");
@@ -140,6 +117,33 @@ public void processOpts() {
}
}
+ private void processRestTemplateOpts() {
+ if (this.additionalProperties.containsKey(USE_CLASS_LEVEL_BEAN_VALIDATION)) {
+ this.useClassLevelBeanValidation = convertPropertyToBoolean(USE_CLASS_LEVEL_BEAN_VALIDATION);
+ }
+ writePropertyBack(USE_CLASS_LEVEL_BEAN_VALIDATION, this.useClassLevelBeanValidation);
+
+ if (this.additionalProperties.containsKey(USE_JACKSON_CONVERSION)) {
+ this.useJacksonConversion = convertPropertyToBoolean(USE_JACKSON_CONVERSION);
+ }
+ writePropertyBack(USE_JACKSON_CONVERSION, this.useJacksonConversion);
+ if (this.useJacksonConversion) {
+ this.supportingFiles.removeIf(f -> f.templateFile.equals("RFC3339DateFormat.mustache"));
+ }
+
+ if (this.additionalProperties.containsKey(USE_DEFAULT_API_CLIENT)) {
+ this.useDefaultApiClient = convertPropertyToBoolean(USE_DEFAULT_API_CLIENT);
+ }
+ writePropertyBack(USE_DEFAULT_API_CLIENT, this.useDefaultApiClient);
+
+ this.restTemplateBeanName = (String) this.additionalProperties.get(REST_TEMPLATE_BEAN_NAME);
+
+ if (this.additionalProperties.containsKey(CREATE_API_COMPONENT)) {
+ this.createApiComponent = convertPropertyToBoolean(CREATE_API_COMPONENT);
+ }
+ writePropertyBack(CREATE_API_COMPONENT, this.createApiComponent);
+ }
+
@Override
public void postProcessModelProperty(CodegenModel model, CodegenProperty p) {
super.postProcessModelProperty(model, p);
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatSpringCodeGen.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatSpringCodeGen.java
index ff0e5cb9c..9fbb36840 100644
--- a/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatSpringCodeGen.java
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/java/BoatSpringCodeGen.java
@@ -182,12 +182,10 @@ public void processOpts() {
// ApiUtil.java present or not
// true or false
final String supFiles = GlobalSettings.getProperty(CodegenConstants.SUPPORTING_FILES);
- final boolean useApiUtil =
- supFiles == null
- ? false // cleared by false
- : supFiles.isEmpty()
- ? needApiUtil() // set to empty by true
- : supFiles.contains("ApiUtil.java"); // set by
+ // cleared by false
+ final boolean useApiUtil = supFiles != null && (supFiles.isEmpty()
+ ? needApiUtil() // set to empty by true
+ : supFiles.contains("ApiUtil.java")); // set by
if (!useApiUtil) {
this.supportingFiles
diff --git a/boat-scaffold/src/main/java/com/backbase/oss/codegen/marina/BoatHandlebarsEngineAdapter.java b/boat-scaffold/src/main/java/com/backbase/oss/codegen/marina/BoatHandlebarsEngineAdapter.java
new file mode 100644
index 000000000..ea2bdee19
--- /dev/null
+++ b/boat-scaffold/src/main/java/com/backbase/oss/codegen/marina/BoatHandlebarsEngineAdapter.java
@@ -0,0 +1,62 @@
+package com.backbase.oss.codegen.marina;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.github.jknack.handlebars.*;
+import com.github.jknack.handlebars.context.FieldValueResolver;
+import com.github.jknack.handlebars.context.JavaBeanValueResolver;
+import com.github.jknack.handlebars.context.MapValueResolver;
+import com.github.jknack.handlebars.helper.ConditionalHelpers;
+import com.github.jknack.handlebars.helper.StringHelpers;
+import com.github.jknack.handlebars.io.AbstractTemplateLoader;
+import com.github.jknack.handlebars.io.TemplateLoader;
+import com.github.jknack.handlebars.io.TemplateSource;
+import lombok.extern.slf4j.Slf4j;
+import org.openapitools.codegen.api.TemplatingGenerator;
+import org.openapitools.codegen.templating.HandlebarsEngineAdapter;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
+
+@Slf4j
+public class BoatHandlebarsEngineAdapter extends HandlebarsEngineAdapter {
+
+ @Override
+ public String compileTemplate(TemplatingGenerator generator,
+ Map bundle, String templateFile) throws IOException {
+ TemplateLoader loader = new AbstractTemplateLoader() {
+ @Override
+ public TemplateSource sourceAt(String location) {
+ return findTemplate(generator, location);
+ }
+ };
+
+ Context context = Context
+ .newBuilder(bundle)
+ .resolver(
+ MapValueResolver.INSTANCE,
+ JavaBeanValueResolver.INSTANCE,
+ FieldValueResolver.INSTANCE)
+ .build();
+
+ Handlebars handlebars = new Handlebars(loader);
+ handlebars.registerHelperMissing((obj, options) -> {
+ log.warn(String.format(Locale.ROOT, "Unregistered helper name '%s', processing template:%n%s", options.helperName, options.fn.text()));
+ return "";
+ });
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+ objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ Helper