Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .github/workflows/samples-spring-jdk17.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ on:
- samples/server/petstore/springboot-petstore-with-api-response-examples/**
- samples/server/petstore/springboot-sort-validation/**
- samples/server/petstore/springboot-paged-model/**
- samples/server/others/springboot-pre-authorize/**
- samples/openapi3/server/petstore/spring-boot-oneof-sealed/**
- samples/openapi3/server/petstore/spring-boot-oneof-interface/**
- samples/client/petstore/spring-http-interface-oauth/**
Expand All @@ -38,6 +39,7 @@ on:
- samples/server/petstore/springboot-petstore-with-api-response-examples/**
- samples/server/petstore/springboot-sort-validation/**
- samples/server/petstore/springboot-paged-model/**
- samples/server/others/springboot-pre-authorize/**
- samples/openapi3/server/petstore/spring-boot-oneof-sealed/**
- samples/openapi3/server/petstore/spring-boot-oneof-interface/**
- samples/client/petstore/spring-http-interface-oauth/**
Expand Down Expand Up @@ -66,6 +68,7 @@ jobs:
- samples/server/petstore/springboot-petstore-with-api-response-examples
- samples/server/petstore/springboot-sort-validation
- samples/server/petstore/springboot-paged-model
- samples/server/others/springboot-pre-authorize
- samples/openapi3/server/petstore/spring-boot-oneof-sealed
- samples/openapi3/server/petstore/spring-boot-oneof-interface
- samples/client/petstore/spring-http-interface-oauth
Expand Down
40 changes: 40 additions & 0 deletions JavaSpring/libraries/spring-boot/openapi2SpringBoot.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package {{basePackage}};

{{#openApiNullable}}
import com.fasterxml.jackson.databind.Module;
import org.openapitools.jackson.nullable.JsonNullableModule;
{{/openApiNullable}}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
{{#useSpringSecurityPreAuthorize}}
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
{{/useSpringSecurityPreAuthorize}}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;

@SpringBootApplication(
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class
)
@ComponentScan(
basePackages = {"{{basePackage}}", "{{apiPackage}}" , "{{configPackage}}"},
nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class
)
{{#useSpringSecurityPreAuthorize}}
@EnableMethodSecurity
{{/useSpringSecurityPreAuthorize}}
public class OpenApiGeneratorApplication {
public static void main(String[] args) {
SpringApplication.run(OpenApiGeneratorApplication.class, args);
}

{{#openApiNullable}}
@Bean(name = "{{basePackage}}.OpenApiGeneratorApplication.jsonNullableModule")
public Module jsonNullableModule() {
return new JsonNullableModule();
}
{{/openApiNullable}}

}
11 changes: 11 additions & 0 deletions bin/configs/spring-boot-pre-authorize.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
generatorName: spring
outputDir: samples/server/others/springboot-pre-authorize
library: spring-boot
inputSpec: modules/openapi-generator/src/test/resources/3_0/spring/preauthorize-scopes.yaml
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
additionalProperties:
documentationProvider: none
annotationLibrary: none
useSwaggerUI: "false"
useSpringSecurityPreAuthorize: "true"
hideGenerationTimestamp: "true"
2 changes: 2 additions & 0 deletions docs/generators/java-camel.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|sourceFolder|source folder for generated code| |src/main/java|
|springApiVersion|Value for 'version' attribute in @RequestMapping (for Spring 7 and above).| |null|
|springSecurityAuthorityPrefix|Prefix added to OAuth2/OpenID Connect scopes when generating Spring Security authorities.| |SCOPE_|
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation.| |false|
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|title|server title name or client service name| |OpenAPI Spring|
Expand All @@ -131,6 +132,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useSpringBoot4|Generate code and provide dependencies for use with Spring Boot 4.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
|useSpringBuiltInValidation|Disable `@Validated` at the class level when using built-in validation.| |false|
|useSpringController|Annotate the generated API as a Spring Controller| |false|
|useSpringSecurityPreAuthorize|Generate Spring Security @PreAuthorize annotations from OAuth2/OpenID Connect security scopes.| |false|
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|
|useTags|use tags for creating interface and controller classnames| |false|
|virtualService|Generates the virtual service. For more details refer - https://github.com/virtualansoftware/virtualan/wiki| |false|
Expand Down
2 changes: 2 additions & 0 deletions docs/generators/spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|sourceFolder|source folder for generated code| |src/main/java|
|springApiVersion|Value for 'version' attribute in @RequestMapping (for Spring 7 and above).| |null|
|springSecurityAuthorityPrefix|Prefix added to OAuth2/OpenID Connect scopes when generating Spring Security authorities.| |SCOPE_|
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation.| |false|
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|title|server title name or client service name| |OpenAPI Spring|
Expand All @@ -124,6 +125,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useSpringBoot4|Generate code and provide dependencies for use with Spring Boot 4.x. (Use jakarta instead of javax in imports). Enabling this option will also enable `useJakartaEe`.| |false|
|useSpringBuiltInValidation|Disable `@Validated` at the class level when using built-in validation.| |false|
|useSpringController|Annotate the generated API as a Spring Controller| |false|
|useSpringSecurityPreAuthorize|Generate Spring Security @PreAuthorize annotations from OAuth2/OpenID Connect security scopes.| |false|
|useSwaggerUI|Open the OpenApi specification in swagger-ui. Will also import and configure needed dependencies| |true|
|useTags|use tags for creating interface and controller classnames| |false|
|virtualService|Generates the virtual service. For more details refer - https://github.com/virtualansoftware/virtualan/wiki| |false|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ public static enum ENUM_PROPERTY_NAMING_TYPE {camelCase, PascalCase, snake_case,
public static final String X_MODIFIERS = "x-modifiers";
public static final String X_MODIFIER_PREFIX = "x-modifier-";
public static final String X_MODEL_IS_MUTABLE = "x-model-is-mutable";
public static final String X_MODEL_IS_OPERATION_INPUT = "x-model-is-operation-input";
public static final String X_IMPLEMENTS = "x-implements";
public static final String X_IS_ONE_OF_INTERFACE = "x-is-one-of-interface";
public static final String USE_ENUM_VALUE_INTERFACE = "useEnumValueInterface";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Mustache.Lambda;
import com.samskivert.mustache.Template;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.media.Content;
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 lombok.Getter;
import lombok.Setter;
import org.apache.commons.io.FilenameUtils;
Expand Down Expand Up @@ -616,6 +621,7 @@ public ModelsMap postProcessModels(ModelsMap objs) {
@Override
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
final Map<String, ModelsMap> processed = super.postProcessAllModels(objs);
final Set<String> operationInputModels = getOperationInputModels();

Map<String, CodegenModel> enumRefs = new HashMap<>();
for (Map.Entry<String, ModelsMap> entry : processed.entrySet()) {
Expand Down Expand Up @@ -645,6 +651,9 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
continue;
}

if (operationInputModels.contains(entry.getKey()) || operationInputModels.contains(model.schemaName)) {
model.vendorExtensions.put(X_MODEL_IS_OPERATION_INPUT, true);
}
model.vendorExtensions.put(X_MODEL_IS_MUTABLE, modelIsMutable(model, null));

CodegenComposedSchemas composedSchemas = model.getComposedSchemas();
Expand Down Expand Up @@ -718,6 +727,77 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
return processed;
}

private Set<String> getOperationInputModels() {
Set<String> operationInputModels = new HashSet<>();
Set<String> visitedModels = new HashSet<>();
if (openAPI == null || openAPI.getPaths() == null) {
return operationInputModels;
}

for (PathItem pathItem : openAPI.getPaths().values()) {
collectOperationInputModels(pathItem.getParameters(), operationInputModels, visitedModels);
for (Operation operation : pathItem.readOperations()) {
collectOperationInputModels(operation.getParameters(), operationInputModels, visitedModels);
RequestBody requestBody = ModelUtils.getReferencedRequestBody(openAPI, operation.getRequestBody());
if (requestBody != null) {
collectOperationInputModels(requestBody.getContent(), operationInputModels, visitedModels);
}
}
}
return operationInputModels;
}

private void collectOperationInputModels(List<Parameter> parameters, Set<String> operationInputModels, Set<String> visitedModels) {
if (parameters == null) {
return;
}
for (Parameter unresolvedParameter : parameters) {
Parameter parameter = ModelUtils.getReferencedParameter(openAPI, unresolvedParameter);
if (parameter != null) {
collectOperationInputModels(parameter.getSchema(), operationInputModels, visitedModels);
collectOperationInputModels(parameter.getContent(), operationInputModels, visitedModels);
}
}
}

private void collectOperationInputModels(Content content, Set<String> operationInputModels, Set<String> visitedModels) {
if (content == null) {
return;
}
content.values().forEach(mediaType -> collectOperationInputModels(mediaType.getSchema(), operationInputModels, visitedModels));
}

private void collectOperationInputModels(Schema schema, Set<String> operationInputModels, Set<String> visitedModels) {
if (schema == null || Boolean.TRUE.equals(schema.getReadOnly())) {
return;
}
if (schema.get$ref() != null) {
String modelName = ModelUtils.getSimpleRef(schema.get$ref());
operationInputModels.add(modelName);
if (visitedModels.add(modelName)) {
collectOperationInputModels(ModelUtils.getSchema(openAPI, modelName), operationInputModels, visitedModels);
}
}
if (schema.getOneOf() != null) {
schema.getOneOf().forEach(child -> collectOperationInputModels((Schema) child, operationInputModels, visitedModels));
}
if (schema.getAllOf() != null) {
schema.getAllOf().forEach(child -> collectOperationInputModels((Schema) child, operationInputModels, visitedModels));
}
if (schema.getAnyOf() != null) {
schema.getAnyOf().forEach(child -> collectOperationInputModels((Schema) child, operationInputModels, visitedModels));
}
// TODO: Traverse OAS 3.1 schema keywords that can reference operation-input models,
// such as prefixItems, contains, if/then/else, dependentSchemas, and unevaluatedProperties.
collectOperationInputModels(ModelUtils.getSchemaItems(schema), operationInputModels, visitedModels); // in case schema has array type
if (schema.getAdditionalProperties() instanceof Schema) {
collectOperationInputModels((Schema) schema.getAdditionalProperties(), operationInputModels, visitedModels);
}
if (schema.getProperties() != null) {
schema.getProperties().values().forEach(property -> collectOperationInputModels((Schema) property, operationInputModels, visitedModels));
}
}

/**
* Returns true if the model contains any properties with a public setter
* If true, the model's constructor accessor should be made public to ensure end users
Expand Down
Loading
Loading