Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ It currently consists of
# Release Notes
BOAT is still under development and subject to change.

## 0.18.1
* Spring generator: fixed `@ExampleObject` rendering in `api.mustache` by unwrapping escaped quotes in example payloads.
* Added `unwrapEscapedQuotes` lambda to `boat-spring` generator templates to prevent malformed annotation values (for example `value = "\"{...}"`).
* Added a regression test to verify generated Spring API interfaces include valid `@ExampleObject` annotation values and remain parseable Java code.

## 0.18.0
* openapi-generator `7.20.0` baseline (Spring Boot 4, Jackson 3)
* moved Java and JavaSpring templates to `7.20.0` adding remaing custom features
Expand Down
2 changes: 1 addition & 1 deletion boat-engine/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>
<artifactId>boat-engine</artifactId>
<packaging>jar</packaging>
Expand Down
2 changes: 1 addition & 1 deletion boat-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>
<artifactId>boat-maven-plugin</artifactId>

Expand Down
2 changes: 1 addition & 1 deletion boat-quay/boat-quay-lint/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>boat-quay</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>

<artifactId>boat-quay-lint</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion boat-quay/boat-quay-rules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>boat-quay</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>

<artifactId>boat-quay-rules</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion boat-quay/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>


Expand Down
4 changes: 2 additions & 2 deletions boat-scaffold/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>

<artifactId>boat-scaffold</artifactId>
Expand Down Expand Up @@ -102,7 +102,7 @@
<dependency>
<groupId>com.backbase.oss</groupId>
<artifactId>boat-trail-resources</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class BoatSpringCodeGen extends SpringCodegen {

public static final String ADD_SERVLET_REQUEST = "addServletRequest";
public static final String ADD_BINDING_RESULT = "addBindingResult";
public static final String UNWRAP_ESCAPED_QUOTES = "unwrapEscapedQuotes";

private static final String VENDOR_EXTENSION_NOT_NULL = "x-not-null";

Expand Down Expand Up @@ -147,6 +148,23 @@ protected String postProcessLine(String line) {
}
}

static class UnwrapEscapedQuotes implements Mustache.Lambda {

@Override
public void execute(Fragment frag, Writer out) throws IOException {
String text = frag.execute();
if (text == null) {
return;
}
String normalized = text.replace("\\\\\"", "\\\"");
if (normalized.length() >= 4 && normalized.startsWith("\\\"") && normalized.endsWith("\\\"")) {
out.write(normalized.substring(2, normalized.length() - 2));
return;
}
out.write(normalized);
}
}

