From 2215a03059c424f4fd8cb9e32a94b68ae254c55b Mon Sep 17 00:00:00 2001 From: Tatiana Fesenko Date: Thu, 20 Sep 2018 10:23:36 -0400 Subject: [PATCH 01/11] Add GenTarget for "Java Spring (Boot + MVC + CloudFeign) Server" --- ...pring (Boot + MVC + CloudFeign) Server.gen | 160 ++++++++++++++++++ .../build.gradle | 33 ++++ .../pom.xml | 67 ++++++++ 3 files changed, 260 insertions(+) create mode 100644 Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen create mode 100644 Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/build.gradle create mode 100644 Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/pom.xml diff --git a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen new file mode 100644 index 0000000..2c9a28f --- /dev/null +++ b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen @@ -0,0 +1,160 @@ +--- +name: "Java Spring (Boot + MVC + CloudFeign) Server" +genTemplateId: "com.modelsolv.reprezen.gentemplates.openapi.generator.SpringCodegen" +relativeOutputDir: generated +prerequisites: null +primarySource: + path: "../../../models/petstore-expanded.yaml" +namedSources: null +# The parameters object contains variables that are processed directly by the GenTemplate. +parameters: + # Sort method arguments to place required parameters before optional parameters. + sortParamsByRequiredFlag: null + + # Whether to ensure parameter names are unique in an operation (rename parameters that are not). + ensureUniqueParams: null + + # boolean, toggles whether unicode identifiers are allowed in names or not, default is false + allowUnicodeIdentifiers: null + + # Add form or body parameters to the beginning of the parameter list. + prependFormOrBodyParameters: null + + # package for generated models + modelPackage: null + + # package for generated api classes + apiPackage: null + + # root package for generated code + invokerPackage: null + + # groupId in generated pom.xml + groupId: null + + # artifactId in generated pom.xml + artifactId: null + + # artifact version in generated pom.xml + artifactVersion: null + + # artifact URL in generated pom.xml + artifactUrl: null + + # artifact description in generated pom.xml + artifactDescription: null + + # SCM connection in generated pom.xml + scmConnection: null + + # SCM developer connection in generated pom.xml + scmDeveloperConnection: null + + # SCM URL in generated pom.xml + scmUrl: null + + # developer name in generated pom.xml + developerName: null + + # developer email in generated pom.xml + developerEmail: null + + # developer organization in generated pom.xml + developerOrganization: null + + # developer organization URL in generated pom.xml + developerOrganizationUrl: null + + # The name of the license + licenseName: null + + # The URL of the license + licenseUrl: null + + # source folder for generated code + sourceFolder: null + + # prefix for generated code members and local variables + localVariablePrefix: null + + # boolean - toggle "implements Serializable" for generated models + serializableModel: null + + # Treat BigDecimal values as Strings to avoid precision loss. + bigDecimalAsString: null + + # whether to use fully qualified name for classes under java.util. This option only works for Java API client + fullJavaUtil: null + + # hides the timestamp when files were generated + hideGenerationTimestamp: null + + # whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML) + withXml: null + + # Option. Date library to use + dateLibrary: null + + # Option. Use Java8 classes instead of third party equivalents + java8: null + + # server title name or client service name + title: null + + # configuration package for generated code + configPackage: null + + # base package (invokerPackage) for generated code + basePackage: null + + # Whether to generate only API interface stubs without the server files. + interfaceOnly: null + + # Whether to generate the server files using the delegate pattern + delegatePattern: null + + # Whether to select only one produces/consumes content-type by operation. + singleContentTypes: null + + # use async Callable controllers + async: null + + # wrap responses in Mono/Flux Reactor types (spring-boot only) + reactive: null + + # wrap the responses in given type (Future,Callable,CompletableFuture,ListenableFuture,DeferredResult,HystrixCommand,RxObservable,RxSingle or fully qualified type) + responseWrapper: null + + # use tags for creating interface and controller classnames + useTags: null + + # Use BeanValidation API annotations + useBeanValidation: null + + # Use of @ApiImplicitParams for headers. + implicitHeaders: null + + # Generate Spring OpenAPI Docket configuration class. + swaggerDocketConfig: null + + # Use Optional container for optional parameters + useOptional: null + + # library template (sub-template) to use + library: null + + # Contents of OpenAPI Generator configuration file. + # This is the file that would be passed with --config option on OpenAPI Generator commandline. + # The JSON contents of that file should be the value of this parameter. + # This parameter need not be used. If it is absent, all string-valued parameters are collected into + # a map that is then passed to the OpenAPI Generator module. If a map is provided here, then string-valued + # parameters are still copied in, overriding like-named values appearing in the map. + openApiCodegenConfig: null + + # System properties to set, as in the -D option of OpenAPI Generatorcommand line. + # Each property should be a json object with a name/value pair for each property. + # Example: for '-Dmodels -Dapis=User,Pets' use the following: + # value: + # models: '' + # apis: Users,Pets + openApiCodegenSystemProperties: null diff --git a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/build.gradle b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/build.gradle new file mode 100644 index 0000000..42e28d7 --- /dev/null +++ b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/build.gradle @@ -0,0 +1,33 @@ +apply plugin: 'java' + + repositories { + maven { + url "http://maven.reprezen.com/repository/releases" + } + maven { + url "http://maven.reprezen.com/repository/eclipse/" + } + mavenCentral() + } + + dependencies { + compile ('com.modelsolv.reprezen:com.modelsolv.reprezen.generators.api:1.6.11.9445') + compile ('com.modelsolv.reprezen:com.modelsolv.reprezen.generators.xtend:1.6.11.9445') { + exclude module: 'org.eclipse.equinox.bidi' + exclude module: 'org.eclipse.emf.common.ui' + exclude module: 'org.eclipse.e4.ui.workbench3' + exclude module: 'org.apache.batik.css' + exclude module: 'org.eclipse.e4.ui.css.swt' + } + compile ('com.modelsolv.reprezen:com.modelsolv.reprezen.generators.standard:1.6.11.9445') + compile fileTree(dir: '/Users/tanya/RepreZen/workspace/shared/GenTemplates', include: ['*.jar']) + compile fileTree(dir: '/Users/tanya/Documents/workspace/Contract-as-Code-Demo-OpenAPI3---Spring-Boot/Expanded Pet Store (v3)/lib', include: ['*.jar']) + } + + task(execGenTarget, dependsOn: 'classes', type: JavaExec) { + main = 'com.modelsolv.reprezen.generators.api.util.GeneratorLauncher' + classpath = sourceSets.main.runtimeClasspath + args '/Users/tanya/Documents/workspace/Contract-as-Code-Demo-OpenAPI3---Spring-Boot/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen' + } + + defaultTasks 'execGenTarget' diff --git a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/pom.xml b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/pom.xml new file mode 100644 index 0000000..aa31b3e --- /dev/null +++ b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.modelsolv.reprezen.generators + pet-store-expanded + 1.0-SNAPSHOT + ../../../pom.xml + + java-spring--boot---mvc---cloudfeign--server-gen + GenTarget Launcher For Java Spring (Boot + MVC + CloudFeign) Server.gen + pom + + /Users/tanya/Documents/workspace/Contract-as-Code-Demo-OpenAPI3---Spring-Boot/Expanded Pet Store (v3)/lib + /Users/tanya/RepreZen/workspace/shared/GenTemplates + + + clean generate-sources + + + com.googlecode.addjars-maven-plugin + addjars-maven-plugin + 1.0.5 + + + generate-sources + + add-jars + + + + + ${shared.gentemplates.dir} + + + ${project.lib.dir} + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.4.0 + + + generate-sources + + java + + + + + true + com.modelsolv.reprezen.generators.api.util.GeneratorLauncher + compile + false + + Java Spring (Boot + MVC + CloudFeign) Server.gen + + + + + + \ No newline at end of file From 4e52c4bd5292ee251d60d99f0f63f4498bd222c7 Mon Sep 17 00:00:00 2001 From: Tatiana Fesenko Date: Thu, 20 Sep 2018 14:15:24 -0400 Subject: [PATCH 02/11] Modify output folder and packages in the *.gen file --- ...pring (Boot + MVC + CloudFeign) Server.gen | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen index 2c9a28f..707e27f 100644 --- a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen +++ b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen @@ -1,7 +1,7 @@ --- name: "Java Spring (Boot + MVC + CloudFeign) Server" genTemplateId: "com.modelsolv.reprezen.gentemplates.openapi.generator.SpringCodegen" -relativeOutputDir: generated +relativeOutputDir: ../../../implementation/springboot-petstore-demo prerequisites: null primarySource: path: "../../../models/petstore-expanded.yaml" @@ -21,19 +21,19 @@ parameters: prependFormOrBodyParameters: null # package for generated models - modelPackage: null + modelPackage: com.reprezen.demo.springboot.model # package for generated api classes - apiPackage: null + apiPackage: com.reprezen.demo.springboot.api # root package for generated code - invokerPackage: null + invokerPackage: com.reprezen.demo.springboot # groupId in generated pom.xml - groupId: null + groupId: com.reprezen.demo # artifactId in generated pom.xml - artifactId: null + artifactId: petstore-demo # artifact version in generated pom.xml artifactVersion: null @@ -42,7 +42,7 @@ parameters: artifactUrl: null # artifact description in generated pom.xml - artifactDescription: null + artifactDescription: "Demontration of the Contract-as-Code approach with Spring Boot artifacts generated from an OpenAPI3 doc" # SCM connection in generated pom.xml scmConnection: null @@ -87,7 +87,7 @@ parameters: fullJavaUtil: null # hides the timestamp when files were generated - hideGenerationTimestamp: null + hideGenerationTimestamp: true # whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML) withXml: null @@ -96,22 +96,22 @@ parameters: dateLibrary: null # Option. Use Java8 classes instead of third party equivalents - java8: null + java8: true # server title name or client service name title: null # configuration package for generated code - configPackage: null + configPackage: com.reprezen.demo.springboot.swaggerui # base package (invokerPackage) for generated code - basePackage: null + basePackage: com.reprezen.demo.springboot # Whether to generate only API interface stubs without the server files. - interfaceOnly: null + interfaceOnly: true # Whether to generate the server files using the delegate pattern - delegatePattern: null + delegatePattern: true # Whether to select only one produces/consumes content-type by operation. singleContentTypes: null From 736a7ce0a37214119cf99abcdd532a1a300b3326 Mon Sep 17 00:00:00 2001 From: Tatiana Fesenko Date: Thu, 20 Sep 2018 14:16:49 -0400 Subject: [PATCH 03/11] Generate code --- .../.openapi-generator-ignore | 23 ++++ .../.openapi-generator/VERSION | 1 + .../springboot-petstore-demo/README.md | 18 +++ .../springboot-petstore-demo/pom.xml | 62 ++++++++++ .../demo/springboot/OpenAPI2SpringBoot.java | 33 +++++ .../demo/springboot/RFC3339DateFormat.java | 22 ++++ .../demo/springboot/api/ApiException.java | 11 ++ .../demo/springboot/api/ApiOriginFilter.java | 28 +++++ .../springboot/api/ApiResponseMessage.java | 70 +++++++++++ .../reprezen/demo/springboot/api/ApiUtil.java | 17 +++ .../springboot/api/NotFoundException.java | 11 ++ .../reprezen/demo/springboot/api/PetsApi.java | 115 ++++++++++++++++++ .../springboot/api/PetsApiController.java | 25 ++++ .../reprezen/demo/springboot/model/Error.java | 108 ++++++++++++++++ .../demo/springboot/model/NewPet.java | 107 ++++++++++++++++ .../reprezen/demo/springboot/model/Pet.java | 84 +++++++++++++ .../springboot/swaggerui/HomeController.java | 16 +++ .../swaggerui/OpenAPIDocumentationConfig.java | 71 +++++++++++ .../src/main/resources/application.properties | 4 + 19 files changed, 826 insertions(+) create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator-ignore create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/RFC3339DateFormat.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiUtil.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/HomeController.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/resources/application.properties diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator-ignore b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator-ignore new file mode 100644 index 0000000..7484ee5 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# 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 diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION new file mode 100644 index 0000000..56fea8a --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION @@ -0,0 +1 @@ +3.0.0 \ No newline at end of file diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md new file mode 100644 index 0000000..f7a85c9 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md @@ -0,0 +1,18 @@ +# OpenAPI generated server + +Spring Boot Server + + +## Overview +This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. +By using the [OpenAPI-Spec](https://openapis.org), you can easily generate a server stub. +This is an example of building a OpenAPI-enabled server in Java using the SpringBoot framework. + +The underlying library integrating OpenAPI to SpringBoot is [springfox](https://github.com/springfox/springfox) + +Start your server as an simple java application + +You can view the api documentation in swagger-ui by pointing to +http://localhost:8080/ + +Change default port value in application.properties \ No newline at end of file diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml new file mode 100644 index 0000000..360df36 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml @@ -0,0 +1,62 @@ + + 4.0.0 + com.reprezen.demo + petstore-demo + jar + petstore-demo + 1.0.0 + + 1.8 + ${java.version} + ${java.version} + 2.8.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.0.1.RELEASE + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + io.springfox + springfox-swagger2 + ${springfox-version} + + + io.springfox + springfox-swagger-ui + ${springfox-version} + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + + diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java new file mode 100644 index 0000000..7b76ae9 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java @@ -0,0 +1,33 @@ +package com.reprezen.demo.springboot; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.ExitCodeGenerator; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = { "com.reprezen.demo.springboot", "com.reprezen.demo.springboot.api" , "com.reprezen.demo.springboot.swaggerui"}) +public class OpenAPI2SpringBoot implements CommandLineRunner { + + @Override + public void run(String... arg0) throws Exception { + if (arg0.length > 0 && arg0[0].equals("exitcode")) { + throw new ExitException(); + } + } + + public static void main(String[] args) throws Exception { + new SpringApplication(OpenAPI2SpringBoot.class).run(args); + } + + class ExitException extends RuntimeException implements ExitCodeGenerator { + private static final long serialVersionUID = 1L; + + @Override + public int getExitCode() { + return 10; + } + + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/RFC3339DateFormat.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/RFC3339DateFormat.java new file mode 100644 index 0000000..9dfbe42 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/RFC3339DateFormat.java @@ -0,0 +1,22 @@ +package com.reprezen.demo.springboot; + +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; +import com.fasterxml.jackson.databind.util.ISO8601Utils; + +import java.text.FieldPosition; +import java.util.Date; + + +public class RFC3339DateFormat extends ISO8601DateFormat { + + private static final long serialVersionUID = 1L; + + // Same as ISO8601DateFormat but serializing milliseconds. + @Override + public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { + String value = ISO8601Utils.format(date, true); + toAppendTo.append(value); + return toAppendTo; + } + +} \ No newline at end of file diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java new file mode 100644 index 0000000..801fd80 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java @@ -0,0 +1,11 @@ +package com.reprezen.demo.springboot.api; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +public class ApiException extends Exception{ + private int code; + public ApiException (int code, String msg) { + super(msg); + this.code = code; + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java new file mode 100644 index 0000000..b95012c --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java @@ -0,0 +1,28 @@ +package com.reprezen.demo.springboot.api; + +import java.io.IOException; + +import javax.servlet.*; +import javax.servlet.http.HttpServletResponse; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +public class ApiOriginFilter implements javax.servlet.Filter { + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + HttpServletResponse res = (HttpServletResponse) response; + res.addHeader("Access-Control-Allow-Origin", "*"); + res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); + res.addHeader("Access-Control-Allow-Headers", "Content-Type"); + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java new file mode 100644 index 0000000..3d8edf9 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java @@ -0,0 +1,70 @@ +package com.reprezen.demo.springboot.api; + +import javax.xml.bind.annotation.XmlTransient; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +@javax.xml.bind.annotation.XmlRootElement +public class ApiResponseMessage { + public static final int ERROR = 1; + public static final int WARNING = 2; + public static final int INFO = 3; + public static final int OK = 4; + public static final int TOO_BUSY = 5; + + int code; + String type; + String message; + + public ApiResponseMessage(){} + + public ApiResponseMessage(int code, String message){ + this.code = code; + switch(code){ + case ERROR: + setType("error"); + break; + case WARNING: + setType("warning"); + break; + case INFO: + setType("info"); + break; + case OK: + setType("ok"); + break; + case TOO_BUSY: + setType("too busy"); + break; + default: + setType("unknown"); + break; + } + this.message = message; + } + + @XmlTransient + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiUtil.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiUtil.java new file mode 100644 index 0000000..f6014ce --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiUtil.java @@ -0,0 +1,17 @@ +package com.reprezen.demo.springboot.api; + +import org.springframework.web.context.request.NativeWebRequest; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class ApiUtil { + public static void setExampleResponse(NativeWebRequest req, String contentType, String example) { + try { + req.getNativeResponse(HttpServletResponse.class).addHeader("Content-Type", contentType); + req.getNativeResponse(HttpServletResponse.class).getOutputStream().print(example); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java new file mode 100644 index 0000000..683dbab --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java @@ -0,0 +1,11 @@ +package com.reprezen.demo.springboot.api; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +public class NotFoundException extends ApiException { + private int code; + public NotFoundException (int code, String msg) { + super(code, msg); + this.code = code; + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java new file mode 100644 index 0000000..91c5e36 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java @@ -0,0 +1,115 @@ +/** + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.0.0). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +package com.reprezen.demo.springboot.api; + +import com.reprezen.demo.springboot.model.Error; +import com.reprezen.demo.springboot.model.NewPet; +import com.reprezen.demo.springboot.model.Pet; +import io.swagger.annotations.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.util.List; +import java.util.Map; +import java.util.Optional; +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +@Api(value = "pets", description = "the pets API") +public interface PetsApi { + + default Optional getRequest() { + return Optional.empty(); + } + + @ApiOperation(value = "", nickname = "addPet", notes = "Creates a new pet in the store. Duplicates are allowed", response = Pet.class, tags={ }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "pet response", response = Pet.class), + @ApiResponse(code = 200, message = "unexpected error", response = Error.class) }) + @RequestMapping(value = "/pets", + produces = { "application/json" }, + consumes = { "application/json" }, + method = RequestMethod.POST) + default ResponseEntity addPet(@ApiParam(value = "Pet to add to the store" ,required=true ) @Valid @RequestBody NewPet newPet) { + getRequest().ifPresent(request -> { + for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) { + if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { + ApiUtil.setExampleResponse(request, "application/json", "null"); + break; + } + } + }); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + @ApiOperation(value = "", nickname = "deletePet", notes = "deletes a single pet based on the ID supplied", tags={ }) + @ApiResponses(value = { + @ApiResponse(code = 204, message = "pet deleted"), + @ApiResponse(code = 200, message = "unexpected error", response = Error.class) }) + @RequestMapping(value = "/pets/{id}", + produces = { "application/json" }, + method = RequestMethod.DELETE) + default ResponseEntity deletePet(@ApiParam(value = "ID of pet to delete",required=true) @PathVariable("id") Long id) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + @ApiOperation(value = "", nickname = "findPetById", notes = "Returns a user based on a single ID, if the user does not have access to the pet", response = Pet.class, tags={ }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "pet response", response = Pet.class), + @ApiResponse(code = 200, message = "unexpected error", response = Error.class) }) + @RequestMapping(value = "/pets/{id}", + produces = { "application/json" }, + method = RequestMethod.GET) + default ResponseEntity findPetById(@ApiParam(value = "ID of pet to fetch",required=true) @PathVariable("id") Long id) { + getRequest().ifPresent(request -> { + for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) { + if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { + ApiUtil.setExampleResponse(request, "application/json", "null"); + break; + } + } + }); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + + + @ApiOperation(value = "", nickname = "findPets", notes = "Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. ", response = Pet.class, responseContainer = "List", tags={ }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "pet response", response = Pet.class, responseContainer = "List"), + @ApiResponse(code = 200, message = "unexpected error", response = Error.class) }) + @RequestMapping(value = "/pets", + produces = { "application/json" }, + method = RequestMethod.GET) + default ResponseEntity> findPets(@ApiParam(value = "tags to filter by") @Valid @RequestParam(value = "tags", required = false) List tags,@ApiParam(value = "maximum number of results to return") @Valid @RequestParam(value = "limit", required = false) Integer limit) { + getRequest().ifPresent(request -> { + for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) { + if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { + ApiUtil.setExampleResponse(request, "application/json", "null"); + break; + } + } + }); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + + } + +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java new file mode 100644 index 0000000..ab4ffc2 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java @@ -0,0 +1,25 @@ +package com.reprezen.demo.springboot.api; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.context.request.NativeWebRequest; +import java.util.Optional; +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +@Controller +@RequestMapping("${openapi.swaggerPetstore.base-path:/api}") +public class PetsApiController implements PetsApi { + + private final NativeWebRequest request; + + @org.springframework.beans.factory.annotation.Autowired + public PetsApiController(NativeWebRequest request) { + this.request = request; + } + + @Override + public Optional getRequest() { + return Optional.ofNullable(request); + } + +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java new file mode 100644 index 0000000..c9935ec --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java @@ -0,0 +1,108 @@ +package com.reprezen.demo.springboot.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.springframework.validation.annotation.Validated; +import javax.validation.Valid; +import javax.validation.constraints.*; + +/** + * Error + */ +@Validated +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +public class Error { + @JsonProperty("code") + private Integer code = null; + + @JsonProperty("message") + private String message = null; + + public Error code(Integer code) { + this.code = code; + return this; + } + + /** + * Get code + * @return code + **/ + @ApiModelProperty(required = true, value = "") + @NotNull + + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public Error message(String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + **/ + @ApiModelProperty(required = true, value = "") + @NotNull + + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Error error = (Error) o; + return Objects.equals(this.code, error.code) && + Objects.equals(this.message, error.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Error {\n"); + + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java new file mode 100644 index 0000000..68bbb9f --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java @@ -0,0 +1,107 @@ +package com.reprezen.demo.springboot.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.springframework.validation.annotation.Validated; +import javax.validation.Valid; +import javax.validation.constraints.*; + +/** + * NewPet + */ +@Validated +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +public class NewPet { + @JsonProperty("name") + private String name = null; + + @JsonProperty("tag") + private String tag = null; + + public NewPet name(String name) { + this.name = name; + return this; + } + + /** + * Get name + * @return name + **/ + @ApiModelProperty(required = true, value = "") + @NotNull + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public NewPet tag(String tag) { + this.tag = tag; + return this; + } + + /** + * Get tag + * @return tag + **/ + @ApiModelProperty(value = "") + + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NewPet newPet = (NewPet) o; + return Objects.equals(this.name, newPet.name) && + Objects.equals(this.tag, newPet.tag); + } + + @Override + public int hashCode() { + return Objects.hash(name, tag); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class NewPet {\n"); + + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" tag: ").append(toIndentedString(tag)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java new file mode 100644 index 0000000..b88af83 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java @@ -0,0 +1,84 @@ +package com.reprezen.demo.springboot.model; + +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.reprezen.demo.springboot.model.NewPet; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.springframework.validation.annotation.Validated; +import javax.validation.Valid; +import javax.validation.constraints.*; + +/** + * Pet + */ +@Validated +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +public class Pet extends NewPet { + @JsonProperty("id") + private Long id = null; + + public Pet id(Long id) { + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @ApiModelProperty(required = true, value = "") + @NotNull + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(id, super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/HomeController.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/HomeController.java new file mode 100644 index 0000000..a28370b --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/HomeController.java @@ -0,0 +1,16 @@ +package com.reprezen.demo.springboot.swaggerui; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Home redirection to swagger api documentation + */ +@Controller +public class HomeController { + @RequestMapping(value = "/") + public String index() { + System.out.println("swagger-ui.html"); + return "redirect:swagger-ui.html"; + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java new file mode 100644 index 0000000..66bb246 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java @@ -0,0 +1,71 @@ +package com.reprezen.demo.springboot.swaggerui; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import org.springframework.web.util.UriComponentsBuilder; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.paths.Paths; +import springfox.documentation.spring.web.paths.RelativePathProvider; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import javax.servlet.ServletContext; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") + +@Configuration +@EnableSwagger2 +public class OpenAPIDocumentationConfig { + + ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("Swagger Petstore") + .description("A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification") + .license("MIT") + .licenseUrl("http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT") + .termsOfServiceUrl("http://madskristensen.net") + .version("1.0.0") + .contact(new Contact("","", "foo@example.com")) + .build(); + } + + @Bean + public Docket customImplementation(ServletContext servletContext, @Value("${openapi.swaggerPetstore.base-path:/api}") String basePath) { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("com.reprezen.demo.springboot.api")) + .build() + .pathProvider(new BasePathAwareRelativePathProvider(servletContext, basePath)) + .directModelSubstitute(java.time.LocalDate.class, java.sql.Date.class) + .directModelSubstitute(java.time.OffsetDateTime.class, java.util.Date.class) + .apiInfo(apiInfo()); + } + + class BasePathAwareRelativePathProvider extends RelativePathProvider { + private String basePath; + + public BasePathAwareRelativePathProvider(ServletContext servletContext, String basePath) { + super(servletContext); + this.basePath = basePath; + } + + @Override + protected String applicationPath() { + return Paths.removeAdjacentForwardSlashes(UriComponentsBuilder.fromPath(super.applicationPath()).path(basePath).build().toString()); + } + + @Override + public String getOperationPath(String operationPath) { + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromPath("/"); + return Paths.removeAdjacentForwardSlashes( + uriComponentsBuilder.path(operationPath.replaceFirst("^" + basePath, "")).build().toString()); + } + } + +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/resources/application.properties b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/resources/application.properties new file mode 100644 index 0000000..a3d004b --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/resources/application.properties @@ -0,0 +1,4 @@ +springfox.documentation.swagger.v2.path=/api-docs +server.port=8080 +spring.jackson.date-format=com.reprezen.demo.springboot.RFC3339DateFormat +spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false \ No newline at end of file From a0667109135e6ecb043c6c1887172e35b2b7970a Mon Sep 17 00:00:00 2001 From: Tatiana Fesenko Date: Thu, 20 Sep 2018 15:42:43 -0400 Subject: [PATCH 04/11] Update .gitignore file --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index a1c2a23..d44e644 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,10 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* + +# Locally ignored (path-specific) files and directories. +*settings/ +*metadata/ + +# Generator trace file +*.trace.json From fdf4c2344e61ce1447e75640c5e4459cc605a5e0 Mon Sep 17 00:00:00 2001 From: Tanya Fesenko Date: Thu, 20 Sep 2018 15:54:25 -0400 Subject: [PATCH 05/11] Describe Contract-as-Code approach --- README.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53db148..c88e7d7 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,38 @@ -# Contract-as-Code-Demo-OpenAPI3---Spring-Boot +# Contract-as-Code Demo: OpenAPI3 -> Spring Boot Demo for OpenAPI3 to Spring Boot generator -## Work in Progress +To run the code locally +1. `git checkout final` +2. Navigate to the Spring Boot directory: `cd 'Expanded Pet Store (v3)/implementation/springboot-petstore-demo/'` +3. `mvn spring-boot:run` +4. Access API at this URI: http://localhost:8080/api/pets/ + +To learn more about the Contract-as-Code approach, watch our presentation: [API Contract-As-Code: Rapid Development with OpenAPI](https://www.slideshare.net/TedEpstein/api-contractascode-rapid-development-with-openapi) + + +# Work in Progress +## Step 1: Describe +Describe your RESTful API * step_1a Create "Expanded Pet Store" Project * step_1b Add GenTarget for "Java Spring (Boot + MVC + CloudFeign) Server" * step_1c Modify output folder and packages in the *.gen file + +## Step 2: Generate +Generate code and add customizations * step_2a Generate code * step_2b Add implementation to the code + +### Run locally +Now you can run the API locally with this maven command: +``` +mvn spring-boot:run +``` +The API will be exposed at the following URI: http://localhost:8080/api/pets/ + +## Step 3: Iterate * step_3a Add a new method to the OAS document * step_3b Re-generate code * step_3c Add missing implementation + + * ... From 4922368389156e00cf94083af38164d73a77f9fb Mon Sep 17 00:00:00 2001 From: Tanya Fesenko Date: Thu, 20 Sep 2018 15:55:11 -0400 Subject: [PATCH 06/11] Remove duplicate explanation about running locally --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index c88e7d7..ed92918 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,7 @@ Generate code and add customizations * step_2a Generate code * step_2b Add implementation to the code -### Run locally -Now you can run the API locally with this maven command: -``` -mvn spring-boot:run -``` -The API will be exposed at the following URI: http://localhost:8080/api/pets/ +Now you can run the API locally as described above. ## Step 3: Iterate * step_3a Add a new method to the OAS document From 49c8e0044bf23b615d40fccb196e317386ef9365 Mon Sep 17 00:00:00 2001 From: Tanya Fesenko Date: Thu, 20 Sep 2018 17:12:33 -0400 Subject: [PATCH 07/11] Update descriptions of the steps --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed92918..e0a9b8f 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,13 @@ To learn more about the Contract-as-Code approach, watch our presentation: [API # Work in Progress -## Step 1: Describe +## Step 1: Design Describe your RESTful API * step_1a Create "Expanded Pet Store" Project * step_1b Add GenTarget for "Java Spring (Boot + MVC + CloudFeign) Server" * step_1c Modify output folder and packages in the *.gen file -## Step 2: Generate +## Step 2: Generate and Implement Generate code and add customizations * step_2a Generate code * step_2b Add implementation to the code From 9ab3d5f03cc6f8fda21516c17ff00811541a73aa Mon Sep 17 00:00:00 2001 From: Tanya Fesenko Date: Thu, 20 Sep 2018 18:28:06 -0400 Subject: [PATCH 08/11] Add a link to SpringCodegen --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0a9b8f..a9d8bf5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Contract-as-Code Demo: OpenAPI3 -> Spring Boot -Demo for OpenAPI3 to Spring Boot generator +Creating a Spring Boot app from an OpenAPI3 document with [SpringCodegen](https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java) To run the code locally 1. `git checkout final` From 351dec6ee546c3cf887ec6cb7c9d9133e231e4e6 Mon Sep 17 00:00:00 2001 From: Tanya Fesenko Date: Mon, 24 Sep 2018 09:16:45 -0400 Subject: [PATCH 09/11] Updated the repo name to API-CodeFlow-Spring-Boot --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9d8bf5..4c82ac8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Contract-as-Code Demo: OpenAPI3 -> Spring Boot +# API CodeFlow Spring Boot Creating a Spring Boot app from an OpenAPI3 document with [SpringCodegen](https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java) To run the code locally From c1e48bd6cb408d01790e31f90f826ac9c8c44acc Mon Sep 17 00:00:00 2001 From: Tatiana Fesenko Date: Mon, 24 Sep 2018 09:51:38 -0400 Subject: [PATCH 10/11] Customized generator parameters * `hideGenerationTimestamp: true` - timestamps create noise, disable them * `delegatePattern: true` - allows us to extract implementation * `java8: false` - the java8 option generates default methods in interfaces which. Because of it, unimplemented methods in interface implementations will NOT be detected by the compiler. --- .../Java Spring (Boot + MVC + CloudFeign) Server.gen | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen index 707e27f..3699ded 100644 --- a/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen +++ b/Expanded Pet Store (v3)/gentargets/petstore-expanded/Java Spring (Boot + MVC + CloudFeign) Server/Java Spring (Boot + MVC + CloudFeign) Server.gen @@ -96,7 +96,7 @@ parameters: dateLibrary: null # Option. Use Java8 classes instead of third party equivalents - java8: true + java8: false # server title name or client service name title: null @@ -108,7 +108,7 @@ parameters: basePackage: com.reprezen.demo.springboot # Whether to generate only API interface stubs without the server files. - interfaceOnly: true + interfaceOnly: false # Whether to generate the server files using the delegate pattern delegatePattern: true @@ -149,7 +149,11 @@ parameters: # This parameter need not be used. If it is absent, all string-valued parameters are collected into # a map that is then passed to the OpenAPI Generator module. If a map is provided here, then string-valued # parameters are still copied in, overriding like-named values appearing in the map. - openApiCodegenConfig: null + openApiCodegenConfig: + hideGenerationTimestamp: true + delegatePattern: true + # the java8 option generates default methods in interfaces which. Because of it, unimplemented methods in interface implementations will NOT be detected by the compiler. + java8: false # System properties to set, as in the -D option of OpenAPI Generatorcommand line. # Each property should be a json object with a name/value pair for each property. From 8adec3ef129a9e1381998fb372de72a90c8c0ddb Mon Sep 17 00:00:00 2001 From: Tatiana Fesenko Date: Mon, 24 Sep 2018 10:06:37 -0400 Subject: [PATCH 11/11] Generate OpenAPI Codegen Artifacts for Spring Boot --- .../.openapi-generator/VERSION | 2 +- .../springboot-petstore-demo/README.md | 2 +- .../springboot-petstore-demo/pom.xml | 10 +- .../demo/springboot/OpenAPI2SpringBoot.java | 20 +- .../demo/springboot/api/ApiException.java | 1 - .../demo/springboot/api/ApiOriginFilter.java | 1 - .../springboot/api/ApiResponseMessage.java | 1 - .../springboot/api/NotFoundException.java | 1 - .../reprezen/demo/springboot/api/PetsApi.java | 57 +---- .../springboot/api/PetsApiController.java | 45 +++- .../demo/springboot/api/PetsApiDelegate.java | 41 ++++ .../reprezen/demo/springboot/model/Error.java | 3 - .../demo/springboot/model/NewPet.java | 3 - .../reprezen/demo/springboot/model/Pet.java | 3 - .../swaggerui/CustomInstantDeserializer.java | 232 ++++++++++++++++++ .../swaggerui/JacksonConfiguration.java | 23 ++ .../swaggerui/OpenAPIDocumentationConfig.java | 6 +- 17 files changed, 366 insertions(+), 85 deletions(-) create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiDelegate.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/CustomInstantDeserializer.java create mode 100644 Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/JacksonConfiguration.java diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION index 56fea8a..06eda28 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/.openapi-generator/VERSION @@ -1 +1 @@ -3.0.0 \ No newline at end of file +3.2.3 \ No newline at end of file diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md index f7a85c9..764a5cc 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/README.md @@ -10,7 +10,7 @@ This is an example of building a OpenAPI-enabled server in Java using the Spring The underlying library integrating OpenAPI to SpringBoot is [springfox](https://github.com/springfox/springfox) -Start your server as an simple java application +Start your server as a simple java application You can view the api documentation in swagger-ui by pointing to http://localhost:8080/ diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml index 360df36..10cac49 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/pom.xml @@ -6,7 +6,7 @@ petstore-demo 1.0.0 - 1.8 + 1.7 ${java.version} ${java.version} 2.8.0 @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 1.5.12.RELEASE src/main/java @@ -48,10 +48,10 @@ springfox-swagger-ui ${springfox-version} - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + com.github.joschi.jackson + jackson-datatype-threetenbp + 2.8.4 diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java index 7b76ae9..2e07e4f 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/OpenAPI2SpringBoot.java @@ -4,10 +4,14 @@ import org.springframework.boot.ExitCodeGenerator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @SpringBootApplication -@ComponentScan(basePackages = { "com.reprezen.demo.springboot", "com.reprezen.demo.springboot.api" , "com.reprezen.demo.springboot.swaggerui"}) +@ComponentScan(basePackages = {"com.reprezen.demo.springboot", "com.reprezen.demo.springboot.api" , "com.reprezen.demo.springboot.swaggerui"}) public class OpenAPI2SpringBoot implements CommandLineRunner { @Override @@ -30,4 +34,18 @@ public int getExitCode() { } } + + @Bean + public WebMvcConfigurer webConfigurer() { + return new WebMvcConfigurerAdapter() { + /*@Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("*") + .allowedHeaders("Content-Type"); + }*/ + }; + } + } diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java index 801fd80..aece227 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiException.java @@ -1,6 +1,5 @@ package com.reprezen.demo.springboot.api; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") public class ApiException extends Exception{ private int code; diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java index b95012c..073dca5 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiOriginFilter.java @@ -5,7 +5,6 @@ import javax.servlet.*; import javax.servlet.http.HttpServletResponse; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") public class ApiOriginFilter implements javax.servlet.Filter { @Override diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java index 3d8edf9..42c5d11 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/ApiResponseMessage.java @@ -2,7 +2,6 @@ import javax.xml.bind.annotation.XmlTransient; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") @javax.xml.bind.annotation.XmlRootElement public class ApiResponseMessage { diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java index 683dbab..a7f3323 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/NotFoundException.java @@ -1,6 +1,5 @@ package com.reprezen.demo.springboot.api; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") public class NotFoundException extends ApiException { private int code; diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java index 91c5e36..468b2fe 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApi.java @@ -1,5 +1,5 @@ /** - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.0.0). + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (3.2.3). * https://openapi-generator.tech * Do not edit the class manually. */ @@ -9,9 +9,8 @@ import com.reprezen.demo.springboot.model.NewPet; import com.reprezen.demo.springboot.model.Pet; import io.swagger.annotations.*; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; @@ -19,23 +18,17 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.multipart.MultipartFile; import javax.validation.Valid; import javax.validation.constraints.*; import java.util.List; import java.util.Map; -import java.util.Optional; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") +@Validated @Api(value = "pets", description = "the pets API") public interface PetsApi { - default Optional getRequest() { - return Optional.empty(); - } - @ApiOperation(value = "", nickname = "addPet", notes = "Creates a new pet in the store. Duplicates are allowed", response = Pet.class, tags={ }) @ApiResponses(value = { @ApiResponse(code = 200, message = "pet response", response = Pet.class), @@ -44,18 +37,7 @@ default Optional getRequest() { produces = { "application/json" }, consumes = { "application/json" }, method = RequestMethod.POST) - default ResponseEntity addPet(@ApiParam(value = "Pet to add to the store" ,required=true ) @Valid @RequestBody NewPet newPet) { - getRequest().ifPresent(request -> { - for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) { - if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { - ApiUtil.setExampleResponse(request, "application/json", "null"); - break; - } - } - }); - return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); - - } + ResponseEntity addPet(@ApiParam(value = "Pet to add to the store" ,required=true ) @Valid @RequestBody NewPet newPet); @ApiOperation(value = "", nickname = "deletePet", notes = "deletes a single pet based on the ID supplied", tags={ }) @@ -65,10 +47,7 @@ default ResponseEntity addPet(@ApiParam(value = "Pet to add to the store" , @RequestMapping(value = "/pets/{id}", produces = { "application/json" }, method = RequestMethod.DELETE) - default ResponseEntity deletePet(@ApiParam(value = "ID of pet to delete",required=true) @PathVariable("id") Long id) { - return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); - - } + ResponseEntity deletePet(@ApiParam(value = "ID of pet to delete",required=true) @PathVariable("id") Long id); @ApiOperation(value = "", nickname = "findPetById", notes = "Returns a user based on a single ID, if the user does not have access to the pet", response = Pet.class, tags={ }) @@ -78,18 +57,7 @@ default ResponseEntity deletePet(@ApiParam(value = "ID of pet to delete",r @RequestMapping(value = "/pets/{id}", produces = { "application/json" }, method = RequestMethod.GET) - default ResponseEntity findPetById(@ApiParam(value = "ID of pet to fetch",required=true) @PathVariable("id") Long id) { - getRequest().ifPresent(request -> { - for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) { - if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { - ApiUtil.setExampleResponse(request, "application/json", "null"); - break; - } - } - }); - return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); - - } + ResponseEntity findPetById(@ApiParam(value = "ID of pet to fetch",required=true) @PathVariable("id") Long id); @ApiOperation(value = "", nickname = "findPets", notes = "Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. ", response = Pet.class, responseContainer = "List", tags={ }) @@ -99,17 +67,6 @@ default ResponseEntity findPetById(@ApiParam(value = "ID of pet to fetch",r @RequestMapping(value = "/pets", produces = { "application/json" }, method = RequestMethod.GET) - default ResponseEntity> findPets(@ApiParam(value = "tags to filter by") @Valid @RequestParam(value = "tags", required = false) List tags,@ApiParam(value = "maximum number of results to return") @Valid @RequestParam(value = "limit", required = false) Integer limit) { - getRequest().ifPresent(request -> { - for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) { - if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) { - ApiUtil.setExampleResponse(request, "application/json", "null"); - break; - } - } - }); - return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); - - } + ResponseEntity> findPets(@ApiParam(value = "tags to filter by") @Valid @RequestParam(value = "tags", required = false) List tags,@ApiParam(value = "maximum number of results to return") @Valid @RequestParam(value = "limit", required = false) Integer limit); } diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java index ab4ffc2..7758ad6 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiController.java @@ -1,25 +1,50 @@ package com.reprezen.demo.springboot.api; +import com.reprezen.demo.springboot.model.Error; +import com.reprezen.demo.springboot.model.NewPet; +import com.reprezen.demo.springboot.model.Pet; +import io.swagger.annotations.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.context.request.NativeWebRequest; -import java.util.Optional; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.*; +import javax.validation.Valid; +import java.util.List; +import java.util.Map; @Controller @RequestMapping("${openapi.swaggerPetstore.base-path:/api}") public class PetsApiController implements PetsApi { - private final NativeWebRequest request; + private final PetsApiDelegate delegate; + + public PetsApiController(@org.springframework.beans.factory.annotation.Autowired(required = false) PetsApiDelegate delegate) { + this.delegate = delegate; + } + + public ResponseEntity addPet(@ApiParam(value = "Pet to add to the store" ,required=true ) @Valid @RequestBody NewPet newPet) { + return delegate.addPet(newPet); + } + + public ResponseEntity deletePet(@ApiParam(value = "ID of pet to delete",required=true) @PathVariable("id") Long id) { + return delegate.deletePet(id); + } - @org.springframework.beans.factory.annotation.Autowired - public PetsApiController(NativeWebRequest request) { - this.request = request; + public ResponseEntity findPetById(@ApiParam(value = "ID of pet to fetch",required=true) @PathVariable("id") Long id) { + return delegate.findPetById(id); } - @Override - public Optional getRequest() { - return Optional.ofNullable(request); + public ResponseEntity> findPets(@ApiParam(value = "tags to filter by") @Valid @RequestParam(value = "tags", required = false) List tags,@ApiParam(value = "maximum number of results to return") @Valid @RequestParam(value = "limit", required = false) Integer limit) { + return delegate.findPets(tags, limit); } } diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiDelegate.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiDelegate.java new file mode 100644 index 0000000..aea71c8 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/api/PetsApiDelegate.java @@ -0,0 +1,41 @@ +package com.reprezen.demo.springboot.api; + +import com.reprezen.demo.springboot.model.Error; +import com.reprezen.demo.springboot.model.NewPet; +import com.reprezen.demo.springboot.model.Pet; +import io.swagger.annotations.*; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; +import java.util.Map; + +/** + * A delegate to be called by the {@link PetsApiController}}. + * Implement this interface with a {@link org.springframework.stereotype.Service} annotated class. + */ + +public interface PetsApiDelegate { + + /** + * @see PetsApi#addPet + */ + ResponseEntity addPet( NewPet newPet); + + /** + * @see PetsApi#deletePet + */ + ResponseEntity deletePet( Long id); + + /** + * @see PetsApi#findPetById + */ + ResponseEntity findPetById( Long id); + + /** + * @see PetsApi#findPets + */ + ResponseEntity> findPets( List tags, + Integer limit); + +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java index c9935ec..dcd272f 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Error.java @@ -5,15 +5,12 @@ import com.fasterxml.jackson.annotation.JsonCreator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.springframework.validation.annotation.Validated; import javax.validation.Valid; import javax.validation.constraints.*; /** * Error */ -@Validated -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") public class Error { @JsonProperty("code") diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java index 68bbb9f..8320dd9 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/NewPet.java @@ -5,15 +5,12 @@ import com.fasterxml.jackson.annotation.JsonCreator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.springframework.validation.annotation.Validated; import javax.validation.Valid; import javax.validation.constraints.*; /** * NewPet */ -@Validated -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") public class NewPet { @JsonProperty("name") diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java index b88af83..4c488dc 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/model/Pet.java @@ -6,15 +6,12 @@ import com.reprezen.demo.springboot.model.NewPet; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import org.springframework.validation.annotation.Validated; import javax.validation.Valid; import javax.validation.constraints.*; /** * Pet */ -@Validated -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") public class Pet extends NewPet { @JsonProperty("id") diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/CustomInstantDeserializer.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/CustomInstantDeserializer.java new file mode 100644 index 0000000..65eaff2 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/CustomInstantDeserializer.java @@ -0,0 +1,232 @@ +package com.reprezen.demo.springboot.swaggerui; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonTokenId; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.datatype.threetenbp.DecimalUtils; +import com.fasterxml.jackson.datatype.threetenbp.deser.ThreeTenDateTimeDeserializerBase; +import com.fasterxml.jackson.datatype.threetenbp.function.BiFunction; +import com.fasterxml.jackson.datatype.threetenbp.function.Function; +import org.threeten.bp.DateTimeException; +import org.threeten.bp.DateTimeUtils; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZoneId; +import org.threeten.bp.ZonedDateTime; +import org.threeten.bp.format.DateTimeFormatter; +import org.threeten.bp.temporal.Temporal; +import org.threeten.bp.temporal.TemporalAccessor; + +import java.io.IOException; +import java.math.BigDecimal; + +/** + * Deserializer for ThreeTen temporal {@link Instant}s, {@link OffsetDateTime}, and {@link ZonedDateTime}s. + * Adapted from the jackson threetenbp InstantDeserializer to add support for deserializing rfc822 format. + * + * @author Nick Williams + */ +public class CustomInstantDeserializer + extends ThreeTenDateTimeDeserializerBase { + private static final long serialVersionUID = 1L; + + public static final CustomInstantDeserializer INSTANT = new CustomInstantDeserializer( + Instant.class, DateTimeFormatter.ISO_INSTANT, + new Function() { + @Override + public Instant apply(TemporalAccessor temporalAccessor) { + return Instant.from(temporalAccessor); + } + }, + new Function() { + @Override + public Instant apply(FromIntegerArguments a) { + return Instant.ofEpochMilli(a.value); + } + }, + new Function() { + @Override + public Instant apply(FromDecimalArguments a) { + return Instant.ofEpochSecond(a.integer, a.fraction); + } + }, + null + ); + + public static final CustomInstantDeserializer OFFSET_DATE_TIME = new CustomInstantDeserializer( + OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME, + new Function() { + @Override + public OffsetDateTime apply(TemporalAccessor temporalAccessor) { + return OffsetDateTime.from(temporalAccessor); + } + }, + new Function() { + @Override + public OffsetDateTime apply(FromIntegerArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, + new Function() { + @Override + public OffsetDateTime apply(FromDecimalArguments a) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, + new BiFunction() { + @Override + public OffsetDateTime apply(OffsetDateTime d, ZoneId z) { + return d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime())); + } + } + ); + + public static final CustomInstantDeserializer ZONED_DATE_TIME = new CustomInstantDeserializer( + ZonedDateTime.class, DateTimeFormatter.ISO_ZONED_DATE_TIME, + new Function() { + @Override + public ZonedDateTime apply(TemporalAccessor temporalAccessor) { + return ZonedDateTime.from(temporalAccessor); + } + }, + new Function() { + @Override + public ZonedDateTime apply(FromIntegerArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId); + } + }, + new Function() { + @Override + public ZonedDateTime apply(FromDecimalArguments a) { + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId); + } + }, + new BiFunction() { + @Override + public ZonedDateTime apply(ZonedDateTime zonedDateTime, ZoneId zoneId) { + return zonedDateTime.withZoneSameInstant(zoneId); + } + } + ); + + protected final Function fromMilliseconds; + + protected final Function fromNanoseconds; + + protected final Function parsedToValue; + + protected final BiFunction adjust; + + protected CustomInstantDeserializer(Class supportedType, + DateTimeFormatter parser, + Function parsedToValue, + Function fromMilliseconds, + Function fromNanoseconds, + BiFunction adjust) { + super(supportedType, parser); + this.parsedToValue = parsedToValue; + this.fromMilliseconds = fromMilliseconds; + this.fromNanoseconds = fromNanoseconds; + this.adjust = adjust == null ? new BiFunction() { + @Override + public T apply(T t, ZoneId zoneId) { + return t; + } + } : adjust; + } + + @SuppressWarnings("unchecked") + protected CustomInstantDeserializer(CustomInstantDeserializer base, DateTimeFormatter f) { + super((Class) base.handledType(), f); + parsedToValue = base.parsedToValue; + fromMilliseconds = base.fromMilliseconds; + fromNanoseconds = base.fromNanoseconds; + adjust = base.adjust; + } + + @Override + protected JsonDeserializer withDateFormat(DateTimeFormatter dtf) { + if (dtf == _formatter) { + return this; + } + return new CustomInstantDeserializer(this, dtf); + } + + @Override + public T deserialize(JsonParser parser, DeserializationContext context) throws IOException { + //NOTE: Timestamps contain no timezone info, and are always in configured TZ. Only + //string values have to be adjusted to the configured TZ. + switch (parser.getCurrentTokenId()) { + case JsonTokenId.ID_NUMBER_FLOAT: { + BigDecimal value = parser.getDecimalValue(); + long seconds = value.longValue(); + int nanoseconds = DecimalUtils.extractNanosecondDecimal(value, seconds); + return fromNanoseconds.apply(new FromDecimalArguments( + seconds, nanoseconds, getZone(context))); + } + + case JsonTokenId.ID_NUMBER_INT: { + long timestamp = parser.getLongValue(); + if (context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) { + return this.fromNanoseconds.apply(new FromDecimalArguments( + timestamp, 0, this.getZone(context) + )); + } + return this.fromMilliseconds.apply(new FromIntegerArguments( + timestamp, this.getZone(context) + )); + } + + case JsonTokenId.ID_STRING: { + String string = parser.getText().trim(); + if (string.length() == 0) { + return null; + } + if (string.endsWith("+0000")) { + string = string.substring(0, string.length() - 5) + "Z"; + } + T value; + try { + TemporalAccessor acc = _formatter.parse(string); + value = parsedToValue.apply(acc); + if (context.isEnabled(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)) { + return adjust.apply(value, this.getZone(context)); + } + } catch (DateTimeException e) { + throw _peelDTE(e); + } + return value; + } + } + throw context.mappingException("Expected type float, integer, or string."); + } + + private ZoneId getZone(DeserializationContext context) { + // Instants are always in UTC, so don't waste compute cycles + return (_valueClass == Instant.class) ? null : DateTimeUtils.toZoneId(context.getTimeZone()); + } + + private static class FromIntegerArguments { + public final long value; + public final ZoneId zoneId; + + private FromIntegerArguments(long value, ZoneId zoneId) { + this.value = value; + this.zoneId = zoneId; + } + } + + private static class FromDecimalArguments { + public final long integer; + public final int fraction; + public final ZoneId zoneId; + + private FromDecimalArguments(long integer, int fraction, ZoneId zoneId) { + this.integer = integer; + this.fraction = fraction; + this.zoneId = zoneId; + } + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/JacksonConfiguration.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/JacksonConfiguration.java new file mode 100644 index 0000000..dabf783 --- /dev/null +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/JacksonConfiguration.java @@ -0,0 +1,23 @@ +package com.reprezen.demo.springboot.swaggerui; + +import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZonedDateTime; + +@Configuration +public class JacksonConfiguration { + + @Bean + @ConditionalOnMissingBean(ThreeTenModule.class) + ThreeTenModule threeTenModule() { + ThreeTenModule module = new ThreeTenModule(); + module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); + module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); + module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); + return module; + } +} diff --git a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java index 66bb246..092d10f 100644 --- a/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java +++ b/Expanded Pet Store (v3)/implementation/springboot-petstore-demo/src/main/java/com/reprezen/demo/springboot/swaggerui/OpenAPIDocumentationConfig.java @@ -17,7 +17,6 @@ import javax.servlet.ServletContext; -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2018-09-20T14:14:53.886-04:00[America/New_York]") @Configuration @EnableSwagger2 @@ -41,9 +40,8 @@ public Docket customImplementation(ServletContext servletContext, @Value("${open .select() .apis(RequestHandlerSelectors.basePackage("com.reprezen.demo.springboot.api")) .build() - .pathProvider(new BasePathAwareRelativePathProvider(servletContext, basePath)) - .directModelSubstitute(java.time.LocalDate.class, java.sql.Date.class) - .directModelSubstitute(java.time.OffsetDateTime.class, java.util.Date.class) + .directModelSubstitute(org.threeten.bp.LocalDate.class, java.sql.Date.class) + .directModelSubstitute(org.threeten.bp.OffsetDateTime.class, java.util.Date.class) .apiInfo(apiInfo()); }