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
15 changes: 15 additions & 0 deletions bin/configs/spring-http-interface-oauth.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
generatorName: spring
library: spring-http-interface
outputDir: samples/client/petstore/spring-http-interface-oauth
inputSpec: modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
additionalProperties:
artifactId: spring-http-interface-oauth
snapshotVersion: "true"
hideGenerationTimestamp: "true"
modelNameSuffix: 'Dto'
generatedConstructorWithRequiredArgs: "false"
clientRegistrationId: "petstore-oauth"
parentGroupId: "org.springframework.boot"
parentArtifactId: "spring-boot-starter-parent"
parentVersion: "3.5.0"
1 change: 1 addition & 0 deletions docs/generators/java-camel.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|camelSecurityDefinitions|generate camel security definitions| |true|
|camelUseDefaultValidationErrorProcessor|generate default validation error processor| |true|
|camelValidationErrorProcessor|validation error processor bean name| |validationErrorProcessor|
|clientRegistrationId|Client registration ID for OAuth2 in Spring HTTP Interface (@ClientRegistrationId annotation).| |null|
|configPackage|configuration package for generated code| |org.openapitools.configuration|
|containerDefaultToNull|Set containers (array, set, map) default to null| |false|
|dateLibrary|Option. Date library to use|<dl><dt>**joda**</dt><dd>Joda (for legacy app only)</dd><dt>**legacy**</dt><dd>Legacy java.util.Date</dd><dt>**java8-localdatetime**</dt><dd>Java 8 using LocalDateTime (for legacy app only)</dd><dt>**java8**</dt><dd>Java 8 native JSR310 (preferred for jdk 1.8+)</dd></dl>|java8|
Expand Down
1 change: 1 addition & 0 deletions docs/generators/spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|bigDecimalAsString|Treat BigDecimal values as Strings to avoid precision loss.| |false|
|booleanGetterPrefix|Set booleanGetterPrefix| |get|
|camelCaseDollarSign|Fix camelCase when starting with $ sign. when true : $Value when false : $value| |false|
|clientRegistrationId|Client registration ID for OAuth2 in Spring HTTP Interface (@ClientRegistrationId annotation).| |null|
|configPackage|configuration package for generated code| |org.openapitools.configuration|
|containerDefaultToNull|Set containers (array, set, map) default to null| |false|
|dateLibrary|Option. Date library to use|<dl><dt>**joda**</dt><dd>Joda (for legacy app only)</dd><dt>**legacy**</dt><dd>Legacy java.util.Date</dd><dt>**java8-localdatetime**</dt><dd>Java 8 using LocalDateTime (for legacy app only)</dd><dt>**java8**</dt><dd>Java 8 native JSR310 (preferred for jdk 1.8+)</dd></dl>|java8|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public class SpringCodegen extends AbstractJavaCodegen
public static final String JACKSON3_PACKAGE = "tools.jackson";
public static final String JACKSON_PACKAGE = "jacksonPackage";
public static final String ADDITIONAL_NOT_NULL_ANNOTATIONS = "additionalNotNullAnnotations";
public static final String CLIENT_REGISTRATION_ID = "clientRegistrationId";

