├── .gitignore ├── README.md ├── api-codegen ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── likelen │ │ └── codegen │ │ └── spring │ │ └── CustomSpringCodeGenerator.java │ └── resources │ ├── META-INF │ └── services │ │ └── org.openapitools.codegen.CodegenConfig │ └── custom-codegen │ ├── api.mustache │ ├── bodyParams.mustache │ ├── cookieParams.mustache │ ├── formParams.mustache │ ├── headerParams.mustache │ ├── model.mustache │ ├── pathParams.mustache │ ├── pojo.mustache │ └── queryParams.mustache ├── api-mockserver ├── build.gradle └── src │ └── main │ ├── java │ └── com │ │ └── likelen │ │ └── openapi │ │ └── mockserver │ │ └── Main.java │ └── resources │ └── openapi.yaml ├── app ├── build.gradle └── src │ └── main │ ├── codegen-config │ ├── .gitignore │ ├── api-order-contract.yaml │ └── config.json │ ├── java │ └── com │ │ └── likelen │ │ └── openapi │ │ ├── Application.java │ │ └── controller │ │ └── OrderController.java │ └── resources │ └── hello.yaml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store 43 | /app/src/main/swagger-generated/ 44 | /.idea/ 45 | /app/src/main/openapi-generated/ 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # openapi-codegen-demo 2 | 3 | 해당 openapi-generator 에서 제공하는 spring-boot Codegen 을 커스텀한 Repository 입니다. 4 | 5 | 6 | 7 | ## 구성 8 | 9 | - api-codegen(Java Version 11) 10 | 11 | api-codegen 은 기존에 제공하던 [OPEN API codegenerator](https://openapi-generator.tech/) 를 Custom 한 모듈입니다. 문자열 템플릿 [mustache](https://mustache.github.io/) 에 대한 설정은 api-codegen/src/main/resources/custom-codegen 을 통해 확인하실 수 있습니다. 12 | 13 | - api-mockserver(Java Version 11) 14 | 15 | API 계약서(openapi.yaml) 기반으로 가짜 서버를 동작 시킬 수 있는 모듈입니다. 자세한 내용은 [MockServer Using OpenAPI](https://www.mock-server.com/mock_server/using_openapi.html) 에서 확인하실 수 있습니다. 16 | 17 | - app(Java Version 11) 18 | 19 | API 계약서를 설계하여 실제로 동작하는 애플리케이션이 동작하는 모듈입니다. 20 | 21 | 22 | 23 | ## How to run CodeGen 24 | 25 | 1. `./gradlew :api-codegen:build` 26 | 27 | api-codegen 모듈을 Build 합니다. 28 | 29 | 2. `./gradlew clean :app:build` 30 | 31 | openapi-generated 폴더가 생성되었음을 확인할 수 있습니다. 32 | 33 | > 주의! 34 | > 35 | > api-codegen build 를 먼저 실행 후, app 모듈의 코드를 빌드해야만 합니다. 36 | 37 | 38 | 39 | ## How to run Mockserver 40 | 41 | `./gradlew :api-mockserver:run` 42 | 43 | http://localhost:8085/apis/orders 에 접속하여 Mock Server 가 동작함을 확인할 수 있습니다. 44 | 45 | ## How to run App 46 | 47 | ` ./gradlew :app:bootRun` 48 | 49 | http://localhost:8080/apis/orders 에 접속하여 App 이 동작함을 확인할 수 있습니다. 50 | 51 | > 주의! 52 | > 53 | > api-codegen build 를 먼저 실행 후, app 모듈의 코드를 실행해야만 합니다. 54 | 55 | ###### 56 | 57 | ## API FIRST DESIGN 개발 프로세스 58 | 59 | 1. API 명세를 기반으로 API 계약서를 설계 한다. 60 | - app/src/main/codegen-config/api-order-contract.yml 에서 API 설계한 내용을 찾을 수 있습니다. 61 | 2. 설계된 API 계약서를 기반으로 이해관계자와 토론과 공유를 한다. 62 | 3. Open API 도구를 활용하여(여기서는 Code Generator) 코드를 구현한다. 63 | 4. API 문서를 관심있어 하는 이해관계자에게 전달한다. 64 | 65 | 66 | 만약, API 명세가 변경됨에 따른 프로세스는 다음과 같습니다. 67 | 68 | 1. API 명세가 담긴 API 계약서에서 변경할 API 의 내용을 변경한다. 69 | 2. 변경된 API 계약서를 기반으로 다시 Code Generator 를 실행한다. 70 | 3. API 가 변경되어 구현되지 않은 부분을 구현한다. -------------------------------------------------------------------------------- /api-codegen/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java-library' 3 | } 4 | 5 | 6 | repositories { 7 | mavenCentral() 8 | } 9 | 10 | tasks.withType(JavaCompile) { 11 | options.encoding = 'UTF-8' 12 | sourceCompatibility = '1.8' 13 | targetCompatibility = '1.8' 14 | } 15 | 16 | 17 | dependencies { 18 | 19 | implementation "org.openapitools:openapi-generator:6.6.0" 20 | 21 | } -------------------------------------------------------------------------------- /api-codegen/src/main/java/com/likelen/codegen/spring/CustomSpringCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package com.likelen.codegen.spring; 2 | 3 | import io.swagger.v3.oas.models.media.Schema; 4 | import org.openapitools.codegen.CodegenModel; 5 | import org.openapitools.codegen.languages.SpringCodegen; 6 | 7 | public class CustomSpringCodeGenerator extends SpringCodegen { 8 | 9 | 10 | public CustomSpringCodeGenerator() { 11 | super(); 12 | templateDir = "custom-codegen"; 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "custom-codegen"; 18 | } 19 | 20 | @Override 21 | public void processOpts() { 22 | super.processOpts(); 23 | // imports for pojos 24 | importMapping.remove("ApiModelProperty"); 25 | importMapping.remove("ApiModel"); 26 | } 27 | 28 | @Override 29 | public CodegenModel fromModel(String name, Schema model) { 30 | super.fromModel(name, model); 31 | CodegenModel codegenModel = super.fromModel(name, model); 32 | codegenModel.imports.remove("ApiModel"); 33 | codegenModel.imports.remove("ApiModelProperty"); 34 | return codegenModel; 35 | } 36 | 37 | 38 | } -------------------------------------------------------------------------------- /api-codegen/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig: -------------------------------------------------------------------------------- 1 | com.likelen.codegen.spring.CustomSpringCodeGenerator -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/api.mustache: -------------------------------------------------------------------------------- 1 | /** 2 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) ({{{generatorVersion}}}). 3 | * https://openapi-generator.tech 4 | * Do not edit the class manually. 5 | */ 6 | package {{package}}; 7 | 8 | {{#imports}}import {{import}}; 9 | {{/imports}} 10 | 11 | {{#jdk8-no-delegate}} 12 | {{#virtualService}} 13 | import io.virtualan.annotation.ApiVirtual; 14 | import io.virtualan.annotation.VirtualService; 15 | {{/virtualService}} 16 | import org.springframework.http.HttpStatus; 17 | import org.springframework.http.MediaType; 18 | {{/jdk8-no-delegate}} 19 | import org.springframework.http.ResponseEntity; 20 | {{#useBeanValidation}} 21 | import org.springframework.validation.annotation.Validated; 22 | {{/useBeanValidation}} 23 | {{#vendorExtensions.x-spring-paginated}} 24 | import org.springframework.data.domain.Pageable; 25 | {{/vendorExtensions.x-spring-paginated}} 26 | import org.springframework.web.bind.annotation.*; 27 | {{#jdk8-no-delegate}} 28 | {{^reactive}} 29 | import org.springframework.web.context.request.NativeWebRequest; 30 | {{/reactive}} 31 | {{/jdk8-no-delegate}} 32 | import org.springframework.web.multipart.MultipartFile; 33 | {{#reactive}} 34 | import org.springframework.web.server.ServerWebExchange; 35 | import reactor.core.publisher.Flux; 36 | import reactor.core.publisher.Mono; 37 | import org.springframework.http.codec.multipart.Part; 38 | {{/reactive}} 39 | 40 | 41 | {{#useBeanValidation}} 42 | import javax.validation.Valid; 43 | import javax.validation.constraints.*; 44 | {{/useBeanValidation}} 45 | import java.util.List; 46 | import java.util.Map; 47 | {{#jdk8-no-delegate}} 48 | import java.util.Optional; 49 | {{/jdk8-no-delegate}} 50 | {{^jdk8-no-delegate}} 51 | {{#useOptional}} 52 | import java.util.Optional; 53 | {{/useOptional}} 54 | {{/jdk8-no-delegate}} 55 | {{#async}} 56 | import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture{{/jdk8}}; 57 | {{/async}} 58 | {{#useBeanValidation}} 59 | @Validated 60 | {{/useBeanValidation}} 61 | 62 | {{#operations}} 63 | {{#virtualService}} 64 | @VirtualService 65 | {{/virtualService}} 66 | @RestController 67 | public interface {{classname}} { 68 | {{#jdk8-default-interface}} 69 | {{^isDelegate}} 70 | {{^reactive}} 71 | 72 | default Optional getRequest() { 73 | return Optional.empty(); 74 | } 75 | {{/reactive}} 76 | {{/isDelegate}} 77 | {{#isDelegate}} 78 | 79 | default {{classname}}Delegate getDelegate() { 80 | return new {{classname}}Delegate() {}; 81 | } 82 | {{/isDelegate}} 83 | {{/jdk8-default-interface}} 84 | {{#operation}} 85 | 86 | /** 87 | * {{httpMethod}} {{{path}}}{{#summary}} : {{.}}{{/summary}} 88 | {{#notes}} 89 | * {{.}} 90 | {{/notes}} 91 | * 92 | {{#allParams}} 93 | * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}} 94 | {{/allParams}} 95 | * @return {{#responses}}{{message}} (status code {{code}}){{^-last}} 96 | * or {{/-last}}{{/responses}} 97 | {{#isDeprecated}} 98 | * @deprecated 99 | {{/isDeprecated}} 100 | {{#externalDocs}} 101 | * {{description}} 102 | * @see {{summary}} Documentation 103 | {{/externalDocs}} 104 | */ 105 | {{#virtualService}} 106 | 107 | {{/virtualService}} 108 | 109 | @{{#lambda.titlecase}}{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}{{/lambda.titlecase}}Mapping( 110 | value = "{{{path}}}"{{#singleContentTypes}}{{#hasProduces}}, 111 | produces = "{{{vendorExtensions.x-accepts}}}"{{/hasProduces}}{{#hasConsumes}}, 112 | consumes = "{{{vendorExtensions.x-contentType}}}"{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}, 113 | produces = { {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} }{{/hasProduces}}{{#hasConsumes}}, 114 | consumes = { {{#consumes}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/consumes}} }{{/hasConsumes}}{{/singleContentTypes}} 115 | ) 116 | {{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{^-last}},{{/-last}}{{#-last}}{{#reactive}}, {{/reactive}}{{/-last}}{{/allParams}}{{#reactive}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{^jdk8-default-interface}};{{/jdk8-default-interface}}{{#jdk8-default-interface}}{{#unhandledException}} throws Exception{{/unhandledException}} { 117 | {{#delegate-method}} 118 | return {{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, pageable{{/vendorExtensions.x-spring-paginated}}); 119 | } 120 | 121 | // Override this method 122 | {{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} { 123 | {{/delegate-method}} 124 | {{^isDelegate}} 125 | {{>methodBody}} 126 | {{/isDelegate}} 127 | {{#isDelegate}} 128 | return getDelegate().{{operationId}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}, pageable{{/vendorExtensions.x-spring-paginated}}); 129 | {{/isDelegate}} 130 | }{{/jdk8-default-interface}} 131 | 132 | {{/operation}} 133 | } 134 | {{/operations}} 135 | -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/bodyParams.mustache: -------------------------------------------------------------------------------- 1 | {{#isBodyParam}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody{{^required}}(required = false){{/required}} {{^reactive}}{{{dataType}}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isBodyParam}} -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/cookieParams.mustache: -------------------------------------------------------------------------------- 1 | {{#isCookieParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}} @CookieValue("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isCookieParam}} -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/formParams.mustache: -------------------------------------------------------------------------------- 1 | {{#isFormParam}}{{^isFile}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{{dataType}}} {{paramName}}{{/isFile}}{{#isFile}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#isArray}}List<{{/isArray}}{{#reactive}}Flux{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{#isArray}}>{{/isArray}} {{baseName}}{{/isFile}}{{/isFormParam}} -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/headerParams.mustache: -------------------------------------------------------------------------------- 1 | {{#isHeaderParam}}@RequestHeader(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{>optionalDataType}} {{paramName}}{{/isHeaderParam}} -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/model.mustache: -------------------------------------------------------------------------------- 1 | package {{package}}; 2 | 3 | import java.util.Objects; 4 | {{#imports}}import {{import}}; 5 | {{/imports}} 6 | {{#openApiNullable}} 7 | import org.openapitools.jackson.nullable.JsonNullable; 8 | {{/openApiNullable}} 9 | {{#serializableModel}} 10 | import java.io.Serializable; 11 | {{/serializableModel}} 12 | {{#useBeanValidation}} 13 | import javax.validation.Valid; 14 | import javax.validation.constraints.*; 15 | {{/useBeanValidation}} 16 | {{#performBeanValidation}} 17 | import org.hibernate.validator.constraints.*; 18 | {{/performBeanValidation}} 19 | {{#jackson}} 20 | {{#withXml}} 21 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; 22 | import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; 23 | {{/withXml}} 24 | {{/jackson}} 25 | {{#withXml}} 26 | import javax.xml.bind.annotation.*; 27 | {{/withXml}} 28 | {{^parent}} 29 | {{#hateoas}} 30 | import org.springframework.hateoas.RepresentationModel; 31 | {{/hateoas}} 32 | {{/parent}} 33 | 34 | {{#models}} 35 | {{#model}} 36 | {{#isEnum}} 37 | {{>enumOuterClass}} 38 | {{/isEnum}} 39 | {{^isEnum}} 40 | {{>pojo}} 41 | {{/isEnum}} 42 | {{/model}} 43 | {{/models}} 44 | -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/pathParams.mustache: -------------------------------------------------------------------------------- 1 | {{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}@PathVariable("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isPathParam}} -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/pojo.mustache: -------------------------------------------------------------------------------- 1 | /** 2 | * {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} 3 | */{{#description}} 4 | //{{{description}}} 5 | {{/description}} 6 | {{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}}{{>additionalModelTypeAnnotations}} 7 | public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}}{{^parent}}{{#hateoas}}extends RepresentationModel<{{classname}}> {{/hateoas}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { 8 | {{#serializableModel}} 9 | private static final long serialVersionUID = 1L; 10 | 11 | {{/serializableModel}} 12 | {{#vars}} 13 | {{#isEnum}} 14 | {{^isContainer}} 15 | {{>enumClass}} 16 | {{/isContainer}} 17 | {{#isContainer}} 18 | {{#mostInnerItems}} 19 | {{>enumClass}} 20 | {{/mostInnerItems}} 21 | {{/isContainer}} 22 | {{/isEnum}} 23 | {{#jackson}} 24 | @JsonProperty("{{baseName}}"){{#withXml}} 25 | @JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}"){{/withXml}} 26 | {{/jackson}} 27 | {{#gson}} 28 | @SerializedName("{{baseName}}") 29 | {{/gson}} 30 | {{#isContainer}} 31 | {{#useBeanValidation}}@Valid{{/useBeanValidation}} 32 | {{#openApiNullable}} 33 | private {{>nullableDataType}} {{name}} = {{#isNullable}}JsonNullable.undefined(){{/isNullable}}{{^isNullable}}{{#required}}{{{defaultValue}}}{{/required}}{{^required}}null{{/required}}{{/isNullable}}; 34 | {{/openApiNullable}} 35 | {{^openApiNullable}} 36 | private {{>nullableDataType}} {{name}} = {{#required}}{{{defaultValue}}}{{/required}}{{^required}}null{{/required}}; 37 | {{/openApiNullable}} 38 | {{/isContainer}} 39 | {{^isContainer}} 40 | {{#isDate}} 41 | @org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE) 42 | {{/isDate}} 43 | {{#isDateTime}} 44 | @org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME) 45 | {{/isDateTime}} 46 | {{#openApiNullable}} 47 | private {{>nullableDataType}} {{name}}{{#isNullable}} = JsonNullable.undefined(){{/isNullable}}{{^isNullable}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}{{/isNullable}}; 48 | {{/openApiNullable}} 49 | {{^openApiNullable}} 50 | private {{>nullableDataType}} {{name}}{{#isNullable}} = null{{/isNullable}}{{^isNullable}}{{#defaultValue}} = {{{.}}}{{/defaultValue}}{{/isNullable}}; 51 | {{/openApiNullable}} 52 | {{/isContainer}} 53 | 54 | {{/vars}} 55 | {{#vars}} 56 | public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) { 57 | {{#openApiNullable}} 58 | this.{{name}} = {{#isNullable}}JsonNullable.of({{name}}){{/isNullable}}{{^isNullable}}{{name}}{{/isNullable}}; 59 | {{/openApiNullable}} 60 | {{^openApiNullable}} 61 | this.{{name}} = {{name}}; 62 | {{/openApiNullable}} 63 | return this; 64 | } 65 | {{#isArray}} 66 | 67 | public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) { 68 | {{#openApiNullable}} 69 | {{^required}} 70 | if (this.{{name}} == null{{#isNullable}} || !this.{{name}}.isPresent(){{/isNullable}}) { 71 | this.{{name}} = {{#isNullable}}JsonNullable.of({{{defaultValue}}}){{/isNullable}}{{^isNullable}}{{{defaultValue}}}{{/isNullable}}; 72 | } 73 | {{/required}} 74 | this.{{name}}{{#isNullable}}.get(){{/isNullable}}.add({{name}}Item); 75 | {{/openApiNullable}} 76 | {{^openApiNullable}} 77 | if (this.{{name}} == null) { 78 | this.{{name}} = {{{defaultValue}}}; 79 | } 80 | this.{{name}}.add({{name}}Item); 81 | {{/openApiNullable}} 82 | return this; 83 | } 84 | {{/isArray}} 85 | {{#isMap}} 86 | 87 | public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) { 88 | {{^required}} 89 | if (this.{{name}} == null) { 90 | this.{{name}} = {{{defaultValue}}}; 91 | } 92 | {{/required}} 93 | this.{{name}}.put(key, {{name}}Item); 94 | return this; 95 | } 96 | {{/isMap}} 97 | 98 | /** 99 | {{#description}} 100 | * {{{description}}} 101 | {{/description}} 102 | {{^description}} 103 | * Get {{name}} 104 | {{/description}} 105 | {{#minimum}} 106 | * minimum: {{minimum}} 107 | {{/minimum}} 108 | {{#maximum}} 109 | * maximum: {{maximum}} 110 | {{/maximum}} 111 | * @return {{name}} 112 | */ 113 | {{#vendorExtensions.x-extra-annotation}} 114 | {{{vendorExtensions.x-extra-annotation}}} 115 | {{/vendorExtensions.x-extra-annotation}} 116 | 117 | {{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{>nullableDataType}} {{getter}}() { 118 | return {{name}}; 119 | } 120 | 121 | public void {{setter}}({{>nullableDataType}} {{name}}) { 122 | this.{{name}} = {{name}}; 123 | } 124 | 125 | {{/vars}} 126 | 127 | @Override 128 | public boolean equals(Object o) { 129 | if (this == o) { 130 | return true; 131 | } 132 | if (o == null || getClass() != o.getClass()) { 133 | return false; 134 | }{{#hasVars}} 135 | {{classname}} {{classVarName}} = ({{classname}}) o; 136 | return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} && 137 | {{/-last}}{{/vars}}{{#parent}} && 138 | super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}} 139 | return true;{{/hasVars}} 140 | } 141 | 142 | @Override 143 | public int hashCode() { 144 | return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}); 145 | } 146 | 147 | @Override 148 | public String toString() { 149 | StringBuilder sb = new StringBuilder(); 150 | sb.append("class {{classname}} {\n"); 151 | {{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}} 152 | {{#vars}}sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n"); 153 | {{/vars}}sb.append("}"); 154 | return sb.toString(); 155 | } 156 | 157 | /** 158 | * Convert the given object to string with each line indented by 4 spaces 159 | * (except the first line). 160 | */ 161 | private String toIndentedString(Object o) { 162 | if (o == null) { 163 | return "null"; 164 | } 165 | return o.toString().replace("\n", "\n "); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /api-codegen/src/main/resources/custom-codegen/queryParams.mustache: -------------------------------------------------------------------------------- 1 | {{#isQueryParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}} {{#useBeanValidation}}@Valid{{/useBeanValidation}}{{^isModel}} @RequestParam(value = {{#isMap}}""{{/isMap}}{{^isMap}}"{{baseName}}"{{/isMap}}{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{^isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}{{/isContainer}}){{/isModel}}{{#isDate}} @org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE){{/isDate}}{{#isDateTime}} @org.springframework.format.annotation.DateTimeFormat(iso = org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME){{/isDateTime}} {{>optionalDataType}} {{paramName}}{{/isQueryParam}} -------------------------------------------------------------------------------- /api-mockserver/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'application' 4 | } 5 | 6 | mainClassName ='com.likelen.openapi.mockserver.Main' 7 | group = 'com.likelen.openapi.mockserver' 8 | 9 | group 'org.example' 10 | version '1.0-SNAPSHOT' 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | 16 | dependencies { 17 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' 18 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' 19 | implementation 'org.mock-server:mockserver-netty:5.11.1' 20 | 21 | } 22 | 23 | test { 24 | useJUnitPlatform() 25 | } 26 | -------------------------------------------------------------------------------- /api-mockserver/src/main/java/com/likelen/openapi/mockserver/Main.java: -------------------------------------------------------------------------------- 1 | package com.likelen.openapi.mockserver; 2 | 3 | import org.mockserver.integration.ClientAndServer; 4 | import org.mockserver.mock.OpenAPIExpectation; 5 | 6 | class Main { 7 | 8 | public static void main(String[] args) { 9 | ClientAndServer mockServer = ClientAndServer.startClientAndServer(8085); 10 | mockServer.upsert( 11 | OpenAPIExpectation 12 | .openAPIExpectation("openapi.yaml") 13 | ); 14 | 15 | System.out.println("MockServer Ready."); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /api-mockserver/src/main/resources/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.0" 2 | info: 3 | version: 0.0.1 4 | title: Orders 5 | paths: 6 | /apis/orders: 7 | get: 8 | summary: 특정 유저의 모든 주문내역을 조회합니다. 9 | operationId: showAllOrdersByUsers 10 | tags: 11 | - order 12 | parameters: 13 | - in: query 14 | name: v 15 | schema: 16 | type: string 17 | example: '0.0.2' 18 | description: The version of api 19 | - in: query 20 | name: user 21 | schema: 22 | type: string 23 | example: '123456-2222123' 24 | description: "user name" 25 | - in: query 26 | name: detail 27 | schema: 28 | type: string 29 | example: '얼굴이 동그라미' 30 | description: "user detail" 31 | responses: 32 | '200': 33 | description: 모든 주문 내역을 반환 합니다. 34 | content: 35 | application/json: 36 | schema: 37 | type: array 38 | items: 39 | $ref: '#/components/schemas/SubscriptionOrdersModel' 40 | '400': 41 | description: unexpected error 42 | content: 43 | application/json: 44 | schema: 45 | $ref: '#/components/schemas/Error' 46 | components: 47 | schemas: 48 | SubscriptionOrdersModel: 49 | type: 'object' 50 | properties: 51 | id: 52 | type: 'string' 53 | description: 'orderId' 54 | example: '246523764' 55 | subscriptionId: 56 | type: 'string' 57 | description: '정기 결제가 진행된 구독 ID 입니다' 58 | example: 'ad4d8bed-1967-4e68-af97-290ca710c2f6_3647777233' 59 | result: 60 | type: 'string' 61 | example: "SUCCESS | FAILED" 62 | description: '여부 실패시, additionalProperties 에 failedReason 포함됨' 63 | userId: 64 | type: 'string' 65 | example: 'ad4d8bed-1967-4e68-af97-290ca710c2f6' 66 | orderId: 67 | type: 'string' 68 | example: 'order-2312355' 69 | description: 'PG 에서 확인할 수 있는 고유 결제 ID' 70 | paidAt: 71 | type: 'string' 72 | example: "2022-08-11" 73 | description: '결제일을 확인할 수 있다.' 74 | refundedAt: 75 | type: 'string' 76 | example: "2022-08-09" 77 | description: '결제일을 확인할 수 있다.' 78 | additionalProperties: 79 | additionalProperties: 80 | $ref: '#/components/schemas/StringMap' 81 | type: object 82 | description: '추가 되어질 수 있는 내역 담기' 83 | Error: 84 | required: 85 | - value 86 | properties: 87 | description: 88 | type: 'string' 89 | example: '적절하지 않은 값입니다.' 90 | StringMap: 91 | type: string 92 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | import org.openapitools.generator.gradle.plugin.tasks.GenerateTask 2 | buildscript { 3 | 4 | dependencies { 5 | classpath project(':api-codegen') 6 | } 7 | } 8 | 9 | plugins { 10 | id "org.openapi.generator" version "6.6.0" 11 | } 12 | 13 | plugins { 14 | id 'java-library' 15 | id 'org.springframework.boot' version '2.4.1' 16 | id 'io.spring.dependency-management' version '1.0.10.RELEASE' 17 | id 'idea' 18 | 19 | } 20 | 21 | group = 'com.likelen.openapi-demo' 22 | version = '1.0-SNAPSHOT' 23 | sourceCompatibility = '11' 24 | 25 | repositories { 26 | mavenCentral() 27 | } 28 | 29 | dependencies { 30 | implementation 'org.springframework.boot:spring-boot-starter-web' 31 | 32 | compileOnly 'io.swagger:swagger-annotations:1.6.2' 33 | compileOnly 'jakarta.validation:jakarta.validation-api:2.0.2' 34 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 35 | 36 | testImplementation 'org.mock-server:mockserver-netty:5.14.0' 37 | } 38 | 39 | test { 40 | useJUnitPlatform() 41 | } 42 | 43 | test { 44 | useJUnitPlatform() 45 | } 46 | 47 | def swaggerRoot = "$projectDir/src/main/codegen-config".toString() 48 | def swaggerAPIOutput = "$projectDir/src/main".toString() 49 | 50 | openApiValidate { 51 | inputSpec="$swaggerRoot/api-order-contract.yaml".toString() 52 | recommend=true 53 | } 54 | 55 | openApiGenerate { 56 | inputSpec="$swaggerRoot/api-order-contract.yaml".toString() 57 | generatorName = "custom-codegen" 58 | configFile= "$swaggerRoot/config.json".toString() 59 | outputDir= "$swaggerAPIOutput".toString() 60 | configOptions = [ 61 | "sourceFolder" : "openapi-generated" 62 | ] 63 | } 64 | 65 | tasks.named("openApiGenerate") { 66 | 67 | it.doLast { 68 | delete "$projectDir/src/main/pom.xml" 69 | delete "$projectDir/src/main/README.md" 70 | delete "$projectDir/src/main/.openapi-generator-ignore" 71 | delete "$projectDir/src/main/.openapi-generator" 72 | delete "$projectDir/src/main/resources" + "/" + "swagger" 73 | 74 | } 75 | } 76 | 77 | 78 | task openApiYmlGenerate(type: GenerateTask){ 79 | inputSpec="$swaggerRoot/api-order-contract.yaml".toString() 80 | generatorName = "openapi-yaml".toString() 81 | outputDir= "$swaggerAPIOutput/resources/swagger/".toString() 82 | configOptions = [ 83 | outputFile: "openapi.yml" 84 | ] 85 | 86 | def outputDir = "$projectDir/src/main/resources" 87 | it.doLast { 88 | delete outputDir + "/" + "swagger" 89 | } 90 | } 91 | 92 | tasks.openApiGenerate.dependsOn tasks.openApiValidate 93 | tasks.compileJava.dependsOn tasks.openApiGenerate, tasks.openApiYmlGenerate 94 | sourceSets.main.java.srcDir "${openApiGenerate.outputDir.get()}/${openApiGenerate.configOptions['sourceFolder'].get()}" 95 | sourceSets.main.resources.srcDir "${openApiGenerate.outputDir.get()}/src/main/resources" 96 | -------------------------------------------------------------------------------- /app/src/main/codegen-config/.gitignore: -------------------------------------------------------------------------------- 1 | .generated -------------------------------------------------------------------------------- /app/src/main/codegen-config/api-order-contract.yaml: -------------------------------------------------------------------------------- 1 | openapi: "3.0.0" 2 | info: 3 | version: 0.0.1 4 | title: Orders 5 | paths: 6 | /apis/orders: 7 | get: 8 | summary: 특정 유저의 모든 주문내역을 조회합니다. 9 | operationId: showAllOrdersByUsers 10 | tags: 11 | - order 12 | parameters: 13 | - in: query 14 | name: v 15 | schema: 16 | type: string 17 | example: '0.0.2' 18 | description: The version of api 19 | - in: query 20 | name: user 21 | schema: 22 | type: string 23 | example: '123456-2222123' 24 | description: "user name" 25 | - in: query 26 | name: detail 27 | schema: 28 | type: string 29 | example: '얼굴이 동그라미' 30 | description: "user detail" 31 | responses: 32 | '200': 33 | description: 모든 주문 내역을 반환 합니다. 34 | content: 35 | application/json: 36 | schema: 37 | type: array 38 | items: 39 | $ref: '#/components/schemas/SubscriptionOrdersModel' 40 | '400': 41 | description: unexpected error 42 | content: 43 | application/json: 44 | schema: 45 | $ref: '#/components/schemas/Error' 46 | components: 47 | schemas: 48 | SubscriptionOrdersModel: 49 | type: 'object' 50 | properties: 51 | id: 52 | type: 'string' 53 | description: 'orderId' 54 | example: '246523764' 55 | subscriptionId: 56 | type: 'string' 57 | description: '정기 결제가 진행된 구독 ID 입니다' 58 | example: 'ad4d8bed-1967-4e68-af97-290ca710c2f6_3647777233' 59 | result: 60 | type: 'string' 61 | example: "SUCCESS | FAILED" 62 | description: '여부 실패시, additionalProperties 에 failedReason 포함됨' 63 | userId: 64 | type: 'string' 65 | example: 'ad4d8bed-1967-4e68-af97-290ca710c2f6' 66 | orderId: 67 | type: 'string' 68 | example: 'order-2312355' 69 | description: 'PG 에서 확인할 수 있는 고유 결제 ID' 70 | paidAt: 71 | type: 'string' 72 | example: "2022-08-11" 73 | description: '결제일을 확인할 수 있다.' 74 | refundedAt: 75 | type: 'string' 76 | example: "2022-08-09" 77 | description: '결제일을 확인할 수 있다.' 78 | additionalProperties: 79 | additionalProperties: 80 | $ref: '#/components/schemas/StringMap' 81 | type: object 82 | description: '추가 되어질 수 있는 내역 담기' 83 | Error: 84 | required: 85 | - value 86 | properties: 87 | description: 88 | type: 'string' 89 | example: '적절하지 않은 값입니다.' 90 | StringMap: 91 | type: string 92 | -------------------------------------------------------------------------------- /app/src/main/codegen-config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "library": "spring-boot", 4 | "interfaceOnly" : true, 5 | "basePackage" : "com.likelen.openapi", 6 | "configPackage" : "example.api.config", 7 | "modelPackage": "com.likelen.openapi.models", 8 | "apiPackage": "com.likelen.openapi.apis", 9 | "invokerPackage": "com.likelen.openapi.apis", 10 | "useTags" : true, 11 | "skipDefaultInterface" : true, 12 | "dateLibrary": "java8", 13 | "useBeanValidation" : true, 14 | "serializableModel" : true, 15 | "implicitHeaders" : false, 16 | "swaggerDocketConfig": false, 17 | "hideGenerationTimestamp": true, 18 | 19 | "useSpringfox": false, 20 | "reactive": false, 21 | "openApiNullable" : false 22 | 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/likelen/openapi/Application.java: -------------------------------------------------------------------------------- 1 | package com.likelen.openapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/likelen/openapi/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.likelen.openapi.controller; 2 | 3 | import com.likelen.openapi.apis.OrderApi; 4 | import com.likelen.openapi.models.SubscriptionOrdersModel; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @RestController 12 | class OrderController implements OrderApi { 13 | 14 | @Override 15 | public ResponseEntity> showAllOrdersByUsers(String v, String user, String detail) { 16 | List body = new ArrayList<>(); 17 | //something working 18 | return ResponseEntity.ok(body); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/resources/hello.yaml: -------------------------------------------------------------------------------- 1 | infcon: 2 | name: 인프콘 3 | year: 2023 4 | description: 인프런이 만드는 IT인의 축제 5 | 6 | speaker: 7 | title: 오늘도 여러분의 API는 안녕하신가요? 8 | name: len 9 | description: 작은 발걸음의 연속으로 큰 변화를 만들어내는 것을 좋아합니다. 10 | where: 코엑스 105호 11 | time: 11:40 - 12:20 (40분) 12 | target: 13 | - 주니어 14 | - 아키텍처 15 | 16 | 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LenKIM/openapi-code-gen/14c1bb3d325ae22980087ee447e1530bf642a08c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Aug 05 12:08:21 KST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'openapi-codegen-demo' 2 | 3 | include("api-codegen") 4 | include("api-mockserver") 5 | include("app") 6 | 7 | 8 | --------------------------------------------------------------------------------