/**
* Adds a HttpServletRequest object to the API definition method.
*/
Expand Down Expand Up @@ -332,6 +350,7 @@ public void processOpts() {
this.additionalProperties.put("newLine8", new NewLineIndent(8, " "));
this.additionalProperties.put("toOneLine", new FormatToOneLine());
this.additionalProperties.put("trimAndIndent4", new TrimAndIndent(4, " "));
this.additionalProperties.put(UNWRAP_ESCAPED_QUOTES, new UnwrapEscapedQuotes());
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion boat-scaffold/src/main/templates/boat-spring/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public interface {{classname}} {
{{#examples}}
@ExampleObject(
name = "{{{exampleName}}}",
value = "{{{exampleValue}}}"
value = "{{#unwrapEscapedQuotes}}{{{exampleValue}}}{{/unwrapEscapedQuotes}}"
){{^-last}},{{/-last}}
{{/examples}}
{{#-last}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isA;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -48,14 +49,17 @@
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.UnhandledException;
import org.hamcrest.Matchers;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenOperation;
Expand Down Expand Up @@ -97,6 +101,20 @@ void newLineIndent() throws IOException {
assertThat(output.toString(), equalTo(String.format("__%n__Good%n__ morning,%n__ Dave%n")));
}

@ParameterizedTest
@MethodSource("unwrapEscapedQuotesCases")
void unwrapEscapedQuotes_execute_shouldHandleAllScenarios(String input, String expectedOutput) throws IOException {
final BoatSpringCodeGen.UnwrapEscapedQuotes lambda = new BoatSpringCodeGen.UnwrapEscapedQuotes();
final StringWriter output = new StringWriter();
final Fragment frag = mock(Fragment.class);

when(frag.execute()).thenReturn(input);

lambda.execute(frag, output);

assertThat(output.toString(), equalTo(expectedOutput));
}

@Test
void addServletRequestTestFromOperation(){
final BoatSpringCodeGen gen = new BoatSpringCodeGen();
Expand Down Expand Up @@ -139,6 +157,45 @@ void multipartWithFileAndObject() throws IOException {
assertThat(filesParam.getTypeAsString(), equalTo("List<MultipartFile>"));
}

@Test
void shouldGenerateValidExampleObjectAnnotation() throws IOException {
var codegen = new BoatSpringCodeGen();
var input = new File("src/test/resources/openapi-with-examples/openapi-with-multiple-permissions.yaml");
codegen.setLibrary("spring-boot");
codegen.setInterfaceOnly(true);
codegen.setSkipDefaultInterface(true);
codegen.setOutputDir(TEST_OUTPUT + "/example-object");
codegen.setInputSpec(input.getAbsolutePath());
codegen.additionalProperties().put(SpringCodegen.USE_SPRING_BOOT3, Boolean.TRUE.toString());

var openApiInput = new OpenAPIParser().readLocation(input.getAbsolutePath(), null, new ParseOptions())
.getOpenAPI();
var clientOptInput = new ClientOptInput();
clientOptInput.config(codegen);
clientOptInput.openAPI(openApiInput);

List<File> files = new DefaultGenerator().opts(clientOptInput).generate();

File apiFile = files.stream()
.filter(file -> file.getName().endsWith("Api.java"))
.filter(file -> {
try {
return Files.readString(file.toPath()).contains("@ExampleObject(");
} catch (IOException e) {
throw new UnhandledException(e);
}
})
.findFirst()
.orElseThrow();

String apiContent = Files.readString(apiFile.toPath());
assertTrue(apiContent.contains("@ExampleObject("));
assertTrue(apiContent.contains("Value Exceeded. Must be between {min} and {max}."));
assertTrue(apiContent.contains("Bad Request"));
assertFalse(apiContent.contains("value = \"\\\"{"));
StaticJavaParser.parse(apiFile);
}

@Test
void testReplaceBeanValidationCollectionType() {
var codegen = new BoatSpringCodeGen();
Expand Down Expand Up @@ -552,4 +609,12 @@ private static void assertMethodCollectionReturnType(MethodDeclaration method, S
.getTypeArguments().get().getFirst().get();
assertEquals(itemType, collectionItemType.getName().toString());
}

static Stream<Arguments> unwrapEscapedQuotesCases() {
return Stream.of(
Arguments.of((String) null, ""),
Arguments.of("\\\"{\\\"message\\\":\\\"Bad Request\\\"}\\\"", "{\\\"message\\\":\\\"Bad Request\\\"}"),
Arguments.of("prefix\\\\\"quoted\\\\\"suffix", "prefix\\\"quoted\\\"suffix"),
Arguments.of("\\\"", "\\\""));
}
}
2 changes: 1 addition & 1 deletion boat-trail-resources/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>

<artifactId>boat-trail-resources</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>

<packaging>pom</packaging>
<description>Backbase Open Api Tools is a collection of tools to work with Open API</description>
Expand Down
2 changes: 1 addition & 1 deletion tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>com.backbase.oss</groupId>
<artifactId>backbase-openapi-tools</artifactId>
<version>0.18.0-SNAPSHOT</version>
<version>0.18.1-SNAPSHOT</version>
</parent>

<artifactId>tests</artifactId>
Expand Down