@Getter
public enum RequestMappingMode {
Expand Down Expand Up @@ -183,6 +184,8 @@ public enum RequestMappingMode {
protected boolean useJackson3 = false;
@Getter @Setter
protected boolean additionalNotNullAnnotations = false;
@Getter @Setter
protected String clientRegistrationId = null;

public SpringCodegen() {
super();
Expand Down Expand Up @@ -317,6 +320,7 @@ public SpringCodegen() {

cliOptions.add(CliOption.newBoolean(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, "whether to use deduction for generated oneOf interfaces", useDeductionForOneOfInterfaces));
cliOptions.add(CliOption.newString(SPRING_API_VERSION, "Value for 'version' attribute in @RequestMapping (for Spring 7 and above)."));
cliOptions.add(CliOption.newString(CLIENT_REGISTRATION_ID, "Client registration ID for OAuth2 in Spring HTTP Interface (@ClientRegistrationId annotation)."));
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
supportedLibraries.put(SPRING_CLOUD_LIBRARY,
"Spring-Cloud-Feign client with Spring-Boot auto-configured settings.");
Expand Down Expand Up @@ -505,6 +509,7 @@ public void processOpts() {
convertPropertyToBooleanAndWriteBack(OPTIONAL_ACCEPT_NULLABLE, this::setOptionalAcceptNullable);
convertPropertyToBooleanAndWriteBack(USE_SPRING_BUILT_IN_VALIDATION, this::setUseSpringBuiltInValidation);
convertPropertyToBooleanAndWriteBack(USE_DEDUCTION_FOR_ONE_OF_INTERFACES, this::setUseDeductionForOneOfInterfaces);
convertPropertyToStringAndWriteBack(CLIENT_REGISTRATION_ID, this::setClientRegistrationId);

additionalProperties.put("springHttpStatus", new SpringHttpStatusLambda());

Expand Down Expand Up @@ -883,6 +888,11 @@ public void setIsVoid(boolean isVoid) {
// But use a sensible tag name if there is none
objs.put("tagName", "default".equals(firstTagName) ? firstOperation.baseName : firstTagName);
objs.put("tagDescription", escapeText(firstTag.getDescription()));

// Add clientRegistrationId for spring-http-interface with OAuth
if (SPRING_HTTP_INTERFACE.equals(library) && clientRegistrationId != null && !clientRegistrationId.isEmpty()) {
operations.put("clientRegistrationId", clientRegistrationId);
}
}

removeImport(objs, "java.util.List");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import org.springframework.http.ResponseEntity;
{{/useResponseEntity}}
import org.springframework.web.bind.annotation.*;
import org.springframework.web.service.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartFile;{{#operations}}{{#clientRegistrationId}}
import org.springframework.security.oauth2.client.annotation.ClientRegistrationId;{{/clientRegistrationId}}{{/operations}}
{{#reactive}}

import org.springframework.http.codec.multipart.Part;
Expand All @@ -32,6 +33,9 @@ import {{javaxPackage}}.annotation.Generated;
{{>generatedAnnotation}}

{{#operations}}
{{#clientRegistrationId}}
@ClientRegistrationId("{{clientRegistrationId}}")
{{/clientRegistrationId}}
public interface {{classname}} {
{{#operation}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@
<optional>true</optional>
</dependency>
{{/lombok}}
{{#clientRegistrationId}}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
{{/clientRegistrationId}}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6472,143 +6472,30 @@ public void testExtensionsOnSchema_issue9183() throws IOException {
}

@Test
public void shouldAddNullableImportForArrayTypeModels() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec(
"src/test/resources/3_0/spring/petstore-with-fake-endpoints-models-for-testing-with-spring-pageable.yaml");
final SpringCodegen codegen = new SpringCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(INTERFACE_ONLY, "true");
codegen.additionalProperties().put(CodegenConstants.GENERATE_ALIAS_AS_MODEL, "true");

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

DefaultGenerator generator = new DefaultGenerator();
generator.setGenerateMetadata(false);
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");

Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));

// AnimalFarm is an array-type model with no properties (issue #22788)
JavaFileAssert.assertThat(files.get("AnimalFarm.java"))
.hasImports("org.springframework.lang.Nullable");
JavaFileAssert.assertThat(files.get("Pet.java"))
.hasImports("org.springframework.lang.Nullable");
}

@Test
public void shouldRefuseJackson3WithoutSpringboot4() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore-echo.yaml");
final SpringCodegen codegen = new SpringCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOutputDir(output.getAbsolutePath());

codegen.additionalProperties().put(SpringCodegen.USE_SPRING_BOOT4, "false");
codegen.additionalProperties().put(SpringCodegen.USE_JACKSON_3, "true");

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

Generator generator = new DefaultGenerator()
.opts(input);

Assertions.assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(generator::generate);
}

@Test
public void shouldRefuseOpenApiNullableWithJackson3() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore-echo.yaml");
public void testClientRegistrationIdAnnotation() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOutputDir(output.getAbsolutePath());

codegen.additionalProperties().put(SpringCodegen.USE_SPRING_BOOT4, "true");
codegen.additionalProperties().put(SpringCodegen.USE_JACKSON_3, "true");
codegen.additionalProperties().put(SpringCodegen.OPENAPI_NULLABLE, "true");
codegen.setLibrary("spring-http-interface");
codegen.setClientRegistrationId("my-oauth-client");

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

Generator generator = new DefaultGenerator()
.opts(input);

Assertions.assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(generator::generate);
}

@Test
public void shouldImportJackson2JsonDeserializeForUniqueItemsWhenJackson3NotSet() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
String outputPath = output.getAbsolutePath().replace('\\', '/');

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore-echo.yaml");
final SpringCodegen codegen = new SpringCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOutputDir(output.getAbsolutePath());

codegen.additionalProperties().put(SpringCodegen.USE_SPRING_BOOT4, "true");
codegen.additionalProperties().put(SpringCodegen.USE_JACKSON_3, "false");

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

DefaultGenerator generator = new DefaultGenerator();
generator.setGenerateMetadata(false); // skip metadata generation

Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));
final Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/petstore.yaml");

JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Pet.java"))
.hasImports("com.fasterxml.jackson.databind.annotation.JsonDeserialize");
// Check that the @ClientRegistrationId annotation is generated at class level
JavaFileAssert.assertThat(files.get("PetApi.java"))
.hasImports("org.springframework.security.oauth2.client.annotation.ClientRegistrationId")
.assertTypeAnnotations()
.containsWithNameAndAttributes("ClientRegistrationId", ImmutableMap.of("value", "\"my-oauth-client\""));
}

@Test
public void shouldImportJackson3JsonDeserializeForUniqueItemsWhenJackson3Set() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
String outputPath = output.getAbsolutePath().replace('\\', '/');

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore-echo.yaml");
public void testClientRegistrationIdAnnotationNotPresentWhenNotConfigured() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOutputDir(output.getAbsolutePath());

codegen.setLibrary("spring-http-interface");
// clientRegistrationId not set

codegen.additionalProperties().put(SpringCodegen.USE_SPRING_BOOT4, "true");
codegen.additionalProperties().put(SpringCodegen.USE_JACKSON_3, "true");
codegen.additionalProperties().put(SpringCodegen.OPENAPI_NULLABLE, "false");

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

DefaultGenerator generator = new DefaultGenerator();
generator.setGenerateMetadata(false); // skip metadata generation

Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));
final Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/petstore.yaml");

JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/model/Pet.java"))
.hasImports("tools.jackson.databind.annotation.JsonDeserialize");
// Check that the @ClientRegistrationId annotation is NOT generated
assertFileNotContains(files.get("PetApi.java").toPath(), "@ClientRegistrationId", "ClientRegistrationId");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

# Preserve custom OAuth2 documentation
README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
pom.xml
src/main/java/org/openapitools/api/AnotherFakeApi.java
src/main/java/org/openapitools/api/FakeApi.java
src/main/java/org/openapitools/api/FakeClassnameTags123Api.java
src/main/java/org/openapitools/api/PetApi.java
src/main/java/org/openapitools/api/StoreApi.java
src/main/java/org/openapitools/api/UserApi.java
src/main/java/org/openapitools/configuration/HttpInterfacesAbstractConfigurator.java
src/main/java/org/openapitools/model/AdditionalPropertiesAnyTypeDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesArrayDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesBooleanDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesClassDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesIntegerDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesNumberDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesObjectDto.java
src/main/java/org/openapitools/model/AdditionalPropertiesStringDto.java
src/main/java/org/openapitools/model/AnimalDto.java
src/main/java/org/openapitools/model/ApiResponseDto.java
src/main/java/org/openapitools/model/ArrayOfArrayOfNumberOnlyDto.java
src/main/java/org/openapitools/model/ArrayOfNumberOnlyDto.java
src/main/java/org/openapitools/model/ArrayTestDto.java
src/main/java/org/openapitools/model/BigCatDto.java
src/main/java/org/openapitools/model/CapitalizationDto.java
src/main/java/org/openapitools/model/CatDto.java
src/main/java/org/openapitools/model/CategoryDto.java
src/main/java/org/openapitools/model/ChildWithNullableDto.java
src/main/java/org/openapitools/model/ClassModelDto.java
src/main/java/org/openapitools/model/ClientDto.java
src/main/java/org/openapitools/model/ContainerDefaultValueDto.java
src/main/java/org/openapitools/model/DogDto.java
src/main/java/org/openapitools/model/EnumArraysDto.java
src/main/java/org/openapitools/model/EnumClassDto.java
src/main/java/org/openapitools/model/EnumTestDto.java
src/main/java/org/openapitools/model/FileDto.java
src/main/java/org/openapitools/model/FileSchemaTestClassDto.java
src/main/java/org/openapitools/model/FormatTestDto.java
src/main/java/org/openapitools/model/HasOnlyReadOnlyDto.java
src/main/java/org/openapitools/model/ListDto.java
src/main/java/org/openapitools/model/MapTestDto.java
src/main/java/org/openapitools/model/MixedPropertiesAndAdditionalPropertiesClassDto.java
src/main/java/org/openapitools/model/Model200ResponseDto.java
src/main/java/org/openapitools/model/NameDto.java
src/main/java/org/openapitools/model/NullableMapPropertyDto.java
src/main/java/org/openapitools/model/NumberOnlyDto.java
src/main/java/org/openapitools/model/OrderDto.java
src/main/java/org/openapitools/model/OuterCompositeDto.java
src/main/java/org/openapitools/model/OuterEnumDto.java
src/main/java/org/openapitools/model/ParentWithNullableDto.java
src/main/java/org/openapitools/model/PetDto.java
src/main/java/org/openapitools/model/ReadOnlyFirstDto.java
src/main/java/org/openapitools/model/ResponseObjectWithDifferentFieldNamesDto.java
src/main/java/org/openapitools/model/ReturnDto.java
src/main/java/org/openapitools/model/SpecialModelNameDto.java
src/main/java/org/openapitools/model/TagDto.java
src/main/java/org/openapitools/model/TypeHolderDefaultDto.java
src/main/java/org/openapitools/model/TypeHolderExampleDto.java
src/main/java/org/openapitools/model/UserDto.java
src/main/java/org/openapitools/model/XmlItemDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.21.0-SNAPSHOT
Loading