diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..8c2e2b8196 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: + - package-ecosystem: "maven" + directory: "/" + schedule: + interval: "daily" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000000..f67f5a42c2 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,16 @@ +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + - name: Dependency Review + uses: actions/dependency-review-action@v3 + with: + fail-on-severity: high diff --git a/.github/workflows/maven-pr.yml b/.github/workflows/maven-pr.yml new file mode 100644 index 0000000000..b4a058ade6 --- /dev/null +++ b/.github/workflows/maven-pr.yml @@ -0,0 +1,81 @@ +name: Build Test PR + +on: + pull_request: + branches: [ "master" ] + +jobs: + build_pr: + + runs-on: ubuntu-latest + strategy: + matrix: + java: [ 8, 11, 17 ] + + env: + GENERATORS_VERSION_PROPERTY: "" + steps: + - uses: actions/checkout@v3 + name: git checkout + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: temurin + cache: maven + - name: preliminary checks + run: | + docker login --username=${{ secrets.DOCKERHUB_SB_USERNAME }} --password=${{ secrets.DOCKERHUB_SB_PASSWORD }} + set -e + # fail if templates/generators contain carriage return '\r' + /bin/bash ./bin/utils/detect_carriage_return.sh + # fail if generators contain merge conflicts + /bin/bash ./bin/utils/detect_merge_conflict.sh + # fail if generators contain tab '\t' + /bin/bash ./bin/utils/detect_tab_in_java_class.sh + - uses: s4u/maven-settings-action@v2.8.0 + name: setup maven settings.xml + with: + servers: | + [{ + "id": "sonatype-nexus-staging", + "username": "${{ secrets.OSSRH_USERNAME }}", + "password": "${{ secrets.OSSRH_TOKEN }}" + }, + { + "id": "sonatype-nexus-snapshots", + "username": "${{ secrets.OSSRH_USERNAME }}", + "password": "${{ secrets.OSSRH_TOKEN }}" + }] + - name: Build with Maven + if: ${{ matrix.java != 8 }} + run: | + export MY_POM_VERSION=`mvn -Dswagger-codegen-version=3.0.38 -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` + echo "POM VERSION" ${MY_POM_VERSION} + export CODEGEN_VERSION=`sed -n 's/\([^\s]*\)<\/swagger\-codegen\-version>/\1/p' pom.xml` + export CODEGEN_VERSION=`echo ${CODEGEN_VERSION} | tr -d '[:space:]'` + echo "CODEGEN_VERSION" ${CODEGEN_VERSION} + export CODEGEN_VERSION_PROPERTY="" + if [[ ! $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; + then + if [[ ! $CODEGEN_VERSION =~ ^.*SNAPSHOT$ ]]; + then + # check release version exists + export CODEGEN_FOUND_JSON=`curl -s --max-time 60 --retry 15 --connect-timeout 20 https://search.maven.org/solrsearch/select?q=g:io.swagger.codegen.v3%20AND%20a:swagger-codegen%20AND%20v:${CODEGEN_VERSION}%20AND%20p:jar` + export CODEGEN_FOUND=`echo ${CODEGEN_FOUND_JSON} | jq '.response.numFound'` + echo "CODEGEN_FOUND" ${CODEGEN_FOUND} + if [[ $CODEGEN_FOUND == '0' ]]; + then + echo "codegen version not found" + rm -f maven-metadata.json + curl -o maven-metadata.json -s --max-time 60 --retry 15 --connect-timeout 30 -H "accept: application/json" https://oss.sonatype.org/service/local/repositories/snapshots/content/io/swagger/codegen/v3/swagger-codegen/ + LAST_SNAP=`jq '[.data | sort_by(.lastModified) | reverse | .[] | select( .text | contains("3."))]| .[0].text' maven-metadata.json` + export LAST_SNAP=${LAST_SNAP:1:${#LAST_SNAP}-2} + echo "LAST_SNAP $LAST_SNAP" + export CODEGEN_VERSION_PROPERTY=-Dswagger-codegen-version=$LAST_SNAP + fi + fi + fi + echo "CODEGEN_VERSION_PROPERTY ${CODEGEN_VERSION_PROPERTY}" + echo "CODEGEN_VERSION_PROPERTY=${CODEGEN_VERSION_PROPERTY}" >> $GITHUB_ENV + ./mvnw clean verify -U ${CODEGEN_VERSION_PROPERTY} diff --git a/.github/workflows/maven-push.yml b/.github/workflows/maven-push.yml new file mode 100644 index 0000000000..6145fbc315 --- /dev/null +++ b/.github/workflows/maven-push.yml @@ -0,0 +1,96 @@ +name: Build Test Push + +on: + push: + branches: [ "master" ] + +jobs: + build_push: + + runs-on: ubuntu-latest + strategy: + matrix: + java: [ 8, 11, 17 ] + + env: + GENERATORS_VERSION_PROPERTY: "" + + steps: + - uses: actions/checkout@v3 + name: git checkout + with: + ref: master + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: temurin + cache: maven + - name: preliminary checks + run: | + docker login --username=${{ secrets.DOCKERHUB_SB_USERNAME }} --password=${{ secrets.DOCKERHUB_SB_PASSWORD }} + set -e + # fail if templates/generators contain carriage return '\r' + /bin/bash ./bin/utils/detect_carriage_return.sh + # fail if generators contain merge conflicts + /bin/bash ./bin/utils/detect_merge_conflict.sh + # fail if generators contain tab '\t' + /bin/bash ./bin/utils/detect_tab_in_java_class.sh + - uses: s4u/maven-settings-action@v2.8.0 + name: setup maven settings.xml + with: + servers: | + [{ + "id": "sonatype-nexus-staging", + "username": "${{ secrets.OSSRH_USERNAME }}", + "password": "${{ secrets.OSSRH_TOKEN }}" + }, + { + "id": "sonatype-nexus-snapshots", + "username": "${{ secrets.OSSRH_USERNAME }}", + "password": "${{ secrets.OSSRH_TOKEN }}" + }] + - name: Build with Maven + if: ${{ matrix.java != 8 }} + run: | + export MY_POM_VERSION=`mvn -Dswagger-codegen-version=3.0.38 -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` + echo "POM VERSION" ${MY_POM_VERSION} + export CODEGEN_VERSION=`sed -n 's/\([^\s]*\)<\/swagger\-codegen\-version>/\1/p' pom.xml` + export CODEGEN_VERSION=`echo ${CODEGEN_VERSION} | tr -d '[:space:]'` + echo "CODEGEN_VERSION" ${CODEGEN_VERSION} + export CODEGEN_VERSION_PROPERTY="" + if [[ ! $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; + then + if [[ ! $CODEGEN_VERSION =~ ^.*SNAPSHOT$ ]]; + then + # check release version exists + export CODEGEN_FOUND_JSON=`curl -s --max-time 60 --retry 15 --connect-timeout 20 https://search.maven.org/solrsearch/select?q=g:io.swagger.codegen.v3%20AND%20a:swagger-codegen%20AND%20v:${CODEGEN_VERSION}%20AND%20p:jar` + export CODEGEN_FOUND=`echo ${CODEGEN_FOUND_JSON} | jq '.response.numFound'` + echo "CODEGEN_FOUND" ${CODEGEN_FOUND} + if [[ $CODEGEN_FOUND == '0' ]]; + then + echo "codegen version not found" + rm -f maven-metadata.json + curl -o maven-metadata.json -s --max-time 60 --retry 15 --connect-timeout 30 -H "accept: application/json" https://oss.sonatype.org/service/local/repositories/snapshots/content/io/swagger/codegen/v3/swagger-codegen/ + LAST_SNAP=`jq '[.data | sort_by(.lastModified) | reverse | .[] | select( .text | contains("3."))]| .[0].text' maven-metadata.json` + export LAST_SNAP=${LAST_SNAP:1:${#LAST_SNAP}-2} + echo "LAST_SNAP $LAST_SNAP" + export CODEGEN_VERSION_PROPERTY=-Dswagger-codegen-version=$LAST_SNAP + fi + fi + fi + echo "CODEGEN_VERSION_PROPERTY ${CODEGEN_VERSION_PROPERTY}" + echo "CODEGEN_VERSION_PROPERTY=${CODEGEN_VERSION_PROPERTY}" >> $GITHUB_ENV + ./mvnw clean verify -U ${CODEGEN_VERSION_PROPERTY} + - name: Deploy Maven Snapshot + if: ${{ matrix.java == 17 }} + run: | + export MY_POM_VERSION=`mvn -Dswagger-codegen-version=3.0.38 -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` + echo "POM VERSION" ${MY_POM_VERSION} + if [[ $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; + then + ./mvnw clean deploy -U --settings $HOME/.m2/settings.xml + else + echo "not deploying release: " ${MY_POM_VERSION} + fi + diff --git a/.gitignore b/.gitignore index 6caa272d43..a7e3653162 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ # Log file *.log +# Temporary files +*.tmp +tmp/ + # BlueJ files *.ctxt @@ -14,14 +18,6 @@ # Mobile Tools for Java (J2ME) .mtj.tmp/ -# Package Files # -*.jar -*.war -*.ear -*.zip -*.tar.gz -*.rar - # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* @@ -29,3 +25,6 @@ hs_err_pid* *.iml target/ test-output/ + +.classpath +.settings/ diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar old mode 100755 new mode 100644 index f775b1c04c..bf82ff01c6 Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index eb91947648..30052152b2 100755 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1,18 @@ -distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip \ No newline at end of file +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/.whitesource b/.whitesource new file mode 100644 index 0000000000..2aa441810e --- /dev/null +++ b/.whitesource @@ -0,0 +1,3 @@ +{ + "settingsInheritedFrom": "swagger-api/whitesource-config@main" +} diff --git a/LICENSE b/LICENSE index 8dada3edaf..01abb442b9 100644 --- a/LICENSE +++ b/LICENSE @@ -178,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" + boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2020 SmartBear Software Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index a5ed926bbc..e432d7486c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # -- Master: [![Build Status](https://img.shields.io/jenkins/s/https/jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-codegen-generators-master-java-8.svg)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-codegen-generators-master-java-8) +- Master: [![Build Status](https://img.shields.io/jenkins/build.svg?jobUrl=https://jenkins.swagger.io/job/oss-swagger-codegen-generators-master-java-8)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-codegen-generators-master-java-8) + +[![Build Status](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-codegen-generators-master-java-8/badge/icon?subject=jenkins%20build%20-%20master)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-codegen-generators-master-java-8/) ## Overview **Swagger Codegen Generators** project is a set of classes and templates ([Handlebars](https://jknack.github.io/handlebars.java)) used by [Swagger Codegen 3.0.0 project](https://github.com/swagger-api/swagger-codegen/tree/3.0.0) in its code generation process for a specific language or language framework. The main differents with **Swagger Codegen 2.x.x** are: -- **Handlebars as template engine:** with Handelbars feature is possible to create more logic-less templates. +- **Handlebars as template engine:** with Handlebars feature is possible to create more logic-less templates. - **OAS 3 support:** generator classes work with OpenAPI Specification V3. More details about these and more differences are referenced at [https://github.com/swagger-api/swagger-codegen/releases/tag/v3.0.0](https://github.com/swagger-api/swagger-codegen/releases/tag/v3.0.0) @@ -16,23 +18,20 @@ You need the following installed and available in your $PATH: * Java 8 (http://java.oracle.com) * Apache maven 3.0.4 or greater (http://maven.apache.org/) -## How to contribute. -Right now the templates and generators classes are migrated from [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) **3.0.0** branch. +## How to Contribute. +Right now the templates and generators classes are migrated from [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) **3.0.0** branch. If you want to migrate an existing language/framework, you can follow this [guide](https://github.com/swagger-api/swagger-codegen/wiki/Swagger-Codegen-migration-(swagger-codegen-generators-repository)). -Also you need to keep in mind that **Handlebars** is used as template engines and besides it's pretty similar to **Mustache** there are different that can not be ignored. So you can follow this [guide](https://github.com/swagger-api/swagger-codegen/wiki/Swagger-Codegen-migration-from-Mustache-and-Handlebars-templates.) which explains steps to migrate templates from **Mustaches** to **Handelbars**. - -License -------- - -Copyright 2019 SmartBear Software - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +Also you need to keep in mind that **Handlebars** is used as the template engine. It's pretty similar to **Mustache**, but there are differences that can not be ignored. So you can follow this [guide](https://github.com/swagger-api/swagger-codegen/wiki/Swagger-Codegen-migration-from-Mustache-and-Handlebars-templates.) which explains steps to migrate templates from **Mustaches** to **Handlebars**. + +## Security Contact + +Please disclose any security-related issues or vulnerabilities by emailing [security@swagger.io](mailto:security@swagger.io), instead of using the public issue tracker. + +## License Information on Generated Code + +The Swagger Codegen project is intended as a benefit for users of the Swagger / Open API Specification. The project itself has the [License](#license) as specified. In addition, please understand the following points: + +* The templates included with this project are subject to the [License](#license). +* Generated code is intentionally _not_ subject to the parent project license +When code is generated from this project, it shall be considered **AS IS** and owned by the user of the software. There are no warranties--expressed or implied--for generated code. You can do what you wish with it, and once generated, the code is your responsibility and subject to the licensing terms that you deem appropriate. diff --git a/mvnw b/mvnw index e96ccd5fbb..b7f064624f 100755 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.1.1 # # Required ENV vars: # ------------------ @@ -27,7 +27,6 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -36,6 +35,10 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi @@ -58,9 +61,9 @@ case "`uname`" in # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" + JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME else - export JAVA_HOME="/Library/Java/Home" + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME fi fi ;; @@ -72,36 +75,8 @@ if [ -z "$JAVA_HOME" ] ; then fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` [ -n "$CLASSPATH" ] && @@ -110,11 +85,8 @@ fi # For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" [ -n "$JAVA_HOME" ] && JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? fi if [ -z "$JAVA_HOME" ]; then @@ -146,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`which java`" + JAVACMD="`\\unset -f command; \\command -v java`" fi fi @@ -160,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" @@ -185,7 +154,7 @@ find_maven_basedir() { fi # end of workaround done - echo "${basedir}" + printf '%s' "$(cd "$basedir"; pwd)" } # concatenates all lines of a file @@ -195,21 +164,106 @@ concat_lines() { fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +BASE_DIR=$(find_maven_basedir "$(dirname $0)") if [ -z "$BASE_DIR" ]; then exit 1; fi -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR if [ "$MVNW_VERBOSE" = true ]; then echo $MAVEN_PROJECTBASEDIR fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $wrapperUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + QUIET="--quiet" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + QUIET="" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" + fi + [ $? -eq 0 ] || rm -f "$wrapperJarPath" + elif command -v curl > /dev/null; then + QUIET="--silent" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + QUIET="" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L + fi + [ $? -eq 0 ] || rm -f "$wrapperJarPath" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=`cygpath --path --windows "$javaSource"` + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` [ -n "$CLASSPATH" ] && @@ -218,10 +272,16 @@ if $cygwin; then MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd old mode 100755 new mode 100644 index 4f0b068a03..cba1f040dc --- a/mvnw.cmd +++ b/mvnw.cmd @@ -18,15 +18,14 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script +@REM Apache Maven Wrapper startup batch script, version 3.1.1 @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @REM e.g. to debug Maven itself, use @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -37,7 +36,7 @@ @echo off @REM set title of command window title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% @REM set %HOME% to equivalent of $HOME @@ -46,8 +45,8 @@ if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") @REM Execute a user defined script before this one if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre @REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* :skipRcPre @setlocal @@ -117,11 +116,54 @@ for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do s :endReadAdditionalConfig SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" - set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* if ERRORLEVEL 1 goto error goto end @@ -131,15 +173,15 @@ set ERROR_CODE=1 :end @endlocal & set ERROR_CODE=%ERROR_CODE% -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost @REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" :skipRcPost @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause +if "%MAVEN_BATCH_PAUSE%"=="on" pause -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% -exit /B %ERROR_CODE% +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 0030982a3b..674bc6de95 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ io.swagger.codegen.v3 swagger-codegen-generators - 1.0.9-SNAPSHOT + 1.0.46-SNAPSHOT jar @@ -20,16 +20,12 @@ org.apache.maven.plugins maven-compiler-plugin - 3.6.1 - - 1.8 - 1.8 - + 3.10.1 org.apache.maven.plugins maven-javadoc-plugin - 3.0.1 + 3.5.0 true 1.8 @@ -53,7 +49,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.2.1 attach-sources @@ -65,12 +61,19 @@ + org.apache.maven.plugins maven-surefire-plugin - 2.22.0 + ${surefire-version} + + + org.apache.maven.surefire + surefire-junit4 + ${surefire-version} + + - - -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit-version}/jmockit-${jmockit-version}.jar - + none:none + -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit-version}/jmockit-${jmockit-version}.jar -XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.util=ALL-UNNAMED @@ -118,7 +121,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson-version} + ${jackson-databind-version} com.fasterxml.jackson.core @@ -208,6 +211,18 @@ testng ${testng-version} test + + + snakeyaml + org.yaml + + + + + junit + junit + ${junit-version} + test org.slf4j @@ -236,33 +251,35 @@ com.atlassian.commonmark commonmark - 0.9.0 + 0.17.0 org.mockito mockito-core - 2.8.47 + 2.28.2 test - 3.0.9-SNAPSHOT - 2.0.12 - 2.0.8 - 2.9.8 + 8 + 3.0.52-SNAPSHOT + 2.1.19 + 2.2.19 + 2.15.3 + 2.15.3 2.11.1 3.3.0 - 2.4 - 1.2 - 4.8.1 + 2.15.0 + 1.6.0 + 4.13.2 1.0.0 - 3.4 - 1.7.12 + 3.14.0 + 1.7.36 3.2.1 - 6.9.6 - 2.19.1 - 1.42 - 0.9.11 + 7.8.0 + 3.1.2 + 1.49 + 0.10.2 diff --git a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java index 81d8f5ec72..d9f72d82cc 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java +++ b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java @@ -16,6 +16,7 @@ import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.CodegenResponse; import io.swagger.codegen.v3.CodegenSecurity; +import io.swagger.codegen.v3.ISchemaHandler; import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.examples.ExampleGenerator; import io.swagger.codegen.v3.generators.handlebars.BaseItemsHelper; @@ -77,8 +78,12 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -105,16 +110,16 @@ import static io.swagger.codegen.v3.generators.CodegenHelper.getTypeMappings; import static io.swagger.codegen.v3.generators.CodegenHelper.initalizeSpecialCharacterMapping; import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; -import static io.swagger.codegen.v3.utils.ModelUtils.processCodegenModels; public abstract class DefaultCodegenConfig implements CodegenConfig { - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegenConfig.class); + protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegenConfig.class); public static final String DEFAULT_CONTENT_TYPE = "application/json"; public static final String REQUEST_BODY_NAME = "body"; public static final String DEFAULT_TEMPLATE_DIR = "handlebars"; protected OpenAPI openAPI; + protected OpenAPI unflattenedOpenAPI; protected String inputSpec; protected String inputURL; protected String outputFolder = StringUtils.EMPTY; @@ -138,6 +143,7 @@ public abstract class DefaultCodegenConfig implements CodegenConfig { protected Map modelDocTemplateFiles = new HashMap(); protected Map reservedWordsMappings = new HashMap(); protected String templateDir; + protected String customTemplateDir; protected String templateVersion; protected String embeddedTemplateDir; protected String commonTemplateDir = "_common"; @@ -155,11 +161,10 @@ public abstract class DefaultCodegenConfig implements CodegenConfig { protected Boolean sortParamsByRequiredFlag = true; protected Boolean ensureUniqueParams = true; protected Boolean allowUnicodeIdentifiers = false; - protected String gitUserId, gitRepoId, releaseNote; + protected String gitUserId, gitRepoId, releaseNote, gitRepoBaseURL; protected String httpUserAgent; protected Boolean hideGenerationTimestamp = true; protected TemplateEngine templateEngine = new HandlebarTemplateEngine(this); - protected SchemaHandler schemaHandler = new SchemaHandler(this); // How to encode special characters like $ // They are translated to words like "Dollar" and prefixed with ' // Then translated back during JSON encoding and decoding @@ -169,6 +174,8 @@ public abstract class DefaultCodegenConfig implements CodegenConfig { protected String ignoreFilePathOverride; protected boolean useOas2 = false; + protected boolean copyFistAllOfProperties = false; + protected boolean ignoreImportMapping; public List cliOptions() { return cliOptions; @@ -176,7 +183,14 @@ public List cliOptions() { public void processOpts() { if (additionalProperties.containsKey(CodegenConstants.TEMPLATE_DIR)) { - this.setTemplateDir((String) additionalProperties.get(CodegenConstants.TEMPLATE_DIR)); + this.customTemplateDir = additionalProperties.get(CodegenConstants.TEMPLATE_DIR).toString(); + } + this.embeddedTemplateDir = this.templateDir = getTemplateDir(); + + if (additionalProperties.get(CodegenConstants.IGNORE_IMPORT_MAPPING_OPTION) != null) { + setIgnoreImportMapping(Boolean.parseBoolean( additionalProperties.get(CodegenConstants.IGNORE_IMPORT_MAPPING_OPTION).toString())); + } else { + setIgnoreImportMapping(defaultIgnoreImportMappingOption()); } if (additionalProperties.containsKey(CodegenConstants.TEMPLATE_VERSION)) { @@ -235,7 +249,7 @@ public void processOpts() { // not set in additionalProperties, add value from CodegenConfig in order to use it in templates additionalProperties.put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, hideGenerationTimestamp); } - + if (additionalProperties.containsKey(CodegenConstants.USE_OAS2)) { this.setUseOas2(Boolean.valueOf(additionalProperties.get(CodegenConstants.USE_OAS2).toString())); } @@ -255,32 +269,50 @@ public Map postProcessAllModels(Map processedMod allModels.put(modelName, codegenModel); } } + postProcessAllCodegenModels(allModels); + return processedModels; + } + + protected void postProcessAllCodegenModels(Map allModels) { if (supportsInheritance) { - processCodegenModels(allModels); + for (String name : allModels.keySet()) { + final CodegenModel codegenModel = allModels.get(name); + fixUpParentAndInterfaces(codegenModel, allModels); + } } - for (String modelName : allModels.keySet()) { - final CodegenModel codegenModel = allModels.get(modelName); - if (!codegenModel.vendorExtensions.containsKey("x-is-composed-model")) { - continue; + } + + /** + * Fix up all parent and interface CodegenModel references. + * @param allModels + */ + protected void fixUpParentAndInterfaces(CodegenModel codegenModel, Map allModels) { + if (codegenModel.parent != null) { + codegenModel.parentModel = allModels.get(codegenModel.parent); + } + if (codegenModel.interfaces != null && !codegenModel.interfaces.isEmpty()) { + codegenModel.interfaceModels = new ArrayList(codegenModel.interfaces.size()); + for (String intf : codegenModel.interfaces) { + CodegenModel intfModel = allModels.get(intf); + if (intfModel != null) { + codegenModel.interfaceModels.add(intfModel); + } } - List modelNames = (List) codegenModel.vendorExtensions.get("x-model-names"); - if (modelNames == null || modelNames.isEmpty()) { - continue; + } + CodegenModel parent = codegenModel.parentModel; + // if a discriminator exists on the parent, don't add this child to the inheritance hierarchy + // TODO Determine what to do if the parent discriminator name == the grandparent discriminator name + while (parent != null) { + if (parent.children == null) { + parent.children = new ArrayList(); } - for (String name : modelNames) { - final CodegenModel model = allModels.get(name); - if (model == null) { - continue; - } - if (model.interfaceModels == null) { - model.interfaceModels = new ArrayList<>(); - } - if (!model.interfaceModels.stream().anyMatch(value -> value.name.equalsIgnoreCase(modelName))) { - model.interfaceModels.add(codegenModel); - } + parent.children.add(codegenModel); + if (parent.discriminator == null) { + parent = allModels.get(parent.parent); + } else { + parent = null; } } - return processedModels; } // override with any special post-processing @@ -318,21 +350,40 @@ public void processModelEnums(Map objs) { Map enumVar = new HashMap(); String enumName = findEnumName(truncateIdx, value); enumVar.put("name", toEnumVarName(enumName, cm.dataType)); - enumVar.put("value", toEnumValue(value.toString(), cm.dataType)); + if (value == null) { + enumVar.put("value", toEnumValue(null, cm.dataType)); + } else { + enumVar.put("value", toEnumValue(value.toString(), cm.dataType)); + } enumVars.add(enumVar); } cm.allowableValues.put("enumVars", enumVars); } + updateCodegenModelEnumVars(cm); + } + } - // update codegen property enum with proper naming convention - // and handling of numbers, special characters - for (CodegenProperty var : cm.vars) { - updateCodegenPropertyEnum(var); - } + public boolean isPrimivite(String datatype) { + return "number".equalsIgnoreCase(datatype) + || "integer".equalsIgnoreCase(datatype) + || "boolean".equalsIgnoreCase(datatype); + } + + /** + * update codegen property enum with proper naming convention + * and handling of numbers, special characters + * @param codegenModel + */ + protected void updateCodegenModelEnumVars(CodegenModel codegenModel) { + for (CodegenProperty var : codegenModel.vars) { + updateCodegenPropertyEnum(var); } } private String findEnumName(int truncateIdx, Object value) { + if (value == null) { + return "null"; + } String enumName; if (truncateIdx == 0) { enumName = value.toString(); @@ -346,21 +397,25 @@ private String findEnumName(int truncateIdx, Object value) { } /** - * Returns the common prefix of variables for enum naming + * Returns the common prefix of variables for enum naming if + * two or more variables are present. * * @param vars List of variable names * @return the common prefix for naming */ public String findCommonPrefixOfVars(List vars) { - try { - String[] listStr = vars.toArray(new String[vars.size()]); - String prefix = StringUtils.getCommonPrefix(listStr); - // exclude trailing characters that should be part of a valid variable - // e.g. ["status-on", "status-off"] => "status-" (not "status-o") - return prefix.replaceAll("[a-zA-Z0-9]+\\z", ""); - } catch (ArrayStoreException e) { - return ""; + if (vars.size() > 1) { + try { + String[] listStr = vars.toArray(new String[vars.size()]); + String prefix = StringUtils.getCommonPrefix(listStr); + // exclude trailing characters that should be part of a valid variable + // e.g. ["status-on", "status-off"] => "status-" (not "status-o") + return prefix.replaceAll("[a-zA-Z0-9]+\\z", ""); + } catch (ArrayStoreException e) { + // do nothing, just return default value + } } + return ""; } /** @@ -383,6 +438,9 @@ public String toEnumDefaultValue(String value, String datatype) { * @return the sanitized value for enum */ public String toEnumValue(String value, String datatype) { + if (value == null) { + return null; + } if ("number".equalsIgnoreCase(datatype)) { return value; } else { @@ -547,6 +605,10 @@ public String embeddedTemplateDir() { } } + public String customTemplateDir() { + return this.customTemplateDir; + } + public String getCommonTemplateDir() { return this.commonTemplateDir; } @@ -1075,7 +1137,7 @@ private static String getTypeOfSchema(Schema schema) { } else if (schema instanceof BinarySchema) { return SchemaTypeUtil.BINARY_FORMAT; } else if (schema instanceof FileSchema) { - return "file"; // FIXME: this type does not exist in the OpenAPI 3.0 specification + return SchemaTypeUtil.BINARY_FORMAT; } else if (schema instanceof BooleanSchema) { return SchemaTypeUtil.BOOLEAN_TYPE; } else if (schema instanceof DateSchema) { @@ -1098,15 +1160,23 @@ private static String getTypeOfSchema(Schema schema) { } } else if (schema instanceof MapSchema) { return "map"; + } else if (schema instanceof ObjectSchema) { + return "object"; } else if (schema instanceof UUIDSchema) { return "UUID"; } else if (schema instanceof StringSchema) { return "string"; + } else if (schema instanceof ComposedSchema && schema.getExtensions() != null && schema.getExtensions().containsKey("x-model-name")) { + return schema.getExtensions().get("x-model-name").toString(); + } else { if (schema != null) { if (SchemaTypeUtil.OBJECT_TYPE.equals(schema.getType()) && (hasSchemaProperties(schema) || hasTrueAdditionalProperties(schema))) { return "map"; } else { + if (schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty()) { + return "object"; + } return schema.getType(); } } @@ -1236,6 +1306,9 @@ public String toModelName(final String name) { * @return Codegen Model object */ public CodegenModel fromModel(String name, Schema schema) { + if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getSchemas() != null) { + return fromModel(name, schema, openAPI.getComponents().getSchemas()); + } return fromModel(name, schema, null); } @@ -1272,6 +1345,9 @@ public CodegenModel fromModel(String name, Schema schema, Map al codegenModel.getVendorExtensions().put(CodegenConstants.IS_ALIAS_EXT_NAME, typeAliases.containsKey(name)); codegenModel.discriminator = schema.getDiscriminator(); + if (codegenModel.discriminator != null && codegenModel.discriminator.getPropertyName() != null) { + codegenModel.discriminator.setPropertyName(toVarName(codegenModel.discriminator.getPropertyName())); + } if (schema.getXml() != null) { codegenModel.xmlPrefix = schema.getXml().getPrefix(); @@ -1286,12 +1362,7 @@ public CodegenModel fromModel(String name, Schema schema, Map al addParentContainer(codegenModel, name, schema); } else if (schema instanceof MapSchema) { - codegenModel.getVendorExtensions().put(CodegenConstants.IS_MAP_CONTAINER_EXT_NAME, Boolean.TRUE); - codegenModel.getVendorExtensions().put(IS_CONTAINER_EXT_NAME, Boolean.TRUE); - addParentContainer(codegenModel, name, schema); - if (hasSchemaProperties(schema) || hasTrueAdditionalProperties(schema)) { - addAdditionPropertiesToCodeGenModel(codegenModel, schema); - } + processMapSchema(codegenModel, name, schema); } else if (schema instanceof ComposedSchema) { @@ -1308,7 +1379,7 @@ else if (schema instanceof ComposedSchema) { if(composed.getAllOf() != null) { for (Schema innerModel : composed.getAllOf()) { if (codegenModel.discriminator == null) { - codegenModel.discriminator = schema + codegenModel.discriminator = innerModel .getDiscriminator(); } if (innerModel.getXml() != null) { @@ -1334,17 +1405,13 @@ else if (schema instanceof ComposedSchema) { // parent model final String parentName = getParentName(composed); final Schema parent = StringUtils.isBlank(parentName) ? null : allDefinitions.get(parentName); - final List allOf = composed.getAllOf(); - final List oneOf = composed.getOneOf(); - final List anyOf = composed.getAnyOf(); - // interfaces (intermediate models) if (allOf != null && !allOf.isEmpty()) { - if (codegenModel.interfaces == null) { - codegenModel.interfaces = new ArrayList(); - } - for (int i = 1; i < allOf.size(); i++) { + for (int i = 0; i < allOf.size(); i++) { + if (i == 0 && !copyFistAllOfProperties) { + continue; + } Schema interfaceSchema = allOf.get(i); if (StringUtils.isBlank(interfaceSchema.get$ref())) { continue; @@ -1355,7 +1422,6 @@ else if (schema instanceof ComposedSchema) { refSchema = allDefinitions.get(ref); } final String modelName = toModelName(ref); - codegenModel.interfaces.add(modelName); addImport(codegenModel, modelName); if (allDefinitions != null && refSchema != null) { if (!supportsMixins) { @@ -1367,15 +1433,10 @@ else if (schema instanceof ComposedSchema) { } } } - if (oneOf != null && !oneOf.isEmpty()) { - this.schemaHandler.configureOneOfModel(codegenModel, oneOf); - } - if (anyOf != null && !anyOf.isEmpty()) { - this.schemaHandler.configureAnyOfModel(codegenModel, anyOf); - } + if (parent != null) { codegenModel.parentSchema = parentName; - codegenModel.parent = toModelName(parentName); + codegenModel.parent = typeMapping.containsKey(parentName) ? typeMapping.get(parentName): toModelName(parentName); addImport(codegenModel, codegenModel.parent); if (allDefinitions != null) { if (supportsInheritance) { @@ -1398,7 +1459,12 @@ else if (schema instanceof ComposedSchema) { // comment out below as allowableValues is not set in post processing model enum codegenModel.allowableValues = new HashMap(); codegenModel.allowableValues.put("values", schema.getEnum()); + if (codegenModel.dataType.equals("BigDecimal")) { + addImport(codegenModel, "BigDecimal"); + } } + codegenModel.getVendorExtensions().put(CodegenConstants.IS_NULLABLE_EXT_NAME, Boolean.TRUE.equals(schema.getNullable())); + addVars(codegenModel, schema.getProperties(), schema.getRequired()); } @@ -1407,9 +1473,19 @@ else if (schema instanceof ComposedSchema) { postProcessModelProperty(codegenModel, prop); } } + return codegenModel; } + protected void processMapSchema(CodegenModel codegenModel, String name, Schema schema) { + codegenModel.getVendorExtensions().put(CodegenConstants.IS_MAP_CONTAINER_EXT_NAME, Boolean.TRUE); + codegenModel.getVendorExtensions().put(IS_CONTAINER_EXT_NAME, Boolean.TRUE); + addParentContainer(codegenModel, name, schema); + if (hasSchemaProperties(schema) || hasTrueAdditionalProperties(schema)) { + addAdditionPropertiesToCodeGenModel(codegenModel, schema); + } + } + /** * Recursively look for a discriminator in the interface tree */ @@ -1437,21 +1513,21 @@ protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Sc } protected void addProperties(Map properties, List required, Schema schema, Map allSchemas) { - if(schema instanceof ComposedSchema) { - ComposedSchema composedSchema = (ComposedSchema) schema; - if(composedSchema.getAllOf() == null || composedSchema.getAllOf().isEmpty() || composedSchema.getAllOf().size() == 1) { - return; - } - for (int i = 1; i < composedSchema.getAllOf().size(); i++) { - addProperties(properties, required, composedSchema.getAllOf().get(i), allSchemas); - } - return; - } if(StringUtils.isNotBlank(schema.get$ref())) { Schema interfaceSchema = allSchemas.get(OpenAPIUtil.getSimpleRef(schema.get$ref())); addProperties(properties, required, interfaceSchema, allSchemas); return; } + + if(schema instanceof ComposedSchema) { + ComposedSchema composedSchema = (ComposedSchema) schema; + if(!(composedSchema.getAllOf() == null || composedSchema.getAllOf().isEmpty() || composedSchema.getAllOf().size() == 1)) { + for (int i = 1; i < composedSchema.getAllOf().size(); i++) { + addProperties(properties, required, composedSchema.getAllOf().get(i), allSchemas); + } + } + } + if(schema.getProperties() != null) { properties.putAll(schema.getProperties()); } @@ -1491,37 +1567,62 @@ public CodegenProperty fromProperty(String name, Schema propertySchema) { codegenProperty.name = toVarName(name); codegenProperty.baseName = name; codegenProperty.nameInCamelCase = camelize(codegenProperty.name, false); - codegenProperty.description = escapeText(propertySchema.getDescription()); - codegenProperty.unescapedDescription = propertySchema.getDescription(); - codegenProperty.title = propertySchema.getTitle(); codegenProperty.getter = toGetter(name); codegenProperty.setter = toSetter(name); - String example = toExampleValue(propertySchema); + setSchemaProperties(name, codegenProperty, propertySchema); + + final String type = getSchemaType(propertySchema); + + processPropertySchemaTypes(name, codegenProperty, propertySchema); + + codegenProperty.datatype = getTypeDeclaration(propertySchema); + codegenProperty.dataFormat = propertySchema.getFormat(); + + // this can cause issues for clients which don't support enums + boolean isEnum = getBooleanValue(codegenProperty, IS_ENUM_EXT_NAME); + if (isEnum) { + codegenProperty.datatypeWithEnum = toEnumName(codegenProperty); + codegenProperty.enumName = toEnumName(codegenProperty); + } else { + codegenProperty.datatypeWithEnum = codegenProperty.datatype; + } + + codegenProperty.baseType = getSchemaType(propertySchema); + + processPropertySchemaContainerTypes(codegenProperty, propertySchema, type); + return codegenProperty; + } + + protected void setSchemaProperties(String name, CodegenProperty codegenProperty, Schema schema) { + codegenProperty.description = escapeText(schema.getDescription()); + codegenProperty.unescapedDescription = schema.getDescription(); + codegenProperty.title = schema.getTitle(); + String example = toExampleValue(schema); if(!"null".equals(example)) { codegenProperty.example = example; } - codegenProperty.defaultValue = toDefaultValue(propertySchema); - codegenProperty.defaultValueWithParam = toDefaultValueWithParam(name, propertySchema); - codegenProperty.jsonSchema = Json.pretty(propertySchema); - if (propertySchema.getNullable() != null) { - codegenProperty.nullable = propertySchema.getNullable(); + codegenProperty.defaultValue = toDefaultValue(schema); + codegenProperty.defaultValueWithParam = toDefaultValueWithParam(name, schema); + codegenProperty.jsonSchema = Json.pretty(schema); + codegenProperty.nullable = Boolean.TRUE.equals(schema.getNullable()); + codegenProperty.getVendorExtensions().put(CodegenConstants.IS_NULLABLE_EXT_NAME, Boolean.TRUE.equals(schema.getNullable())); + if (schema.getReadOnly() != null) { + codegenProperty.getVendorExtensions().put(CodegenConstants.IS_READ_ONLY_EXT_NAME, schema.getReadOnly()); } - if (propertySchema.getReadOnly() != null) { - codegenProperty.getVendorExtensions().put(CodegenConstants.IS_READ_ONLY_EXT_NAME, propertySchema.getReadOnly()); - } - if (propertySchema.getXml() != null) { - if (propertySchema.getXml().getAttribute() != null) { - codegenProperty.getVendorExtensions().put(CodegenConstants.IS_XML_ATTRIBUTE_EXT_NAME, propertySchema.getXml().getAttribute()); + if (schema.getXml() != null) { + if (schema.getXml().getAttribute() != null) { + codegenProperty.getVendorExtensions().put(CodegenConstants.IS_XML_ATTRIBUTE_EXT_NAME, schema.getXml().getAttribute()); } - codegenProperty.xmlPrefix = propertySchema.getXml().getPrefix(); - codegenProperty.xmlName = propertySchema.getXml().getName(); - codegenProperty.xmlNamespace = propertySchema.getXml().getNamespace(); + codegenProperty.xmlPrefix = schema.getXml().getPrefix(); + codegenProperty.xmlName = schema.getXml().getName(); + codegenProperty.xmlNamespace = schema.getXml().getNamespace(); } - if (propertySchema.getExtensions() != null && !propertySchema.getExtensions().isEmpty()) { - codegenProperty.getVendorExtensions().putAll(propertySchema.getExtensions()); + if (schema.getExtensions() != null && !schema.getExtensions().isEmpty()) { + codegenProperty.getVendorExtensions().putAll(schema.getExtensions()); } + } - final String type = getSchemaType(propertySchema); + protected void processPropertySchemaTypes(String name, CodegenProperty codegenProperty, Schema propertySchema) { if (propertySchema instanceof IntegerSchema) { codegenProperty.getVendorExtensions().put(CodegenConstants.IS_NUMERIC_EXT_NAME, Boolean.TRUE); if(SchemaTypeUtil.INTEGER64_FORMAT.equals(propertySchema.getFormat())) { @@ -1558,7 +1659,6 @@ public CodegenProperty fromProperty(String name, Schema propertySchema) { codegenProperty.allowableValues = allowableValues; } } - if (propertySchema instanceof StringSchema) { codegenProperty.maxLength = propertySchema.getMaxLength(); codegenProperty.minLength = propertySchema.getMinLength(); @@ -1629,20 +1729,9 @@ public CodegenProperty fromProperty(String name, Schema propertySchema) { codegenProperty.getVendorExtensions().put(CodegenConstants.IS_DATE_TIME_EXT_NAME, Boolean.TRUE); handlePropertySchema(propertySchema, codegenProperty); } - codegenProperty.datatype = getTypeDeclaration(propertySchema); - codegenProperty.dataFormat = propertySchema.getFormat(); - - // this can cause issues for clients which don't support enums - boolean isEnum = getBooleanValue(codegenProperty, IS_ENUM_EXT_NAME); - if (isEnum) { - codegenProperty.datatypeWithEnum = toEnumName(codegenProperty); - codegenProperty.enumName = toEnumName(codegenProperty); - } else { - codegenProperty.datatypeWithEnum = codegenProperty.datatype; - } - - codegenProperty.baseType = getSchemaType(propertySchema); + } + protected void processPropertySchemaContainerTypes(CodegenProperty codegenProperty, Schema propertySchema, String type) { if (propertySchema instanceof ArraySchema) { codegenProperty.getVendorExtensions().put(CodegenConstants.IS_CONTAINER_EXT_NAME, Boolean.TRUE); codegenProperty.getVendorExtensions().put(CodegenConstants.IS_LIST_CONTAINER_EXT_NAME, Boolean.TRUE); @@ -1680,10 +1769,6 @@ public CodegenProperty fromProperty(String name, Schema propertySchema) { // handle inner property CodegenProperty cp = fromProperty("inner", (Schema) propertySchema.getAdditionalProperties()); updatePropertyForMap(codegenProperty, cp); - } else if (propertySchema instanceof ComposedSchema) { - ComposedSchema composedProperty = (ComposedSchema) propertySchema; - Map schemas = this.openAPI.getComponents() != null ? this.openAPI.getComponents().getSchemas() : null; - this.schemaHandler.createCodegenModel(composedProperty, codegenProperty); } else if (propertySchema instanceof MapSchema && hasTrueAdditionalProperties(propertySchema)) { codegenProperty.getVendorExtensions().put(CodegenConstants.IS_CONTAINER_EXT_NAME, Boolean.TRUE); @@ -1697,9 +1782,11 @@ public CodegenProperty fromProperty(String name, Schema propertySchema) { CodegenProperty cp = fromProperty("inner", new ObjectSchema()); updatePropertyForMap(codegenProperty, cp); } else { + if (isObjectSchema(propertySchema)) { + codegenProperty.getVendorExtensions().put("x-is-object", Boolean.TRUE); + } setNonArrayMapProperty(codegenProperty, type); } - return codegenProperty; } private void handleMinMaxValues(Schema propertySchema, CodegenProperty codegenProperty) { @@ -1989,7 +2076,9 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation codegenOperation.returnBaseType = codegenProperty.baseType; } } - codegenOperation.examples = new ExampleGenerator(openAPI).generate(null, null, responseSchema); + if (!additionalProperties.containsKey(CodegenConstants.DISABLE_EXAMPLES_OPTION)) { + codegenOperation.examples = new ExampleGenerator(openAPI).generate(null, null, responseSchema); + } codegenOperation.defaultResponse = toDefaultValue(responseSchema); codegenOperation.returnType = codegenProperty.datatype; boolean hasReference = schemas != null && schemas.containsKey(codegenOperation.returnBaseType); @@ -2021,22 +2110,16 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation codegenOperation.returnTypeIsPrimitive = true; } } - addHeaders(methodResponse, codegenOperation.responseHeaders); + Map componentHeaders = null; + if ((openAPI != null) && (openAPI.getComponents() != null)) { + componentHeaders = openAPI.getComponents().getHeaders(); + } + addHeaders(methodResponse, codegenOperation.responseHeaders, componentHeaders); } } List parameters = operation.getParameters(); - CodegenParameter bodyParam = null; - List allParams = new ArrayList<>(); - List bodyParams = new ArrayList<>(); - List pathParams = new ArrayList<>(); - List queryParams = new ArrayList<>(); - List headerParams = new ArrayList<>(); - List cookieParams = new ArrayList<>(); - List formParams = new ArrayList<>(); - List requiredParams = new ArrayList<>(); - - List codegenContents = new ArrayList<>(); + final OperationParameters operationParameters = new OperationParameters(); RequestBody body = operation.getRequestBody(); if (body != null) { @@ -2054,6 +2137,11 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation Schema schema = body.getContent().get(contentType).getSchema(); if (schema != null && StringUtils.isNotBlank(schema.get$ref())) { schemaName = OpenAPIUtil.getSimpleRef(schema.get$ref()); + try { + schemaName = URLDecoder.decode(schemaName, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + LOGGER.error("Could not decoded string: " + schemaName, e); + } schema = schemas.get(schemaName); } final CodegenContent codegenContent = new CodegenContent(contentType); @@ -2063,8 +2151,12 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation CodegenParameter codegenParameter = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); codegenParameter.description = body.getDescription(); codegenParameter.unescapedDescription = body.getDescription(); - codegenParameter.baseName = REQUEST_BODY_NAME; - codegenParameter.paramName = REQUEST_BODY_NAME; + String bodyName = REQUEST_BODY_NAME; + if (body.getExtensions() != null && body.getExtensions().get("x-codegen-request-body-name") != null) { + bodyName = body.getExtensions().get("x-codegen-request-body-name").toString(); + } + codegenParameter.baseName = bodyName; + codegenParameter.paramName = bodyName; codegenParameter.dataType = "Object"; codegenParameter.baseType = "Object"; @@ -2088,22 +2180,20 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation } // todo: this segment is only to support the "older" template design. it should be removed once all templates are updated with the new {{#contents}} tag. formParameter.getVendorExtensions().put(CodegenConstants.IS_FORM_PARAM_EXT_NAME, Boolean.TRUE); - formParams.add(formParameter.copy()); + operationParameters.addFormParam(formParameter.copy()); if (body.getRequired() != null && body.getRequired()) { - requiredParams.add(formParameter.copy()); + operationParameters.addRequiredParam(formParameter.copy()); } - allParams.add(formParameter); - - codegenContent.getParameters().add(formParameter.copy()); + operationParameters.addAllParams(formParameter); } - codegenContents.add(codegenContent); + operationParameters.addCodegenContents(codegenContent); } } else { - bodyParam = fromRequestBody(body, schemaName, schema, schemas, imports); + CodegenParameter bodyParam = fromRequestBody(body, schemaName, schema, schemas, imports); + operationParameters.setBodyParam(bodyParam); if (foundSchemas.isEmpty()) { - // todo: this segment is only to support the "older" template design. it should be removed once all templates are updated with the new {{#contents}} tag. - bodyParams.add(bodyParam.copy()); - allParams.add(bodyParam); + operationParameters.addBodyParams(bodyParam.copy()); + operationParameters.addAllParams(bodyParam); } else { boolean alreadyAdded = false; for (Schema usedSchema : foundSchemas) { @@ -2116,8 +2206,7 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation } } foundSchemas.add(schema); - codegenContent.getParameters().add(bodyParam.copy()); - codegenContents.add(codegenContent); + operationParameters.addCodegenContents(codegenContent); } } } @@ -2127,84 +2216,30 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation if (StringUtils.isNotBlank(param.get$ref())) { param = getParameterFromRef(param.get$ref(), openAPI); } - CodegenParameter codegenParameter = fromParameter(param, imports); - // rename parameters to make sure all of them have unique names - if (ensureUniqueParams) { - while (true) { - boolean exists = false; - for (CodegenParameter cp : allParams) { - if (codegenParameter.paramName.equals(cp.paramName)) { - exists = true; - break; - } - } - if (exists) { - codegenParameter.paramName = generateNextName(codegenParameter.paramName); - } else { - break; - } - } - } - - // set isPrimitiveType and baseType for allParams - /*if (languageSpecificPrimitives.contains(p.baseType)) { - p.isPrimitiveType = true; - p.baseType = getSwaggerType(p); - }*/ - - - allParams.add(codegenParameter); - // Issue #2561 (neilotoole) : Moved setting of isParam flags - // from here to fromParameter(). - if (param instanceof QueryParameter || "query".equalsIgnoreCase(param.getIn())) { - queryParams.add(codegenParameter.copy()); - } else if (param instanceof PathParameter || "path".equalsIgnoreCase(param.getIn())) { - pathParams.add(codegenParameter.copy()); - } else if (param instanceof HeaderParameter || "header".equalsIgnoreCase(param.getIn())) { - headerParams.add(codegenParameter.copy()); - } else if (param instanceof CookieParameter || "cookie".equalsIgnoreCase(param.getIn())) { - cookieParams.add(codegenParameter.copy()); - } - if (!codegenParameter.required) { - codegenOperation.getVendorExtensions().put(CodegenConstants.HAS_OPTIONAL_PARAMS_EXT_NAME, Boolean.TRUE); - } else { - requiredParams.add(codegenParameter.copy()); + if ((param instanceof QueryParameter || "query".equalsIgnoreCase(param.getIn())) + && param.getStyle() != null && param.getStyle().equals(Parameter.StyleEnum.DEEPOBJECT)) { + operationParameters.parseNestedObjects(param.getName(), param.getSchema(), imports, this, openAPI); + continue; } + CodegenParameter codegenParameter = fromParameter(param, imports); + operationParameters.addParameters(param, codegenParameter); } } - for (String i : imports) { - if (needToImport(i)) { - codegenOperation.imports.add(i); - } - } + addOperationImports(codegenOperation, imports); - codegenOperation.bodyParam = bodyParam; + codegenOperation.bodyParam = operationParameters.getBodyParam(); codegenOperation.httpMethod = httpMethod.toUpperCase(); // move "required" parameters in front of "optional" parameters if (sortParamsByRequiredFlag) { - Collections.sort(allParams, new Comparator() { - @Override - public int compare(CodegenParameter one, CodegenParameter another) { - if (one.required == another.required) return 0; - else if (one.required) return -1; - else return 1; - } - }); + operationParameters.sortRequiredAllParams(); } - codegenOperation.allParams = addHasMore(allParams); - codegenOperation.bodyParams = addHasMore(bodyParams); - codegenOperation.pathParams = addHasMore(pathParams); - codegenOperation.queryParams = addHasMore(queryParams); - codegenOperation.headerParams = addHasMore(headerParams); - // op.cookieParams = cookieParams; - codegenOperation.formParams = addHasMore(formParams); - codegenOperation.requiredParams = addHasMore(requiredParams); + operationParameters.addHasMore(codegenOperation); codegenOperation.externalDocs = operation.getExternalDocs(); - configuresParameterForMediaType(codegenOperation, codegenContents); + configuresParameterForMediaType(codegenOperation, operationParameters.getCodegenContents()); // legacy support codegenOperation.nickname = codegenOperation.operationId; @@ -2214,6 +2249,10 @@ public int compare(CodegenParameter one, CodegenParameter another) { boolean hasRequiredParams = codegenOperation.requiredParams.size() > 0; codegenOperation.getVendorExtensions().put(CodegenConstants.HAS_REQUIRED_PARAMS_EXT_NAME, hasRequiredParams); + boolean hasOptionalParams = codegenOperation.allParams.stream() + .anyMatch(codegenParameter -> !codegenParameter.required); + codegenOperation.getVendorExtensions().put(CodegenConstants.HAS_OPTIONAL_PARAMS_EXT_NAME, hasOptionalParams); + // set Restful Flag codegenOperation.getVendorExtensions().put(CodegenConstants.IS_RESTFUL_SHOW_EXT_NAME, codegenOperation.getIsRestfulShow()); codegenOperation.getVendorExtensions().put(CodegenConstants.IS_RESTFUL_INDEX_EXT_NAME, codegenOperation.getIsRestfulIndex()); @@ -2227,6 +2266,14 @@ public int compare(CodegenParameter one, CodegenParameter another) { return codegenOperation; } + protected void addOperationImports(CodegenOperation codegenOperation, Set operationImports) { + for (String operationImport : operationImports) { + if (needToImport(operationImport)) { + codegenOperation.imports.add(operationImport); + } + } + } + /** * Convert Swagger Response object to Codegen Response object * @@ -2244,12 +2291,35 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) { final Schema responseSchema = getSchemaFromResponse(response); codegenResponse.schema = responseSchema; codegenResponse.message = escapeText(response.getDescription()); - // TODO: codegenResponse.examples = toExamples(response.getExamples()); + + if (response.getContent()!= null) { + Map examples = new HashMap<>(); + for (String name : response.getContent().keySet()) { + if (response.getContent().get(name) != null) { + + if (response.getContent().get(name).getExample() != null) { + examples.put(name, response.getContent().get(name).getExample()); + } + if (response.getContent().get(name).getExamples() != null) { + + for (String exampleName : response.getContent().get(name).getExamples().keySet()) { + examples.put(exampleName, response.getContent().get(name).getExamples().get(exampleName).getValue()); + } + } + } + } + codegenResponse.examples = toExamples(examples); + } + codegenResponse.jsonSchema = Json.pretty(response); if (response.getExtensions() != null && !response.getExtensions().isEmpty()) { codegenResponse.vendorExtensions.putAll(response.getExtensions()); } - addHeaders(response, codegenResponse.headers); + Map componentHeaders = null; + if ((openAPI != null) && (openAPI.getComponents() != null)) { + componentHeaders = openAPI.getComponents().getHeaders(); + } + addHeaders(response, codegenResponse.headers, componentHeaders); codegenResponse.getVendorExtensions().put(CodegenConstants.HAS_HEADERS_EXT_NAME, !codegenResponse.headers.isEmpty()); if (responseSchema != null) { @@ -2269,6 +2339,9 @@ public CodegenResponse fromResponse(String responseCode, ApiResponse response) { } else { codegenResponse.baseType = codegenProperty.baseType; } + if (isFileTypeSchema(responseSchema)) { + codegenResponse.getVendorExtensions().put(CodegenConstants.IS_FILE_EXT_NAME, Boolean.TRUE); + } } codegenResponse.dataType = codegenProperty.datatype; @@ -2346,12 +2419,32 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) LOGGER.info("working on Parameter " + parameter.getName()); } + // move the defaultValue for headers, forms and params + if (parameter instanceof QueryParameter) { + QueryParameter qp = (QueryParameter) parameter; + if (qp.getSchema() != null) { + if (qp.getSchema().getDefault() != null) { + codegenParameter.defaultValue = qp.getSchema().getDefault().toString(); + } + } + } else if (parameter instanceof HeaderParameter) { + HeaderParameter hp = (HeaderParameter) parameter; + if (hp.getSchema() != null) { + if (hp.getSchema().getDefault() != null) { + codegenParameter.defaultValue = hp.getSchema().getDefault().toString(); + } + } + } + if (parameter.getExtensions() != null && !parameter.getExtensions().isEmpty()) { codegenParameter.vendorExtensions.putAll(parameter.getExtensions()); } - if (parameter.getSchema() != null) { - Schema parameterSchema = parameter.getSchema(); + Schema parameterSchema = parameter.getSchema(); + if (parameterSchema == null) { + parameterSchema = getSchemaFromParameter(parameter); + } + if (parameterSchema != null) { String collectionFormat = null; if (parameterSchema instanceof ArraySchema) { // for array parameter final ArraySchema arraySchema = (ArraySchema) parameterSchema; @@ -2361,6 +2454,9 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) inner = new StringSchema().description("//TODO automatically added by swagger-codegen"); arraySchema.setItems(inner); + } else if (isObjectSchema(inner)) { + //fixme: codegenParameter.getVendorExtensions().put(CodegenConstants.HAS_INNER_OBJECT_NAME, Boolean.TRUE); + codegenParameter.getVendorExtensions().put("x-has-inner-object", Boolean.TRUE); } collectionFormat = getCollectionFormat(parameter); @@ -2409,14 +2505,14 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) LOGGER.warn("warning! Schema not found for parameter \"" + parameter.getName() + "\", using String"); parameterSchema = new StringSchema().description("//TODO automatically added by swagger-codegen."); } - if (Boolean.TRUE.equals(parameterSchema.getNullable())) { - codegenParameter.nullable = true; - } CodegenProperty codegenProperty = fromProperty(parameter.getName(), parameterSchema); // set boolean flag (e.g. isString) setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); - setParameterNullable(codegenParameter, codegenProperty); + setParameterNullable(codegenParameter, codegenProperty); //todo: needs to be removed + + codegenParameter.nullable = Boolean.TRUE.equals(parameterSchema.getNullable()); + codegenParameter.getVendorExtensions().put(CodegenConstants.IS_NULLABLE_EXT_NAME, Boolean.TRUE.equals(parameterSchema.getNullable())); codegenParameter.dataType = codegenProperty.datatype; codegenParameter.dataFormat = codegenProperty.dataFormat; @@ -2550,8 +2646,13 @@ else if (parameter instanceof FormParameter) { public CodegenParameter fromRequestBody(RequestBody body, String name, Schema schema, Map schemas, Set imports) { CodegenParameter codegenParameter = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); - codegenParameter.baseName = REQUEST_BODY_NAME; - codegenParameter.paramName = REQUEST_BODY_NAME; + + String bodyName = REQUEST_BODY_NAME; + if (body.getExtensions() != null && body.getExtensions().get("x-codegen-request-body-name") != null) { + bodyName = body.getExtensions().get("x-codegen-request-body-name").toString(); + } + codegenParameter.baseName = bodyName; + codegenParameter.paramName = bodyName; codegenParameter.description = body.getDescription(); codegenParameter.unescapedDescription = body.getDescription(); codegenParameter.required = body.getRequired() != null ? body.getRequired() : Boolean.FALSE; @@ -2585,7 +2686,7 @@ public CodegenParameter fromRequestBody(RequestBody body, String name, Schema sc schema.setName(name); codegenModel = fromModel(name, schema, schemas); } - if (codegenModel != null && !codegenModel.emptyVars) { + if (codegenModel != null) { codegenParameter.baseType = codegenModel.classname; codegenParameter.dataType = getTypeDeclaration(codegenModel.classname); imports.add(codegenParameter.dataType); @@ -2617,6 +2718,9 @@ else if (schema instanceof ArraySchema) { if (inner == null) { inner = new StringSchema().description("//TODO automatically added by swagger-codegen"); arraySchema.setItems(inner); + } else if (isObjectSchema(inner)) { + //fixme: codegenParameter.getVendorExtensions().put(CodegenConstants.HAS_INNER_OBJECT_NAME, Boolean.TRUE); + codegenParameter.getVendorExtensions().put("x-has-inner-object", Boolean.TRUE); } CodegenProperty codegenProperty = fromProperty("property", schema); @@ -2625,7 +2729,9 @@ else if (schema instanceof ArraySchema) { if (codegenProperty.complexType != null) { imports.add(codegenProperty.complexType); } - imports.add(codegenProperty.baseType); + if (codegenParameter.baseType != null) { + imports.add(codegenProperty.baseType); + } CodegenProperty innerCp = codegenProperty; while(innerCp != null) { if(innerCp.complexType != null) { @@ -2645,7 +2751,9 @@ else if (schema instanceof ArraySchema) { setParameterNullable(codegenParameter, codegenProperty); while (codegenProperty != null) { - imports.add(codegenProperty.baseType); + if (codegenProperty.baseType != null) { + imports.add(codegenProperty.baseType); + } codegenProperty = codegenProperty.items; } } @@ -2655,7 +2763,7 @@ else if (schema instanceof BinarySchema) { codegenParameter.getVendorExtensions().put(CodegenConstants.IS_BINARY_EXT_NAME, Boolean.TRUE); } else { - CodegenProperty codegenProperty = fromProperty(REQUEST_BODY_NAME, schema); + CodegenProperty codegenProperty = fromProperty(bodyName, schema); codegenParameter.dataType = codegenProperty.datatype; codegenParameter.baseType = codegenProperty.baseType; if (codegenProperty.complexType != null) { @@ -2714,6 +2822,13 @@ public List fromSecurity(Map securitySc } else if (SecurityScheme.Type.HTTP.equals(schemeDefinition.getType())) { if ("bearer".equalsIgnoreCase(schemeDefinition.getScheme())) { codegenSecurity.getVendorExtensions().put(CodegenConstants.IS_BEARER_EXT_NAME, Boolean.TRUE); + final Map extensions = schemeDefinition.getExtensions(); + if (extensions != null && extensions.get("x-token-example") != null) { + final String tokenExample = extensions.get("x-token-example").toString(); + if (StringUtils.isNotBlank(tokenExample)) { + codegenSecurity.getVendorExtensions().put("x-token-example", tokenExample); + } + } } else { codegenSecurity.getVendorExtensions().put(CodegenConstants.IS_BASIC_EXT_NAME, Boolean.TRUE); } @@ -2775,6 +2890,11 @@ protected void setReservedWordsLowerCase(List words) { } } + protected void setReservedWords(List words) { + reservedWords = new HashSet(); + reservedWords.addAll(words); + } + protected boolean isReservedWord(String word) { return word != null && reservedWords.contains(word.toLowerCase()); } @@ -2842,22 +2962,20 @@ protected List> toExamples(Map examples) { return output; } - private void addHeaders(ApiResponse response, List target) { + private void addHeaders(ApiResponse response, List target, Map componentHeaders) { if (response.getHeaders() != null) { for (Map.Entry headers : response.getHeaders().entrySet()) { - target.add(fromProperty(headers.getKey(), headers.getValue().getSchema())); - } - } - } - - private static List addHasMore(List objs) { - if (objs != null) { - for (int i = 0; i < objs.size(); i++) { - objs.get(i).secondaryParam = i > 0; - objs.get(i).getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, i < objs.size() - 1); + Header header = headers.getValue(); + Schema schema; + if ((header.get$ref() != null) && (componentHeaders != null)) { + String ref = OpenAPIUtil.getSimpleRef(header.get$ref()); + schema = componentHeaders.get(ref).getSchema(); + } else { + schema = header.getSchema(); + } + target.add(fromProperty(headers.getKey(), schema)); } } - return objs; } private static Map addHasMore(Map objs) { @@ -2911,10 +3029,10 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera co.baseName = tag; } - private void addParentContainer(CodegenModel codegenModel, String name, Schema property) { - final CodegenProperty codegenProperty = fromProperty(name, property); + public void addParentContainer(CodegenModel codegenModel, String name, Schema schema) { + final CodegenProperty codegenProperty = fromProperty(name, schema); addImport(codegenModel, codegenProperty.complexType); - codegenModel.parent = toInstantiationType(property); + codegenModel.parent = toInstantiationType(schema); final String containerType = codegenProperty.containerType; final String instantiationType = instantiationTypes.get(containerType); if (instantiationType != null) { @@ -2935,7 +3053,7 @@ private void addParentContainer(CodegenModel codegenModel, String name, Schema p * @return The underscored version of the word */ public static String underscore(String word) { - String firstPattern = "([A-Z]+)([A-Z][a-z])"; + String firstPattern = "([A-Z]+)([A-Z][a-z][a-z]+)"; String secondPattern = "([a-z\\d])([A-Z])"; String replacementPattern = "$1_$2"; // Replace package separator with slash. @@ -2991,7 +3109,7 @@ protected void addImport(CodegenModel m, String type) { } } - private void addVars(CodegenModel codegenModel, Map properties, List required) { + protected void addVars(CodegenModel codegenModel, Map properties, List required) { addVars(codegenModel, properties, required, null, null); } @@ -3037,14 +3155,6 @@ private void addVars(CodegenModel codegenModel, List vars, Map< final CodegenProperty codegenProperty = fromProperty(key, propertySchema); codegenProperty.required = mandatory.contains(key); - if (codegenProperty.vendorExtensions.containsKey("oneOf-model")) { - this.schemaHandler.configureOneOfModelFromProperty(codegenProperty, codegenModel); - } - - if (codegenProperty.vendorExtensions.containsKey("anyOf-model")) { - this.schemaHandler.configureAnyOfModelFromProperty(codegenProperty, codegenModel); - } - if (propertySchema.get$ref() != null) { if (this.openAPI == null) { LOGGER.warn("open api utility object was not properly set."); @@ -3106,6 +3216,29 @@ private void addVars(CodegenModel codegenModel, List vars, Map< codegenModel.readWriteVars.add(codegenProperty); } } + // check if one of the property is a object and has import mapping. + List modelProperties = vars.stream() + .filter(codegenProperty -> getBooleanValue(codegenProperty, "x-is-object") && importMapping.containsKey(codegenProperty.baseType)) + .collect(Collectors.toList()); + if (modelProperties == null || modelProperties.isEmpty()) { + return; + } + + for (CodegenProperty modelProperty : modelProperties) { + List codegenProperties = vars.stream() + .filter(codegenProperty -> !getBooleanValue(codegenProperty, "x-is-object") + && importMapping.containsKey(codegenProperty.baseType) + && codegenProperty.baseType.equals(modelProperty.baseType)) + .collect(Collectors.toList()); + if (codegenProperties == null || codegenProperties.isEmpty()) { + continue; + } + for (CodegenProperty codegenProperty : codegenProperties) { + codegenModel.imports.remove(codegenProperty.baseType); + codegenProperty.datatype = importMapping.get(codegenProperty.baseType); + codegenProperty.datatypeWithEnum = codegenProperty.datatype; + } + } } /** @@ -3272,7 +3405,7 @@ public static String camelize(String word, boolean lowercaseFirstLetter) { public String apiFilename(String templateName, String tag) { String suffix = apiTemplateFiles().get(templateName); - return apiFileFolder() + '/' + toApiFilename(tag) + suffix; + return apiFileFolder() + File.separator + toApiFilename(tag) + suffix; } /** @@ -3395,6 +3528,26 @@ public String getGitRepoId() { return gitRepoId; } + + /** + * Git repo Base URL + * + * @return Git repo Base URL + */ + public String getGitRepoBaseURL() { + return gitRepoBaseURL; + } + + /** + * Set Git repo Base URL. + * + * @param gitRepoBaseURL Git repo Base URL + */ + public void setGitRepoBaseURL(String gitRepoBaseURL) { + this.gitRepoBaseURL = gitRepoBaseURL; + } + + /** * Set release note. * @@ -3594,9 +3747,7 @@ public List readLanguageArguments() { String shortOption = argument.findValue("shortOption") != null ? argument.findValue("shortOption").textValue() : null; String type = argument.findValue("type") != null ? argument.findValue("type").textValue() : "string"; boolean isArray = argument.findValue("isArray") != null ? argument.findValue("isArray").booleanValue() : false; - if (StringUtils.isBlank(option)) { - continue; - } + languageArguments.add(new CodegenArgument() .option(option) .shortOption(shortOption) @@ -3620,6 +3771,21 @@ public String getArgumentsLocation() { return null; } + protected String getOptionValue(String optionName) { + final List codegenArguments = getLanguageArguments(); + if (codegenArguments == null || codegenArguments.isEmpty()) { + return null; + } + Optional codegenArgumentOptional = codegenArguments + .stream() + .filter(argument -> argument.getOption().equalsIgnoreCase(optionName)) + .findAny(); + if (!codegenArgumentOptional.isPresent()) { + return null; + } + return codegenArgumentOptional.get().getValue(); + } + /** * Only write if the file doesn't exist * @@ -3722,18 +3888,40 @@ public void updateCodegenPropertyEnum(CodegenProperty var) { } // put "enumVars" map into `allowableValues", including `name` and `value` - List> enumVars = new ArrayList>(); + List> enumVars = new ArrayList<>(); String commonPrefix = findCommonPrefixOfVars(values); int truncateIdx = commonPrefix.length(); for (Object value : values) { Map enumVar = new HashMap(); String enumName = findEnumName(truncateIdx, value); enumVar.put("name", toEnumVarName(enumName, var.datatype)); - enumVar.put("value", toEnumValue(value.toString(), var.datatype)); + if (value == null) { + enumVar.put("value", toEnumValue(null, var.datatype)); + } else { + enumVar.put("value", toEnumValue(value.toString(), var.datatype)); + } enumVars.add(enumVar); } allowableValues.put("enumVars", enumVars); + // check repeated enum var names + if (enumVars != null & !enumVars.isEmpty()) { + for (int i = 0; i < enumVars.size(); i++) { + final Map enumVarList = enumVars.get(i); + final String enumVarName = enumVarList.get("name"); + for (int j = 0; j < enumVars.size(); j++) { + if (i == j) { + continue; + } + final Map enumVarToCheckList = enumVars.get(j); + final String enumVarNameToCheck = enumVarToCheckList.get("name"); + if (enumVarName.equals(enumVarNameToCheck)) { + enumVarToCheckList.put("name", enumVarName + "_" + j); + } + } + } + } + // handle default value for enum, e.g. available => StatusEnum.AVAILABLE if (var.defaultValue != null) { String enumName = null; @@ -3806,7 +3994,7 @@ public String getIgnoreFilePathOverride() { public void setIgnoreFilePathOverride(final String ignoreFileOverride) { this.ignoreFilePathOverride = ignoreFileOverride; } - + public void setUseOas2(boolean useOas2) { this.useOas2 = useOas2; } @@ -3870,6 +4058,21 @@ protected Schema getSchemaFromResponse(ApiResponse response) { return schema; } + protected Schema getSchemaFromParameter(Parameter parameter) { + if (parameter.getContent() == null || parameter.getContent().isEmpty()) { + return null; + } + Schema schema = null; + for (String contentType : parameter.getContent().keySet()) { + schema = parameter.getContent().get(contentType).getSchema(); + if (schema != null) { + schema.addExtension("x-content-type", contentType); + } + break; + } + return schema; + } + protected Parameter getParameterFromRef(String ref, OpenAPI openAPI) { String parameterName = ref.substring(ref.lastIndexOf('/') + 1); Map parameterMap = openAPI.getComponents().getParameters(); @@ -3893,7 +4096,7 @@ protected void setTemplateEngine() { protected String getTemplateDir() { return new StringBuilder() .append(templateEngine.getName()) - .append("/") + .append(File.separatorChar) .append(getDefaultTemplateDir()) .toString(); } @@ -3925,11 +4128,11 @@ protected void addConsumesInfo(Operation operation, CodegenOperation codegenOper String bodyName = OpenAPIUtil.getSimpleRef(body.get$ref()); body = openAPI.getComponents().getRequestBodies().get(bodyName); } - + if (body.getContent() == null || body.getContent().isEmpty()) { return; } - + Set consumes = body.getContent().keySet(); List> mediaTypeList = new ArrayList<>(); int count = 0; @@ -4075,7 +4278,7 @@ protected String getCollectionFormat(Parameter parameter) { if (parameter.getExplode() == null || parameter.getExplode()) { return "multi"; } - + // Form is the default, if no style is specified. if (parameter.getStyle() == null || Parameter.StyleEnum.FORM.equals(parameter.getStyle())) { return "csv"; @@ -4091,16 +4294,26 @@ else if (Parameter.StyleEnum.SPACEDELIMITED.equals(parameter.getStyle())) { } } - private boolean isObjectSchema (Schema schema) { - if (schema instanceof ObjectSchema ||schema instanceof ComposedSchema) { + public boolean isObjectSchema (Schema schema) { + if (schema == null) { + return false; + } + if (schema instanceof ObjectSchema || schema instanceof ComposedSchema) { return true; } - if (SchemaTypeUtil.OBJECT_TYPE.equals(schema.getType()) && !(schema instanceof MapSchema)) { + if (SchemaTypeUtil.OBJECT_TYPE.equalsIgnoreCase(schema.getType()) && !(schema instanceof MapSchema)) { return true; } if (schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty()) { return true; } + if (StringUtils.isNotBlank(schema.get$ref())) { + Schema refSchema = OpenAPIUtil.getSchemaFromRefSchema(schema, openAPI); + if (refSchema != null) { + return isObjectSchema(refSchema); + } + } + return false; } @@ -4135,12 +4348,12 @@ protected void configuresParameterForMediaType(CodegenOperation codegenOperation codegenOperation.getContents().add(content); return; } + this.addCodegenContentParameters(codegenOperation, codegenContents); for (CodegenContent content : codegenContents) { - addParemeters(content, codegenOperation.headerParams); - addParemeters(content, codegenOperation.queryParams); - addParemeters(content, codegenOperation.pathParams); - } - for (CodegenContent content : codegenContents) { + if (ensureUniqueParams) { + ensureUniqueParameters(content.getParameters()); + } + Collections.sort(content.getParameters(), (CodegenParameter one, CodegenParameter another) -> { if (one.required == another.required){ return 0; @@ -4152,12 +4365,12 @@ protected void configuresParameterForMediaType(CodegenOperation codegenOperation } } ); - addHasMore(content.getParameters()); + OperationParameters.addHasMore(content.getParameters()); } codegenOperation.getContents().addAll(codegenContents); } - private void addParemeters(CodegenContent codegenContent, List codegenParameters) { + protected void addParameters(CodegenContent codegenContent, List codegenParameters) { if (codegenParameters == null || codegenParameters.isEmpty()) { return; } @@ -4166,7 +4379,80 @@ private void addParemeters(CodegenContent codegenContent, List } } + protected void addCodegenContentParameters(CodegenOperation codegenOperation, List codegenContents) { + for (CodegenContent content : codegenContents) { + if (content.getIsForm()) { + addParameters(content, codegenOperation.formParams); + } else { + addParameters(content, codegenOperation.bodyParams); + } + addParameters(content, codegenOperation.headerParams); + addParameters(content, codegenOperation.queryParams); + addParameters(content, codegenOperation.pathParams); + addParameters(content, codegenOperation.cookieParams); + } + } + + protected void ensureUniqueParameters(List codegenParameters) { + if (codegenParameters == null || codegenParameters.isEmpty()) { + return; + } + for (CodegenParameter codegenParameter : codegenParameters) { + long count = codegenParameters.stream() + .filter(codegenParam -> codegenParam.paramName.equals(codegenParameter.paramName)) + .count(); + if (count > 1l) { + codegenParameter.paramName = generateNextName(codegenParameter.paramName); + } + } + } + protected void setParameterNullable(CodegenParameter parameter, CodegenProperty property) { parameter.nullable = property.nullable; } + + protected boolean isFileTypeSchema(Schema schema) { + final Schema fileTypeSchema; + if (StringUtils.isNotBlank(schema.get$ref())) { + fileTypeSchema = OpenAPIUtil.getSchemaFromRefSchema(schema, openAPI); + } else { + fileTypeSchema = schema; + } + if (fileTypeSchema.getProperties() != null) { + final Collection propertySchemas = fileTypeSchema.getProperties().values(); + return propertySchemas.stream().anyMatch(propertySchema -> "string".equalsIgnoreCase(propertySchema.getType()) + && "binary".equalsIgnoreCase(propertySchema.getFormat())); + } + return false; + } + + @Override + public boolean needsUnflattenedSpec() { + return false; + } + + @Override + public void setUnflattenedOpenAPI(OpenAPI unflattenedOpenAPI) { + this.unflattenedOpenAPI = unflattenedOpenAPI; + } + + public boolean getIgnoreImportMapping() { + return ignoreImportMapping; + } + + public void setIgnoreImportMapping(boolean ignoreImportMapping) { + this.ignoreImportMapping = ignoreImportMapping; + } + + public boolean defaultIgnoreImportMappingOption() { + return false; + } + + public ISchemaHandler getSchemaHandler() { + return new SchemaHandler(this); + } + + public OpenAPI getOpenAPI() { + return this.openAPI; + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/OperationParameters.java b/src/main/java/io/swagger/codegen/v3/generators/OperationParameters.java new file mode 100644 index 0000000000..7cf06a29f1 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/OperationParameters.java @@ -0,0 +1,206 @@ +package io.swagger.codegen.v3.generators; + +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenContent; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenParameter; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.CookieParameter; +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.PathParameter; +import io.swagger.v3.oas.models.parameters.QueryParameter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class OperationParameters { + + private CodegenParameter bodyParam = null; + private List allParams = new ArrayList<>(); + private List bodyParams = new ArrayList<>(); + private List pathParams = new ArrayList<>(); + private List queryParams = new ArrayList<>(); + private List headerParams = new ArrayList<>(); + private List cookieParams = new ArrayList<>(); + private List formParams = new ArrayList<>(); + private List requiredParams = new ArrayList<>(); + private List codegenContents = new ArrayList<>(); + + public void setBodyParam(CodegenParameter bodyParam) { + this.bodyParam = bodyParam; + } + + public CodegenParameter getBodyParam() { + return bodyParam; + } + + public List getAllParams() { + return allParams; + } + + public List getBodyParams() { + return bodyParams; + } + + public List getPathParams() { + return pathParams; + } + + public List getQueryParams() { + return queryParams; + } + + public List getHeaderParams() { + return headerParams; + } + + public List getCookieParams() { + return cookieParams; + } + + public List getFormParams() { + return formParams; + } + + public List getRequiredParams() { + return requiredParams; + } + + public List getCodegenContents() { + return codegenContents; + } + + public void addAllParams(CodegenParameter codegenParameter) { + allParams.add(codegenParameter); + } + + public void addBodyParams(CodegenParameter codegenParameter) { + bodyParams.add(codegenParameter); + } + + public void addPathParams(CodegenParameter codegenParameter) { + pathParams.add(codegenParameter); + } + + public void addQueryParams(CodegenParameter codegenParameter) { + queryParams.add(codegenParameter); + } + + public void addHeaderParams(CodegenParameter codegenParameter) { + headerParams.add(codegenParameter); + } + + public void addCookieParams(CodegenParameter codegenParameter) { + cookieParams.add(codegenParameter); + } + + public void addFormParam(CodegenParameter codegenParameter) { + formParams.add(codegenParameter); + } + + public void addRequiredParam(CodegenParameter codegenParameter) { + requiredParams.add(codegenParameter); + } + + public void addCodegenContents(CodegenContent codegenContent) { + codegenContents.add(codegenContent); + } + + public void addParameters(Parameter parameter, CodegenParameter codegenParameter) { + allParams.add(codegenParameter); + + if (parameter instanceof QueryParameter || "query".equalsIgnoreCase(parameter.getIn())) { + queryParams.add(codegenParameter.copy()); + } else if (parameter instanceof PathParameter || "path".equalsIgnoreCase(parameter.getIn())) { + pathParams.add(codegenParameter.copy()); + } else if (parameter instanceof HeaderParameter || "header".equalsIgnoreCase(parameter.getIn())) { + headerParams.add(codegenParameter.copy()); + } else if (parameter instanceof CookieParameter || "cookie".equalsIgnoreCase(parameter.getIn())) { + cookieParams.add(codegenParameter.copy()); + } + if (codegenParameter.required) { + requiredParams.add(codegenParameter.copy()); + } + } + + public void addHasMore(CodegenOperation codegenOperation) { + codegenOperation.allParams = addHasMore(allParams); + codegenOperation.bodyParams = addHasMore(bodyParams); + codegenOperation.pathParams = addHasMore(pathParams); + codegenOperation.queryParams = addHasMore(queryParams); + codegenOperation.headerParams = addHasMore(headerParams); + codegenOperation.cookieParams = addHasMore(cookieParams); + codegenOperation.formParams = addHasMore(formParams); + codegenOperation.requiredParams = addHasMore(requiredParams); + } + + public void sortRequiredAllParams() { + Collections.sort(allParams, (one, another) -> { + if (one.required == another.required) { + return 0; + } else if (one.required) { + return -1; + } else { + return 1; + } + }); + } + + public void parseNestedObjects(String name, Schema schema, Set imports, DefaultCodegenConfig codegenConfig, OpenAPI openAPI) { + schema = OpenAPIUtil.getRefSchemaIfExists(schema, openAPI); + if (schema == null || !isObjectWithProperties(schema)) { + return; + } + final Map properties = schema.getProperties(); + for (String key : properties.keySet()) { + Schema property = properties.get(key); + property = OpenAPIUtil.getRefSchemaIfExists(property, openAPI); + boolean required; + if (schema.getRequired() == null || schema.getRequired().isEmpty()) { + required = false; + } else { + required = schema.getRequired().stream().anyMatch(propertyName -> key.equalsIgnoreCase(propertyName.toString())); + } + final String parameterName; + if (property instanceof ArraySchema) { + parameterName = String.format("%s[%s][]", name, key); + } else { + parameterName = String.format("%s[%s]", name, key); + } + if (isObjectWithProperties(property)) { + parseNestedObjects(parameterName, property, imports, codegenConfig, openAPI); + continue; + } + final Parameter queryParameter = new QueryParameter() + .name(parameterName) + .required(required) + .schema(property); + final CodegenParameter codegenParameter = codegenConfig.fromParameter(queryParameter, imports); + addParameters(queryParameter, codegenParameter); + } + } + + public static List addHasMore(List codegenParameters) { + if (codegenParameters == null || codegenParameters.isEmpty()) { + return codegenParameters; + } + for (int i = 0; i < codegenParameters.size(); i++) { + codegenParameters.get(i).secondaryParam = i > 0; + codegenParameters.get(i).getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, i < codegenParameters.size() - 1); + } + return codegenParameters; + } + + private boolean isObjectWithProperties(Schema schema) { + return ("object".equalsIgnoreCase(schema.getType()) || schema.getType() == null) + && schema.getProperties() != null + && !schema.getProperties().isEmpty(); + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java b/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java index 41a37ea6ad..09f0e13cd9 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java +++ b/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java @@ -1,137 +1,277 @@ package io.swagger.codegen.v3.generators; -import io.swagger.codegen.v3.*; -import io.swagger.codegen.v3.generators.util.OpenAPIUtil; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenModelFactory; +import io.swagger.codegen.v3.CodegenModelType; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.ISchemaHandler; +import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; -public class SchemaHandler { +public class SchemaHandler implements ISchemaHandler { - private DefaultCodegenConfig codegenConfig; + public static final String ALL_OF_PREFFIX = "AllOf"; + public static final String ONE_OF_PREFFIX = "OneOf"; + public static final String ANY_OF_PREFFIX = "AnyOf"; + public static final String ARRAY_ITEMS_SUFFIX = "Items"; + + protected DefaultCodegenConfig codegenConfig; + private List composedModels = new ArrayList<>(); public SchemaHandler(DefaultCodegenConfig codegenConfig) { this.codegenConfig = codegenConfig; } + @Override + public void processComposedSchemas(CodegenModel codegenModel, Schema schema, Map allModels) { + if (schema instanceof ComposedSchema) { + this.addComposedModel(this.processComposedSchema(codegenModel, (ComposedSchema) schema, allModels)); + } + if (schema instanceof ArraySchema) { + this.addComposedModel(this.processArrayItemSchema(codegenModel, (ArraySchema) schema, allModels)); + return; + } + final Map properties = schema.getProperties(); + if (properties == null || properties.isEmpty()) { + return; + } + for (String name : properties.keySet()) { + final Schema property = properties.get(name); + final Optional optionalCodegenProperty = codegenModel.getVars() + .stream() + .filter(codegenProperty -> codegenProperty.baseName.equals(name)) + .findFirst(); + if (!optionalCodegenProperty.isPresent()) { + continue; + } + final CodegenProperty codegenProperty = optionalCodegenProperty.get(); + final String codegenName = codegenModel.getName() + codegenConfig.toModelName(codegenProperty.getName()); + if (property instanceof ComposedSchema) { + this.addComposedModel(this.processComposedSchema(codegenName, codegenProperty, (ComposedSchema) property, allModels)); + continue; + } + if (property instanceof ArraySchema) { + this.addComposedModel(this.processArrayItemSchema(codegenName, codegenProperty, (ArraySchema) property, allModels)); + continue; + } + } + } + + @Override + public List getModels() { + return composedModels; + } - /** - * creates a codegen model object based on a composed schema property. - * @param composedProperty - * @param codegenProperty - */ - public void createCodegenModel(ComposedSchema composedProperty, CodegenProperty codegenProperty) { - final List oneOf = composedProperty.getOneOf(); - final List anyOf = composedProperty.getAnyOf(); + protected CodegenModel processComposedSchema(CodegenModel codegenModel, ComposedSchema composedSchema, Map allModels) { - if (oneOf != null && !oneOf.isEmpty()) { - final CodegenModel oneOfModel = createFromOneOfSchemas(oneOf); - codegenProperty.vendorExtensions.put("oneOf-model", oneOfModel); - } - if (anyOf != null && !anyOf.isEmpty()) { - final CodegenModel anyOfModel = createFromOneOfSchemas(anyOf); - codegenProperty.vendorExtensions.put("anyOf-model", anyOfModel); + final boolean schemaWithNoProperties = codegenModel.vars == null || codegenModel.vars.isEmpty(); + if (schemaWithNoProperties && (composedSchema.getAllOf() == null || composedSchema.getAllOf().isEmpty())) { + if (composedSchema.getOneOf() != null && !composedSchema.getOneOf().isEmpty()) { + this.addInterfaces(composedSchema.getOneOf(), codegenModel, allModels); + } else if (composedSchema.getAnyOf() != null && !composedSchema.getAnyOf().isEmpty()) { + this.addInterfaces(composedSchema.getAnyOf(), codegenModel, allModels); + } + codegenModel.setIsComposedModel(true); + return codegenModel; } + List schemas = composedSchema.getOneOf(); + CodegenModel composedModel = this.createComposedModel(ONE_OF_PREFFIX + codegenModel.getName(), schemas); + if (composedModel == null) { + schemas = composedSchema.getAnyOf(); + composedModel = this.createComposedModel(ANY_OF_PREFFIX + codegenModel.getName(), schemas); + if (composedModel == null) { + return null; + } + } + this.addInterfaceModel(codegenModel, composedModel); + this.addInterfaces(schemas, composedModel, allModels); + return composedModel; } - public void configureOneOfModel(CodegenModel codegenModel, List oneOf) { - String oneOfModelName = "OneOf" + codegenModel.name; - final CodegenModel oneOfModel = CodegenModelFactory.newInstance(CodegenModelType.MODEL); - oneOfModel.name = oneOfModelName; - oneOfModel.classname = codegenConfig.toModelName(oneOfModelName); - oneOfModel.classVarName = codegenConfig.toVarName(oneOfModelName); - oneOfModel.classFilename = codegenConfig.toModelFilename(oneOfModelName); - oneOfModel.vendorExtensions.put("x-is-composed-model", Boolean.TRUE); + protected CodegenModel processComposedSchema(String name, ComposedSchema composedSchema, Map allModels) { + List schemas = composedSchema.getOneOf(); + CodegenModel composedModel = this.createComposedModel(ONE_OF_PREFFIX + name, schemas); + if (composedModel == null) { + schemas = composedSchema.getAnyOf(); + composedModel = this.createComposedModel(ANY_OF_PREFFIX + name, schemas); + if (composedModel == null) { + return null; + } + } + this.addInterfaces(schemas, composedModel, allModels); + return composedModel; + } - final List modelNames = new ArrayList<>(); + protected CodegenModel processComposedSchema(String codegenModelName, CodegenProperty codegenProperty, ComposedSchema composedSchema, Map allModels) { + List schemas = composedSchema.getAllOf(); + if (schemas != null && !schemas.isEmpty()) { + final CodegenModel composedModel = codegenConfig.fromModel(ALL_OF_PREFFIX + codegenModelName, composedSchema); + this.updatePropertyDataType(codegenProperty, composedModel); + return composedModel; + } + schemas = composedSchema.getOneOf(); + CodegenModel composedModel = this.createComposedModel(ONE_OF_PREFFIX + codegenModelName, schemas); + if (composedModel == null) { + schemas = composedSchema.getAnyOf(); + composedModel = this.createComposedModel(ANY_OF_PREFFIX + codegenModelName, schemas); + if (composedModel == null) { + return null; + } + } + this.addInterfaces(schemas, composedModel, allModels); + this.updatePropertyDataType(codegenProperty, composedModel); + return composedModel; + } - for (Schema interfaceSchema : oneOf) { - String schemaName = OpenAPIUtil.getSimpleRef(interfaceSchema.get$ref()); - modelNames.add(codegenConfig.toModelName(schemaName)); + protected CodegenModel processArrayItemSchema(CodegenModel codegenModel, ArraySchema arraySchema, Map allModels) { + final Schema itemsSchema = arraySchema.getItems(); + if (itemsSchema instanceof ComposedSchema) { + final CodegenModel composedModel = this.processComposedSchema(codegenModel.name + ARRAY_ITEMS_SUFFIX, (ComposedSchema) itemsSchema, allModels); + if (composedModel == null) { + return null; + } + this.updateArrayModel(codegenModel, composedModel.name, arraySchema); + return composedModel; } - oneOfModel.vendorExtensions.put("x-model-names", modelNames); - codegenModel.vendorExtensions.put("oneOf-model", oneOfModel); - if (codegenModel.interfaceModels == null) { - codegenModel.interfaceModels = new ArrayList<>(); + return null; + } + + protected CodegenModel processArrayItemSchema(String codegenModelName, CodegenProperty codegenProperty, ArraySchema arraySchema, Map allModels) { + final Schema itemsSchema = arraySchema.getItems(); + if (itemsSchema instanceof ComposedSchema) { + final CodegenModel composedModel = this.processComposedSchema(codegenModelName + ARRAY_ITEMS_SUFFIX, codegenProperty.items, (ComposedSchema) itemsSchema, allModels); + if (composedModel == null) { + return null; + } + this.updatePropertyDataType(codegenProperty, composedModel.name, arraySchema); + this.updatePropertyDataType(codegenProperty.items, composedModel); + return composedModel; } - codegenModel.interfaceModels.add(oneOfModel); + return null; } - public void configureAnyOfModel(CodegenModel codegenModel, List oneOf) { - String oneOfModelName = "AnyOf" + codegenModel.name; - final CodegenModel oneOfModel = CodegenModelFactory.newInstance(CodegenModelType.MODEL); - oneOfModel.name = oneOfModelName; - oneOfModel.classname = codegenConfig.toModelName(oneOfModelName); - oneOfModel.classVarName = codegenConfig.toVarName(oneOfModelName); - oneOfModel.classFilename = codegenConfig.toModelFilename(oneOfModelName); - oneOfModel.vendorExtensions.put("x-is-composed-model", Boolean.TRUE); + protected CodegenModel createComposedModel(String name, List schemas) { + if (schemas == null || schemas.isEmpty()) { + return null; + } + final CodegenModel composedModel = CodegenModelFactory.newInstance(CodegenModelType.MODEL); + composedModel.setIsComposedModel(true); + composedModel.setInterfaces(new ArrayList<>()); + this.configureModel(composedModel, name); - final List modelNames = new ArrayList<>(); + return composedModel; + } - for (Schema interfaceSchema : oneOf) { - String schemaName = OpenAPIUtil.getSimpleRef(interfaceSchema.get$ref()); - modelNames.add(codegenConfig.toModelName(schemaName)); + protected void addInterfaceModel(CodegenModel codegenModel, CodegenModel interfaceModel) { + if (codegenModel == null) { + return; } - oneOfModel.vendorExtensions.put("x-model-names", modelNames); - codegenModel.vendorExtensions.put("anyOf-model", oneOfModel); - if (codegenModel.interfaceModels == null) { - codegenModel.interfaceModels = new ArrayList<>(); + if (codegenModel.getInterfaceModels() == null) { + codegenModel.setInterfaceModels(new ArrayList<>()); } - codegenModel.interfaceModels.add(oneOfModel); + codegenModel.getInterfaceModels().add(interfaceModel); } - public void configureOneOfModelFromProperty(CodegenProperty codegenProperty, CodegenModel codegenModel) { - String name = "OneOf" + codegenConfig.toModelName(codegenModel.name); - name += codegenConfig.toModelName(codegenProperty.name); - CodegenModel oneOfModel = (CodegenModel) codegenProperty.vendorExtensions.get("oneOf-model"); - oneOfModel.name = name; - oneOfModel.classname = codegenConfig.toModelName(name); - oneOfModel.classVarName = codegenConfig.toVarName(name); - oneOfModel.classFilename = codegenConfig.toModelFilename(name); - oneOfModel.vendorExtensions.put("x-is-composed-model", Boolean.TRUE); - codegenProperty.vendorExtensions.remove("oneOf-model"); + protected void addInterfaces(List schemas, CodegenModel codegenModel, Map allModels) { + for (Schema interfaceSchema : schemas) { + final String ref = interfaceSchema.get$ref(); + if (StringUtils.isBlank(ref)) { + continue; + } + final String schemaName = ref.substring(ref.lastIndexOf("/") + 1); + + final CodegenModel model = allModels.get(codegenConfig.toModelName(schemaName)); + this.addInterfaceModel(model, codegenModel); - codegenProperty.datatype = name; - codegenProperty.datatypeWithEnum = name; - codegenProperty.baseType = name; + boolean subTypeAdded = false; + if (codegenModel.getSubTypes() != null) { + subTypeAdded = codegenModel.getSubTypes().stream().anyMatch(existingSubType -> existingSubType.classname.equalsIgnoreCase(model.classname)); + } + if (!subTypeAdded) { + codegenModel.addSubType(model); + } - codegenModel.vendorExtensions.put("oneOf-model", oneOfModel); + if (codegenModel.getVendorExtensions() == null || codegenModel.getVendorExtensions().containsKey("x-discriminator-type")) { + continue; + } + if (codegenModel.getDiscriminator() != null && StringUtils.isNotBlank(codegenModel.getDiscriminator().getPropertyName())) { + Optional optionalProperty = model.vars.stream() + .filter(codegenProperty -> codegenProperty.baseName.equals(codegenModel.getDiscriminator().getPropertyName())).findFirst(); + + optionalProperty.ifPresent(codegenProperty -> { + codegenModel.getVendorExtensions().put("x-discriminator-type", codegenProperty.datatypeWithEnum); + codegenModel.getVendorExtensions().put("x-discriminator-type-getter", codegenConfig.toGetter(codegenModel.getDiscriminator().getPropertyName())); + }); + } + } } - public void configureAnyOfModelFromProperty(CodegenProperty codegenProperty, CodegenModel codegenModel) { - String name = "AnyOf" + codegenConfig.toModelName(codegenModel.name); - name += codegenConfig.toModelName(codegenProperty.name); - CodegenModel anyOfModel = (CodegenModel) codegenProperty.vendorExtensions.get("anyOf-model"); - anyOfModel.name = name; - anyOfModel.classname = codegenConfig.toModelName(name); - anyOfModel.classVarName = codegenConfig.toVarName(name); - anyOfModel.classFilename = codegenConfig.toModelFilename(name); - anyOfModel.vendorExtensions.put("x-is-composed-model", Boolean.TRUE); - codegenProperty.vendorExtensions.remove("anyOf-model"); + protected void configureModel(CodegenModel codegenModel, String name) { + codegenModel.name = name; + codegenModel.classname = codegenConfig.toModelName(name); + codegenModel.classVarName = codegenConfig.toVarName(name); + codegenModel.classFilename = codegenConfig.toModelFilename(name); + } - codegenProperty.datatype = name; - codegenProperty.datatypeWithEnum = name; - codegenProperty.baseType = name; + protected boolean hasNonObjectSchema(List schemas) { + for (Schema schema : schemas) { + if (!codegenConfig.isObjectSchema(schema)) { + return true; + } + } + return false; + } - codegenModel.vendorExtensions.put("anyOf-model", anyOfModel); + protected void addComposedModel(CodegenModel composedModel) { + if (composedModel == null) { + return; + } + this.composedModels.add(composedModel); } - public void configureAnyOfModelFromProperty() { + protected void updatePropertyDataType(CodegenProperty codegenProperty, String schemaName, ArraySchema arraySchema) { + final Schema items = arraySchema.getItems(); + final Schema refSchema = new Schema(); + refSchema.set$ref("#/components/schemas/" + schemaName); + arraySchema.setItems(refSchema); + codegenProperty.setDatatype(this.codegenConfig.getTypeDeclaration(arraySchema)); + codegenProperty.setDatatypeWithEnum(codegenProperty.getDatatype()); + codegenProperty.vendorExtensions.put("x-is-composed", true); + codegenProperty.defaultValue = this.codegenConfig.toDefaultValue(arraySchema); + codegenProperty.defaultValueWithParam = this.codegenConfig.toDefaultValueWithParam(codegenProperty.baseName, arraySchema); + + arraySchema.setItems(items); } - private CodegenModel createFromOneOfSchemas(List schemas) { - final CodegenModel codegenModel = CodegenModelFactory.newInstance(CodegenModelType.MODEL); - final List modelNames = new ArrayList<>(); + protected void updateArrayModel(CodegenModel codegenModel, String schemaName, ArraySchema arraySchema) { + final Schema items = arraySchema.getItems(); + final Schema refSchema = new Schema(); + refSchema.set$ref("#/components/schemas/" + schemaName); + arraySchema.setItems(refSchema); - for (Schema interfaceSchema : schemas) { - String schemaName = OpenAPIUtil.getSimpleRef(interfaceSchema.get$ref()); - modelNames.add(codegenConfig.toModelName(schemaName)); - } - codegenModel.vendorExtensions.put("x-model-names", modelNames); - return codegenModel; + this.codegenConfig.addParentContainer(codegenModel, codegenModel.name, arraySchema); + codegenModel.defaultValue = this.codegenConfig.toDefaultValue(arraySchema); + codegenModel.arrayModelType = this.codegenConfig.fromProperty(codegenModel.name, arraySchema).complexType; + boolean isInterface = codegenModel.arrayModelType.startsWith(ALL_OF_PREFFIX) || codegenModel.arrayModelType.startsWith(ONE_OF_PREFFIX) || codegenModel.arrayModelType.startsWith(ANY_OF_PREFFIX); + codegenModel.getVendorExtensions().put("x-array-model-type-is-interface", isInterface); + + arraySchema.setItems(items); + } + + private void updatePropertyDataType(CodegenProperty codegenProperty, CodegenModel composedModel) { + codegenProperty.datatype = composedModel.getClassname(); + codegenProperty.datatypeWithEnum = composedModel.getClassname(); + codegenProperty.baseType = composedModel.getClassname(); + codegenProperty.complexType = composedModel.getClassname(); + codegenProperty.vendorExtensions.put("x-is-composed", true); } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/dart/DartClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/dart/DartClientCodegen.java new file mode 100644 index 0000000000..a51f24c9ea --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/dart/DartClientCodegen.java @@ -0,0 +1,514 @@ +package io.swagger.codegen.v3.generators.dart; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +public class DartClientCodegen extends DefaultCodegenConfig { + + protected static final Logger LOGGER = LoggerFactory.getLogger(DartClientCodegen.class); + + public static final String BROWSER_CLIENT = "browserClient"; + public static final String PUB_NAME = "pubName"; + public static final String PUB_VERSION = "pubVersion"; + public static final String PUB_DESCRIPTION = "pubDescription"; + public static final String USE_ENUM_EXTENSION = "useEnumExtension"; + protected boolean browserClient = true; + protected String pubName = "swagger"; + protected String pubVersion = "1.0.0"; + protected String pubDescription = "Swagger API client"; + protected boolean useEnumExtension = false; + protected String sourceFolder = ""; + protected String apiDocPath = "docs/"; + protected String modelDocPath = "docs/"; + + public DartClientCodegen() { + super(); + + // clear import mapping (from default generator) as dart does not use it + // at the moment + importMapping.clear(); + + outputFolder = "generated-code/dart"; + modelTemplateFiles.put("model.mustache", ".dart"); + apiTemplateFiles.put("api.mustache", ".dart"); + apiTestTemplateFiles.put("api_test.mustache", ".dart"); + embeddedTemplateDir = templateDir = "dart"; + apiPackage = "lib.api"; + modelPackage = "lib.model"; + testPackage = "tests"; + modelDocTemplateFiles.put("object_doc.mustache", ".md"); + apiDocTemplateFiles.put("api_doc.mustache", ".md"); + + // default HIDE_GENERATION_TIMESTAMP to true + hideGenerationTimestamp = Boolean.TRUE; + + setReservedWordsLowerCase( + Arrays.asList( + "abstract", "as", "assert", "async", "async*", "await", + "break", "case", "catch", "class", "const", "continue", + "default", "deferred", "do", "dynamic", "else", "enum", + "export", "external", "extends", "factory", "false", "final", + "finally", "for", "get", "if", "implements", "import", "in", + "is", "library", "new", "null", "operator", "part", "rethrow", + "return", "set", "static", "super", "switch", "sync*", "this", + "throw", "true", "try", "typedef", "var", "void", "while", + "int", "double", "with", "yield", "yield*" ) + ); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "String", + "bool", + "int", + "num", + "double") + ); + instantiationTypes.put("array", "List"); + instantiationTypes.put("map", "Map"); + + typeMapping = new HashMap<>(); + typeMapping.put("Array", "List"); + typeMapping.put("array", "List"); + typeMapping.put("List", "List"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "String"); + typeMapping.put("char", "String"); + typeMapping.put("int", "int"); + typeMapping.put("long", "int"); + typeMapping.put("short", "int"); + typeMapping.put("number", "num"); + typeMapping.put("float", "double"); + typeMapping.put("double", "double"); + typeMapping.put("BigDecimal", "double"); + typeMapping.put("object", "Object"); + typeMapping.put("integer", "int"); + typeMapping.put("Date", "DateTime"); + typeMapping.put("date", "DateTime"); + typeMapping.put("File", "MultipartFile"); + typeMapping.put("UUID", "String"); + //TODO binary should be mapped to byte array + // mapped to String as a workaround + typeMapping.put("binary", "String"); + typeMapping.put("ByteArray", "String"); + + cliOptions.add(new CliOption(BROWSER_CLIENT, "Is the client browser based")); + cliOptions.add(new CliOption(PUB_NAME, "Name in generated pubspec")); + cliOptions.add(new CliOption(PUB_VERSION, "Version in generated pubspec")); + cliOptions.add(new CliOption(PUB_DESCRIPTION, "Description in generated pubspec")); + cliOptions.add(new CliOption(USE_ENUM_EXTENSION, "Allow the 'x-enum-values' extension for enums")); + cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, "source folder for generated code")); + } + + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public String getName() { + return "dart"; + } + + @Override + public String getHelp() { + return "Generates a Dart client library."; + } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(BROWSER_CLIENT)) { + this.setBrowserClient(convertPropertyToBooleanAndWriteBack(BROWSER_CLIENT)); + } else { + //not set, use to be passed to template + additionalProperties.put(BROWSER_CLIENT, browserClient); + } + + if (additionalProperties.containsKey(PUB_NAME)) { + this.setPubName((String) additionalProperties.get(PUB_NAME)); + } else { + //not set, use to be passed to template + additionalProperties.put(PUB_NAME, pubName); + } + + if (additionalProperties.containsKey(PUB_VERSION)) { + this.setPubVersion((String) additionalProperties.get(PUB_VERSION)); + } else { + //not set, use to be passed to template + additionalProperties.put(PUB_VERSION, pubVersion); + } + + if (additionalProperties.containsKey(PUB_DESCRIPTION)) { + this.setPubDescription((String) additionalProperties.get(PUB_DESCRIPTION)); + } else { + //not set, use to be passed to template + additionalProperties.put(PUB_DESCRIPTION, pubDescription); + } + + if (additionalProperties.containsKey(USE_ENUM_EXTENSION)) { + this.setUseEnumExtension(convertPropertyToBooleanAndWriteBack(USE_ENUM_EXTENSION)); + } else { + // Not set, use to be passed to template. + additionalProperties.put(USE_ENUM_EXTENSION, useEnumExtension); + } + + if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) { + this.setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER)); + } + + // make api and model doc path available in mustache template + additionalProperties.put("apiDocPath", apiDocPath); + additionalProperties.put("modelDocPath", modelDocPath); + + final String libFolder = sourceFolder + File.separator + "lib"; + supportingFiles.add(new SupportingFile("pubspec.mustache", "", "pubspec.yaml")); + supportingFiles.add(new SupportingFile("analysis_options.mustache", "", ".analysis_options")); + supportingFiles.add(new SupportingFile("api_client.mustache", libFolder, "api_client.dart")); + supportingFiles.add(new SupportingFile("api_exception.mustache", libFolder, "api_exception.dart")); + supportingFiles.add(new SupportingFile("api_helper.mustache", libFolder, "api_helper.dart")); + supportingFiles.add(new SupportingFile("apilib.mustache", libFolder, "api.dart")); + + final String authFolder = sourceFolder + File.separator + "lib" + File.separator + "auth"; + supportingFiles.add(new SupportingFile("auth/authentication.mustache", authFolder, "authentication.dart")); + supportingFiles.add(new SupportingFile("auth/http_basic_auth.mustache", authFolder, "http_basic_auth.dart")); + supportingFiles.add(new SupportingFile("auth/api_key_auth.mustache", authFolder, "api_key_auth.dart")); + supportingFiles.add(new SupportingFile("auth/oauth.mustache", authFolder, "oauth.dart")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + } + + @Override + public String escapeReservedWord(String name) { + return name + "_"; + } + + @Override + public String apiFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + apiPackage().replace('.', File.separatorChar); + } + + @Override + public String modelFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + modelPackage().replace('.', File.separatorChar); + } + + @Override + public String apiTestFileFolder() { + return outputFolder + "/" + sourceFolder + "/" + testPackage().replace('/', File.separatorChar); + } + + @Override + public String apiDocFileFolder() { + return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar); + } + + @Override + public String modelDocFileFolder() { + return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar); + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + // camelize (lower first character) the variable name + // pet_id => petId + name = camelize(name, true); + + if (name.matches("^\\d.*")) { + name = "n" + name; + } + + if (isReservedWord(name)) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String name) { + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + LOGGER.warn(name + " (reserved word) cannot be used as model filename. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. return => ModelReturn (after camelize) + } + if (Character.isDigit(name.charAt(0))) { + LOGGER.warn(name + " start with number. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. return => ModelReturn (after camelize) + } + + // camelize the model name + // phone_number => PhoneNumber + return camelize(name); + } + + @Override + public String toModelFilename(String name) { + return underscore(toModelName(name)); + } + + @Override + public String toApiFilename(String name) { + return underscore(toApiName(name)); + } + + @Override + public String toApiTestFilename(String name) { + return underscore(toApiName(name)) + "_test"; + } + + @Override + public String toDefaultValue(Schema schema) { + if (schema instanceof MapSchema) { + return "{}"; + } else if (schema instanceof ArraySchema) { + return "[]"; + } else if (schema instanceof StringSchema) { + if (schema.getDefault() != null) { + String _default = schema.getDefault().toString(); + if (schema.getEnum() == null) { + return String.format("\"%s\"", escapeText(_default)); + } else { + // convert to enum var name later in postProcessModels + return _default; + } + } + } + return super.toDefaultValue(schema); + } + + @Override + public String getTypeDeclaration(Schema schema) { + if (schema instanceof ArraySchema) { + final ArraySchema ap = (ArraySchema) schema; + final Schema inner = ap.getItems(); + return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">"; + } else if (schema instanceof MapSchema) { + final MapSchema mp = (MapSchema) schema; + final Object innerObject = mp.getAdditionalProperties(); + if (innerObject instanceof Schema) { + final Schema inner = (Schema) innerObject; + return getSchemaType(schema) + ""; + } + } + return super.getTypeDeclaration(schema); + } + + @Override + public String getSchemaType(Schema schema) { + String swaggerType = super.getSchemaType(schema); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (languageSpecificPrimitives.contains(type)) { + return type; + } + } else { + type = swaggerType; + } + if (type == null) { + type = "Object"; + } + return toModelName(type); + } + + @Override + public Map postProcessModels(Map objs) { + return postProcessModelsEnum(objs); + } + + @Override + public Map postProcessModelsEnum(Map objs) { + List models = (List) objs.get("models"); + for (Object _mo : models) { + Map modelMap = (Map) _mo; + CodegenModel codegenModel = (CodegenModel) modelMap.get("model"); + boolean succes = buildEnumFromVendorExtension(codegenModel) || buildEnumFromValues(codegenModel); + for (CodegenProperty var : codegenModel.vars) { + updateCodegenPropertyEnum(var); + } + } + return objs; + } + + /** + * Builds the set of enum members from their declared value. + * + * @return {@code true} if the enum was built + */ + private boolean buildEnumFromValues(CodegenModel codegenModel) { + if (!getBooleanValue(codegenModel, IS_ENUM_EXT_NAME) || codegenModel.allowableValues == null) { + return false; + } + final Map allowableValues = codegenModel.allowableValues; + final List values = (List) allowableValues.get("values"); + final List> enumVars = new ArrayList<>(); + final String commonPrefix = findCommonPrefixOfVars(values); + int truncateIdx = commonPrefix.length(); + for (Object value : values) { + Map enumVar = new HashMap(); + String enumName; + if (truncateIdx == 0) { + enumName = value.toString(); + } else { + enumName = value.toString().substring(truncateIdx); + if ("".equals(enumName)) { + enumName = value.toString(); + } + } + enumVar.put("name", toEnumVarName(enumName, codegenModel.dataType)); + enumVar.put("value", toEnumValue(value.toString(), codegenModel.dataType)); + enumVars.add(enumVar); + } + codegenModel.allowableValues.put("enumVars", enumVars); + return true; + } + + /** + * Builds the set of enum members from a vendor extension. + * + * @return {@code true} if the enum was built + */ + private boolean buildEnumFromVendorExtension(CodegenModel codegenModel) { + if (!getBooleanValue(codegenModel, IS_ENUM_EXT_NAME) || codegenModel.allowableValues == null || + !useEnumExtension || + !codegenModel.vendorExtensions.containsKey("x-enum-values")) { + return false; + } + Object extension = codegenModel.vendorExtensions.get("x-enum-values"); + List> values = + (List>) extension; + List> enumVars = + new ArrayList>(); + for (Map value : values) { + Map enumVar = new HashMap(); + String name = camelize((String) value.get("identifier"), true); + if (isReservedWord(name)) { + name = escapeReservedWord(name); + } + enumVar.put("name", name); + enumVar.put("value", toEnumValue( + value.get("numericValue").toString(), codegenModel.dataType)); + if (value.containsKey("description")) { + enumVar.put("description", value.get("description").toString()); + } + enumVars.add(enumVar); + } + codegenModel.allowableValues.put("enumVars", enumVars); + return true; + } + + @Override + public String toEnumVarName(String value, String datatype) { + if (value.length() == 0) { + return "empty"; + } + String var = value.replaceAll("\\W+", "_"); + if ("number".equalsIgnoreCase(datatype) || + "int".equalsIgnoreCase(datatype)) { + var = "Number" + var; + } + return escapeReservedWord(camelize(var, true)); + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("number".equalsIgnoreCase(datatype) || + "int".equalsIgnoreCase(datatype)) { + return value; + } else { + return "\"" + escapeText(value) + "\""; + } + } + + @Override + public String toOperationId(String operationId) { + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + String newOperationId = camelize("call_" + operationId, true); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId); + return newOperationId; + } + + return camelize(operationId, true); + } + + public void setBrowserClient(boolean browserClient) { + this.browserClient = browserClient; + } + + public void setPubName(String pubName) { + this.pubName = pubName; + } + + public void setPubVersion(String pubVersion) { + this.pubVersion = pubVersion; + } + + public void setPubDescription(String pubDescription) { + this.pubDescription = pubDescription; + } + + public void setUseEnumExtension(boolean useEnumExtension) { + this.useEnumExtension = useEnumExtension; + } + + public void setSourceFolder(String sourceFolder) { + this.sourceFolder = sourceFolder; + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } + + + @Override + public String getDefaultTemplateDir() { + return "dart"; + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/dotnet/AbstractCSharpCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/dotnet/AbstractCSharpCodegen.java index 9b294575dc..8b846d9a36 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/dotnet/AbstractCSharpCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/dotnet/AbstractCSharpCodegen.java @@ -4,6 +4,7 @@ import com.github.jknack.handlebars.Lambda; import com.google.common.collect.ImmutableMap; import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenContent; import io.swagger.codegen.v3.CodegenModel; import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.CodegenProperty; @@ -14,7 +15,9 @@ import io.swagger.codegen.v3.generators.handlebars.lambda.LowercaseLambda; import io.swagger.codegen.v3.generators.handlebars.lambda.TitlecaseLambda; import io.swagger.codegen.v3.generators.handlebars.lambda.UppercaseLambda; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; import io.swagger.codegen.v3.utils.ModelUtils; +import io.swagger.codegen.v3.utils.URLPathUtil; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; @@ -29,10 +32,12 @@ import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.parser.util.SchemaTypeUtil; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -101,18 +106,18 @@ public AbstractCSharpCodegen() { Arrays.asList("IDictionary") ); - setReservedWordsLowerCase( + setReservedWords( Arrays.asList( // set "client" as a reserved word to avoid conflicts with IO.Swagger.Client // this is a workaround and can be removed if c# api client is updated to use // fully qualified name - "Client", "client", "parameter", + "Client", "client", "parameter", "File", "List", "list", // local variable names in API methods (endpoints) "localVarPath", "localVarPathParams", "localVarQueryParams", "localVarHeaderParams", "localVarFormParams", "localVarFileParams", "localVarStatusCode", "localVarResponse", "localVarPostBody", "localVarHttpHeaderAccepts", "localVarHttpHeaderAccept", "localVarHttpContentTypes", "localVarHttpContentType", - "localVarStatusCode", + "localVarStatusCode", "ApiResponse", "apiresponse", // C# reserved words "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else", @@ -218,10 +223,6 @@ public void useDateTimeOffset(boolean flag) { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - // {{packageVersion}} if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) { setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION)); @@ -433,12 +434,11 @@ private void postProcessEnumRefs(final Map models) { // This is different in C# than most other generators, because enums in C# are compiled to integral types, // while enums in many other languages are true objects. CodegenModel refModel = enumRefs.get(var.datatype); - var.allowableValues = refModel.allowableValues; + var.allowableValues = new HashMap<>(refModel.allowableValues); updateCodegenPropertyEnum(var); // We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#. var.getVendorExtensions().put(CodegenConstants.IS_PRIMITIVE_TYPE_EXT_NAME, Boolean.TRUE); - var.getVendorExtensions().put(IS_ENUM_EXT_NAME, Boolean.TRUE); } } @@ -532,6 +532,7 @@ public void updateCodegenPropertyEnum(CodegenProperty var) { public Map postProcessOperations(Map objs) { super.postProcessOperations(objs); if (objs != null) { + boolean hasAuthMethods = false; Map operations = (Map) objs.get("operations"); if (operations != null) { List ops = (List) operations.get("operation"); @@ -580,8 +581,12 @@ public Map postProcessOperations(Map objs) { } processOperation(operation); + if (getBooleanValue(operation, CodegenConstants.HAS_AUTH_METHODS_EXT_NAME)) { + hasAuthMethods = true; + } } } + objs.put("hasAuthMethods", hasAuthMethods); } return objs; @@ -738,16 +743,19 @@ public String toDefaultValue(Schema schema) { @Override protected boolean isReservedWord(String word) { // NOTE: This differs from super's implementation in that C# does _not_ want case insensitive matching. - return reservedWords.contains(word); + return reservedWords.contains(word.toLowerCase()); } @Override public String getSchemaType(Schema propertySchema) { String swaggerType = super.getSchemaType(propertySchema); + + swaggerType = getRefSchemaTargetType(propertySchema, swaggerType); + String type; if (swaggerType == null) { - swaggerType = StringUtils.EMPTY; // set swagger type to empty string if null + swaggerType = "object"; } // TODO avoid using toLowerCase as typeMapping should be case-sensitive @@ -762,6 +770,20 @@ public String getSchemaType(Schema propertySchema) { return toModelName(type); } + protected String getRefSchemaTargetType(Schema schema, String schemaType) { + if (schemaType == null) { + return null; + } + if (schema != null && schema.get$ref() != null) { + final Schema refSchema = OpenAPIUtil.getSchemaFromName(schemaType, this.openAPI); + if (refSchema != null && !isObjectSchema(refSchema) && !(refSchema instanceof ArraySchema || refSchema instanceof MapSchema) && refSchema.getEnum() == null) { + schemaType = super.getSchemaType(refSchema); + } + } + return schemaType; + + } + /** * Provides C# strongly typed declaration for simple arrays of some type and arrays of arrays of some type. * @param arr The input array property @@ -901,8 +923,19 @@ public void setInterfacePrefix(final String interfacePrefix) { this.interfacePrefix = interfacePrefix; } + public CodegenModel fromModel(String name, Schema schema, Map allDefinitions) { + final CodegenModel codegenModel = super.fromModel(name, schema, allDefinitions); + if (typeMapping.containsKey(name.toLowerCase()) && isReservedWord(name.toLowerCase())) { + typeMapping.remove(name.toLowerCase()); + } + return codegenModel; + } + @Override public String toEnumValue(String value, String datatype) { + if (value == null) { + return null; + } // C# only supports enums as literals for int, int?, long, long?, byte, and byte?. All else must be treated as strings. // Per: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong. @@ -923,6 +956,12 @@ public String toEnumVarName(String name, String datatype) { // for symbol, e.g. $, # if (getSymbolName(name) != null) { return camelize(getSymbolName(name)); + } + + if (NumberUtils.isNumber(name)) { + return "NUMBER_" + name.replaceAll("-", "MINUS_") + .replaceAll("\\+", "PLUS_") + .replaceAll("\\.", "_DOT_"); } String enumName = sanitizeName(name); @@ -959,6 +998,18 @@ public void setPreserveNewLines(boolean preserveNewLines) { @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); + + final URL urlInfo = URLPathUtil.getServerURL(openAPI); + if ( urlInfo != null && urlInfo.getPort() > 0) { + additionalProperties.put("serverUrl", String.format("%s://%s:%s", urlInfo.getProtocol(), urlInfo.getHost(), urlInfo.getPort())); + + if (StringUtils.isNotBlank(urlInfo.getPath())) { + additionalProperties.put("basePathWithoutHost", urlInfo.getPath()); + } + } else { + additionalProperties.put("serverUrl", URLPathUtil.LOCAL_HOST); + } + if (this.preserveNewLines) { Map schemaMap = openAPI.getComponents() != null ? openAPI.getComponents().getSchemas() : null; if (schemaMap != null) { @@ -1045,6 +1096,24 @@ public void addHandlebarHelpers(Handlebars handlebars) { handlebars.registerHelpers(new CsharpHelper()); } + @Override + protected void addCodegenContentParameters(CodegenOperation codegenOperation, List codegenContents) { + for (CodegenContent content : codegenContents) { + if (content.getIsForm()) { + addParameters(content, codegenOperation.formParams); + } else { + addParameters(content, codegenOperation.bodyParams); + } + addParameters(content, codegenOperation.headerParams); + addParameters(content, codegenOperation.queryParams); + addParameters(content, codegenOperation.pathParams); + } + } + + @Override + public boolean checkAliasModel() { + return true; + } /* TODO: uncomment if/when switching to stream for file upload @Override @@ -1056,4 +1125,4 @@ public void postProcessParameter(CodegenParameter parameter) { } */ -} \ No newline at end of file +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegen.java index ad310bc752..212a596f41 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegen.java @@ -1,29 +1,40 @@ package io.swagger.codegen.v3.generators.dotnet; -import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; - import com.samskivert.mustache.Mustache; - import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenContent; import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenSecurity; import io.swagger.codegen.v3.CodegenType; import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.utils.SemVer; import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.security.SecurityScheme; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.util.*; -import java.util.Map.Entry; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; import static java.util.UUID.randomUUID; public class AspNetCoreServerCodegen extends AbstractCSharpCodegen { private String packageGuid = "{" + randomUUID().toString().toUpperCase() + "}"; + private static final String ASP_NET_CORE_VERSION_OPTION = "--aspnet-core-version"; + private static final String INTERFACE_ONLY_OPTION = "--interface-only"; + private static final String INTERFACE_CONTROLLER_OPTION = "--interface-controller"; + private static final String SWASH_BUCKLE_VERSION_OPTION = "swashBuckleVersion"; + private static final String TARGET_FRAMEWORK = "targetFramework"; + private final String DEFAULT_ASP_NET_CORE_VERSION = "7.0"; + private String aspNetCoreVersion; @SuppressWarnings("hiding") protected Logger LOGGER = LoggerFactory.getLogger(AspNetCoreServerCodegen.class); @@ -34,9 +45,6 @@ public AspNetCoreServerCodegen() { setSourceFolder("src"); outputFolder = "generated-code" + File.separator + this.getName(); - modelTemplateFiles.put("model.mustache", ".cs"); - apiTemplateFiles.put("controller.mustache", ".cs"); - // contextually reserved words // NOTE: C# uses camel cased reserved words, while models are title cased. We don't want lowercase comparisons. reservedWords.addAll( @@ -82,6 +90,21 @@ public AspNetCoreServerCodegen() { addSwitch(CodegenConstants.RETURN_ICOLLECTION, CodegenConstants.RETURN_ICOLLECTION_DESC, this.returnICollection); + + this.aspNetCoreVersion = DEFAULT_ASP_NET_CORE_VERSION; + + addSwitch(INTERFACE_ONLY_OPTION.substring(2), + "Only generate interfaces for controllers", + false); + + addSwitch(INTERFACE_CONTROLLER_OPTION.substring(2), + "Generate interfaces for controllers, implemented by a default controller implementation", + false); + + addOption(ASP_NET_CORE_VERSION_OPTION.substring(2), + "ASP.NET Core version", + DEFAULT_ASP_NET_CORE_VERSION); + } @Override @@ -103,6 +126,11 @@ public String getHelp() { public void processOpts() { super.processOpts(); + setAspNetCoreVersion(); + + modelTemplateFiles.put("model.mustache", ".cs"); + + if (additionalProperties.containsKey(CodegenConstants.OPTIONAL_PROJECT_GUID)) { setPackageGuid((String) additionalProperties.get(CodegenConstants.OPTIONAL_PROJECT_GUID)); } @@ -110,31 +138,89 @@ public void processOpts() { additionalProperties.put("dockerTag", this.packageName.toLowerCase()); - apiPackage = packageName + ".Controllers"; - modelPackage = packageName + ".Models"; + additionalProperties.put("aspNetCoreVersion", aspNetCoreVersion); String packageFolder = sourceFolder + File.separator + packageName; + boolean isThreeDotOneVersion = aspNetCoreVersion.equals("3.1"); + + if (aspNetCoreVersion.equals("2.0")) { + apiTemplateFiles.put("controller.mustache", ".cs"); + addInterfaceControllerTemplate(); + + supportingFiles.add(new SupportingFile("Program.mustache", packageFolder, "Program.cs")); + supportingFiles.add(new SupportingFile("Project.csproj.mustache", packageFolder, this.packageName + ".csproj")); + supportingFiles.add(new SupportingFile("Dockerfile.mustache", packageFolder, "Dockerfile")); + supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs")); + supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs")); + supportingFiles.add(new SupportingFile("Startup.mustache", packageFolder, "Startup.cs")); + } else if (aspNetCoreVersion.equals("2.1") || aspNetCoreVersion.equals("2.2")) { + apiTemplateFiles.put("2.1/controller.mustache", ".cs"); + addInterfaceControllerTemplate(); + + supportingFiles.add(new SupportingFile("2.1/Program.mustache", packageFolder, "Program.cs")); + supportingFiles.add(new SupportingFile("2.1/Project.csproj.mustache", packageFolder, this.packageName + ".csproj")); + supportingFiles.add(new SupportingFile("2.1/Dockerfile.mustache", packageFolder, "Dockerfile")); + supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs")); + supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs")); + supportingFiles.add(new SupportingFile("Startup.mustache", packageFolder, "Startup.cs")); + } else { + final SemVer semVer = new SemVer(aspNetCoreVersion); + apiTemplateFiles.put("3.0/controller.mustache", ".cs"); + addInterfaceControllerTemplate(); + + supportingFiles.add(new SupportingFile("3.0" + File.separator + "Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs")); + supportingFiles.add(new SupportingFile("3.0" + File.separator + "Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs")); + + supportingFiles.add(new SupportingFile("3.0/Startup.mustache", packageFolder, "Startup.cs")); + supportingFiles.add(new SupportingFile("3.0/Program.mustache", packageFolder, "Program.cs")); + + if (semVer.atLeast("5.0")) { + additionalProperties.put(SWASH_BUCKLE_VERSION_OPTION, "6.4.0"); + supportingFiles.add(new SupportingFile("3.1/Project.csproj.mustache", packageFolder, this.packageName + ".csproj")); + } + if (semVer.atLeast("7.0")) { + additionalProperties.put(TARGET_FRAMEWORK, "net7.0"); + } else if (semVer.atLeast("6.0")) { + additionalProperties.put(TARGET_FRAMEWORK, "net6.0"); + } else if (semVer.atLeast("5.0")) { + additionalProperties.put(TARGET_FRAMEWORK, "net5.0"); + } else if (semVer.atLeast("3.1")) { + additionalProperties.put(SWASH_BUCKLE_VERSION_OPTION, "5.5.1"); + additionalProperties.put(TARGET_FRAMEWORK, "netcoreapp3.1"); + supportingFiles.add(new SupportingFile("3.1/Project.csproj.mustache", packageFolder, this.packageName + ".csproj")); + } else { + supportingFiles.add(new SupportingFile("3.0/Project.csproj.mustache", packageFolder, this.packageName + ".csproj")); + } + supportingFiles.add(new SupportingFile("3.0/Dockerfile.mustache", packageFolder, "Dockerfile")); + } + + if (!additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) { + apiPackage = packageName + ".Controllers"; + additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage); + } + + if (!additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) { + modelPackage = packageName + ".Models"; + additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage); + } + supportingFiles.add(new SupportingFile("NuGet.Config", "", "NuGet.Config")); supportingFiles.add(new SupportingFile("build.sh.mustache", "", "build.sh")); supportingFiles.add(new SupportingFile("build.bat.mustache", "", "build.bat")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("Solution.mustache", "", this.packageName + ".sln")); - supportingFiles.add(new SupportingFile("Dockerfile.mustache", packageFolder, "Dockerfile")); supportingFiles.add(new SupportingFile("gitignore", packageFolder, ".gitignore")); supportingFiles.add(new SupportingFile("appsettings.json", packageFolder, "appsettings.json")); - supportingFiles.add(new SupportingFile("Startup.mustache", packageFolder, "Startup.cs")); - supportingFiles.add(new SupportingFile("Program.mustache", packageFolder, "Program.cs")); supportingFiles.add(new SupportingFile("validateModel.mustache", packageFolder + File.separator + "Attributes", "ValidateModelStateAttribute.cs")); supportingFiles.add(new SupportingFile("web.config", packageFolder, "web.config")); - supportingFiles.add(new SupportingFile("Project.csproj.mustache", packageFolder, this.packageName + ".csproj")); - - supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json")); - - supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathFilter.mustache", packageFolder + File.separator + "Filters", "BasePathFilter.cs")); - supportingFiles.add(new SupportingFile("Filters" + File.separator + "GeneratePathParamsValidationFilter.mustache", packageFolder + File.separator + "Filters", "GeneratePathParamsValidationFilter.cs")); + if (isThreeDotOneVersion) { + supportingFiles.add(new SupportingFile("3.1/Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json")); + } else { + supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json")); + } supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md")); supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html")); @@ -165,6 +251,16 @@ public String apiFileFolder() { return outputFolder + File.separator + sourceFolder + File.separator + packageName + File.separator + "Controllers"; } + @Override + public String apiFilename(String templateName, String tag) { + boolean isInterface = templateName.equalsIgnoreCase("icontroller.mustache"); + String suffix = apiTemplateFiles().get(templateName); + if (isInterface) { + return apiFileFolder() + "/I" + toApiFilename(tag) + suffix; + } + return apiFileFolder() + '/' + toApiFilename(tag) + suffix; + } + @Override public String modelFileFolder() { return outputFolder + File.separator + sourceFolder + File.separator + packageName + File.separator + "Models"; @@ -200,6 +296,16 @@ protected void processOperation(CodegenOperation operation) { // Converts, for example, PUT to HttpPut for controller attributes operation.httpMethod = "Http" + operation.httpMethod.substring(0, 1) + operation.httpMethod.substring(1).toLowerCase(); + + if (operation.getContents() != null && !operation.getContents().isEmpty()) { + List contents = operation.getContents() + .stream() + .filter(codegenContent -> !codegenContent.getIsForm()) + .collect( + Collectors.toList()); + operation.getContents().clear(); + operation.getContents().addAll(contents); + } } @Override @@ -207,4 +313,93 @@ public Mustache.Compiler processCompiler(Mustache.Compiler compiler) { // To avoid unexpected behaviors when options are passed programmatically such as { "useCollection": "" } return super.processCompiler(compiler).emptyStringIsFalse(true); } + + @Override + public List fromSecurity(Map securitySchemeMap) { + final List securities = super.fromSecurity(securitySchemeMap); + if (securities == null || securities.isEmpty()) { + return securities; + } + boolean hasBasic = false; + boolean hasBearer = false; + boolean hasApiKey = false; + for (int index = 0; index < securities.size(); index++) { + final CodegenSecurity codegenSecurity = securities.get(index); + if (getBooleanValue(codegenSecurity, CodegenConstants.IS_BASIC_EXT_NAME)) { + hasBasic = true; + } + if (getBooleanValue(codegenSecurity, CodegenConstants.IS_BEARER_EXT_NAME)) { + hasBearer = true; + } + if (getBooleanValue(codegenSecurity, CodegenConstants.IS_API_KEY_EXT_NAME)) { + hasApiKey = true; + } + } + final String packageFolder = sourceFolder + File.separator + packageName; + if (hasBasic) { + supportingFiles.add(new SupportingFile("Security/BasicAuthenticationHandler.mustache", packageFolder + File.separator + "Security", "BasicAuthenticationHandler.cs")); + } + if (hasBearer) { + supportingFiles.add(new SupportingFile("Security/BearerAuthenticationHandler.mustache", packageFolder + File.separator + "Security", "BearerAuthenticationHandler.cs")); + } + if (hasApiKey) { + supportingFiles.add(new SupportingFile("Security/ApiKeyAuthenticationHandler.mustache", packageFolder + File.separator + "Security", "ApiKeyAuthenticationHandler.cs")); + } + return securities; + } + + private void addInterfaceControllerTemplate() { + String interfaceOnlyOption = getOptionValue(INTERFACE_ONLY_OPTION); + boolean interfaceOnly = false; + if (StringUtils.isNotBlank(interfaceOnlyOption)) { + interfaceOnly = Boolean.valueOf(getOptionValue(INTERFACE_ONLY_OPTION)); + } else { + if (additionalProperties.get(INTERFACE_ONLY_OPTION.substring(2)) != null) { + interfaceOnly = Boolean.valueOf(additionalProperties.get(INTERFACE_ONLY_OPTION.substring(2)).toString()); + } + } + + String interfaceControllerOption = getOptionValue(INTERFACE_CONTROLLER_OPTION); + boolean interfaceController = false; + if (StringUtils.isNotBlank(interfaceControllerOption)) { + interfaceController = Boolean.valueOf(getOptionValue(INTERFACE_CONTROLLER_OPTION)); + } else { + if (additionalProperties.get(INTERFACE_CONTROLLER_OPTION.substring(2)) != null) { + interfaceController = Boolean.valueOf(additionalProperties.get(INTERFACE_CONTROLLER_OPTION.substring(2)).toString()); + } + } + + if (interfaceController) { + apiTemplateFiles.put("icontroller.mustache", ".cs"); + additionalProperties.put("interfaceController", Boolean.TRUE); + } + if (interfaceOnly) { + apiTemplateFiles.clear(); + apiTemplateFiles.put("icontroller.mustache", ".cs"); + } + } + + + @Override + public String getArgumentsLocation() { + return "/arguments/aspnetcore.yaml"; + } + + private void setAspNetCoreVersion() { + String optionValue = getOptionValue(ASP_NET_CORE_VERSION_OPTION); + if (StringUtils.isBlank(optionValue)) { + if (additionalProperties.get(ASP_NET_CORE_VERSION_OPTION.substring(2)) != null) { + this.aspNetCoreVersion = additionalProperties.get(ASP_NET_CORE_VERSION_OPTION.substring(2)).toString(); + } else { + return; + } + } else { + this.aspNetCoreVersion = optionValue; + } + final SemVer semVer = new SemVer(this.aspNetCoreVersion); + if (semVer.compareTo(new SemVer("2.0")) < 0) { + LOGGER.error("version '" + this.aspNetCoreVersion + "' is not supported, switching to default version: '" + DEFAULT_ASP_NET_CORE_VERSION + "'"); + this.aspNetCoreVersion = DEFAULT_ASP_NET_CORE_VERSION; + } + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegen.java index 3752731e04..9112e9cc3a 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegen.java @@ -516,7 +516,7 @@ public CodegenModel fromModel(String name, Schema schema, Map al if (allDefinitions != null && codegenModel != null && codegenModel.parent != null) { final Schema parentModel = allDefinitions.get(toModelName(codegenModel.parent)); if (parentModel != null) { - final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel); + final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel, allDefinitions); boolean hasEnums = getBooleanValue(codegenModel, HAS_ENUMS_EXT_NAME); if (hasEnums) { codegenModel = this.reconcileInlineEnums(codegenModel, parentCodegenModel); @@ -587,6 +587,26 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert super.postProcessModelProperty(model, property); } + @Override + protected void fixUpParentAndInterfaces(CodegenModel codegenModel, Map allModels) { + super.fixUpParentAndInterfaces(codegenModel, allModels); + final CodegenModel parentModel = codegenModel.getParentModel(); + if (parentModel == null || (codegenModel.getReadWriteVars() == null || codegenModel.getReadWriteVars().isEmpty()) || (parentModel.getVars() == null || parentModel.getVars().isEmpty())) { + return; + } + codegenModel.setParentVars(parentModel.getVars()); + parentModel.getVars().forEach(parentProperty -> { + codegenModel.getReadWriteVars().stream() + .filter(codegenProperty -> parentProperty.getName().equalsIgnoreCase(codegenProperty.getName())) + .findFirst() + .ifPresent(codegenProperty -> { + codegenProperty.setDatatype(parentProperty.getDatatype()); + codegenProperty.setDatatypeWithEnum(parentProperty.getDatatypeWithEnum()); + }); + }); + + } + /* * The swagger pattern spec follows the Perl convention and style of modifiers. .NET * does not support this syntax directly so we need to convert the pattern to a .NET compatible @@ -600,8 +620,8 @@ public void postProcessPattern(String pattern, Map vendorExtensi //Must follow Perl /pattern/modifiers convention if (pattern.charAt(0) != '/' || i < 2) { - throw new IllegalArgumentException("Pattern must follow the Perl " - + "/pattern/modifiers convention. " + pattern + " is not valid."); + pattern = String.format("/%s/", pattern);; + i = pattern.lastIndexOf('/'); } String regex = pattern.substring(1, i).replace("'", "\'"); @@ -821,4 +841,4 @@ public Mustache.Compiler processCompiler(Mustache.Compiler compiler) { // To avoid unexpected behaviors when options are passed programmatically such as { "supportsAsync": "" } return super.processCompiler(compiler).emptyStringIsFalse(true); } -} \ No newline at end of file +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/dotnet/CsharpDotNet2ClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/dotnet/CsharpDotNet2ClientCodegen.java index 1045b0d1fe..0255be7289 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/dotnet/CsharpDotNet2ClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/dotnet/CsharpDotNet2ClientCodegen.java @@ -9,6 +9,7 @@ public class CsharpDotNet2ClientCodegen extends AbstractCSharpCodegen { public static final String CLIENT_PACKAGE = "clientPackage"; + public static final String USE_CSPROJ_FILE = "useCsProjFile"; protected String clientPackage = "IO.Swagger.Client"; protected String apiDocPath = "docs/"; protected String modelDocPath = "docs/"; @@ -68,6 +69,9 @@ public void processOpts() { supportingFiles.add(new SupportingFile("packages.config.mustache", "vendor", "packages.config")); supportingFiles.add(new SupportingFile("compile-mono.sh.mustache", "", "compile-mono.sh")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + if (additionalProperties.containsKey(USE_CSPROJ_FILE) && Boolean.parseBoolean(additionalProperties.get(USE_CSPROJ_FILE).toString())) { + supportingFiles.add(new SupportingFile("csproj.mustache", "", clientPackage + ".csproj")); + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/examples/ExampleGenerator.java b/src/main/java/io/swagger/codegen/v3/generators/examples/ExampleGenerator.java index e62ab976b6..ea1358a14d 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/examples/ExampleGenerator.java +++ b/src/main/java/io/swagger/codegen/v3/generators/examples/ExampleGenerator.java @@ -157,7 +157,12 @@ public List> generate(Map examples, List processedModels) { -// logger.debug("Resolving example for property {}...", schema); + if (processedModels.contains(schema.get$ref())) { + return schema.getExample(); + } + if (StringUtils.isNotBlank(schema.get$ref())) { + processedModels.add(schema.get$ref()); + } if (schema.getExample() != null) { logger.debug("Example set in swagger spec, returning example: '{}'", schema.getExample().toString()); return schema.getExample(); @@ -190,6 +195,10 @@ private Object resolveSchemaToExample(String propertyName, String mediaType, Sch Schema innerType = ((ArraySchema) schema).getItems(); if (innerType != null) { int arrayLength = schema.getMaxItems() != null ? schema.getMaxItems() : 2; + if (arrayLength > 10) { + logger.warn("value of maxItems of property {} is {}; limiting to 10 examples", schema, arrayLength); + arrayLength = 10; + } Object[] objectProperties = new Object[arrayLength]; Object objProperty = resolveSchemaToExample(propertyName, mediaType, innerType, processedModels); for(int i=0; i < arrayLength; i++) { @@ -238,7 +247,7 @@ private Object resolveSchemaToExample(String propertyName, String mediaType, Sch return "{}"; } return resolveSchemaToExample(propertyName, mediaType, model, processedModels); - } else if (schema instanceof ObjectSchema) { + } else if (schema instanceof ObjectSchema || schema.getProperties() != null) { Map values = new HashMap<>(); if (schema.getProperties() != null) { logger.debug("Creating example from model values"); @@ -269,10 +278,12 @@ private double randomNumber(Double min, Double max) { } private Object resolveModelToExample(String name, String mediaType, Schema schema, Set processedModels) { - if (processedModels.contains(name)) { + if (processedModels.contains(schema.get$ref())) { return schema.getExample(); } - processedModels.add(name); + if (StringUtils.isNotBlank(schema.get$ref())) { + processedModels.add(schema.get$ref()); + } Map values = new HashMap<>(); logger.debug("Resolving model '{}' to example", name); diff --git a/src/main/java/io/swagger/codegen/v3/generators/features/NotNullAnnotationFeatures.java b/src/main/java/io/swagger/codegen/v3/generators/features/NotNullAnnotationFeatures.java new file mode 100644 index 0000000000..20ed3aa20c --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/features/NotNullAnnotationFeatures.java @@ -0,0 +1,11 @@ +package io.swagger.codegen.v3.generators.features; + +public interface NotNullAnnotationFeatures { + + // Language supports generating not Null Jackson Annotation + String NOT_NULL_JACKSON_ANNOTATION = "notNullJacksonAnnotation"; + + void setNotNullJacksonAnnotation(boolean notNullJacksonAnnotation); + + boolean isNotNullJacksonAnnotation(); +} \ No newline at end of file diff --git a/src/main/java/io/swagger/codegen/v3/generators/go/AbstractGoCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/go/AbstractGoCodegen.java new file mode 100644 index 0000000000..7598526d11 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/go/AbstractGoCodegen.java @@ -0,0 +1,588 @@ +package io.swagger.codegen.v3.generators.go; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenContent; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenParameter; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.ISchemaHandler; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.SchemaHandler; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +public abstract class AbstractGoCodegen extends DefaultCodegenConfig { + + protected static Logger LOGGER = LoggerFactory.getLogger(AbstractGoCodegen.class); + + protected boolean withXml = false; + + protected String packageName = "swagger"; + + public AbstractGoCodegen() { + super(); + + hideGenerationTimestamp = Boolean.FALSE; + + defaultIncludes = new HashSet<>( + Arrays.asList( + "map", + "array") + ); + + languageSpecificPrimitives = new HashSet<>( + Arrays.asList( + "string", + "bool", + "uint", + "uint32", + "uint64", + "int", + "int32", + "int64", + "float32", + "float64", + "complex64", + "complex128", + "rune", + "byte") + ); + + instantiationTypes.clear(); + /*instantiationTypes.put("array", "GoArray"); + instantiationTypes.put("map", "GoMap");*/ + + typeMapping.clear(); + typeMapping.put("integer", "int32"); + typeMapping.put("long", "int64"); + typeMapping.put("number", "float32"); + typeMapping.put("float", "float32"); + typeMapping.put("double", "float64"); + typeMapping.put("BigDecimal", "float64"); + typeMapping.put("boolean", "bool"); + typeMapping.put("string", "string"); + typeMapping.put("UUID", "string"); + typeMapping.put("date", "string"); + typeMapping.put("DateTime", "time.Time"); + typeMapping.put("password", "string"); + typeMapping.put("File", "*os.File"); + typeMapping.put("file", "*os.File"); + // map binary to string as a workaround + // the correct solution is to use []byte + typeMapping.put("binary", "*os.File"); + typeMapping.put("ByteArray", "string"); + typeMapping.put("object", "interface{}"); + typeMapping.put("UUID", "string"); + + importMapping = new HashMap<>(); + + cliOptions.clear(); + cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "Go package name (convention: lowercase).") + .defaultValue("swagger")); + + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC) + .defaultValue(Boolean.TRUE.toString())); + } + + /** + * Escapes a reserved word as defined in the `reservedWords` array. Handle escaping + * those terms here. This logic is only called if a variable matches the reserved words + * + * @return the escaped term + */ + @Override + public String escapeReservedWord(String name) { + // Can't start with an underscore, as our fields need to start with an + // UppercaseLetter so that Go treats them as public/visible. + + // Options? + // - MyName + // - AName + // - TheName + // - XName + // - X_Name + // ... or maybe a suffix? + // - Name_ ... think this will work. + if (this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return camelize(name) + '_'; + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = sanitizeName(name.replaceAll("-", "_")); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) + return name; + + // camelize (lower first character) the variable name + // pet_id => PetId + name = camelize(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name)) + name = escapeReservedWord(name); + + // for reserved word or word starting with number, append _ + if (name.matches("^\\d.*")) + name = "Var" + name; + + return name; + } + + @Override + public String toParamName(String name) { + // params should be lowerCamelCase. E.g. "person Person", instead of + // "Person Person". + // + // REVISIT: Actually, for idiomatic go, the param name should + // really should just be a letter, e.g. "p Person"), but we'll get + // around to that some other time... Maybe. + return camelize(toVarName(name), true); + } + + @Override + public String toModelName(String name) { + // camelize the model name + // phone_number => PhoneNumber + return camelize(toModel(name)); + } + + @Override + public String toModelFilename(String name) { + return toModel("model_" + name); + } + + public String toModel(String name) { + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + + name = sanitizeName(name); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + ("model_" + name)); + name = "model_" + name; // e.g. return => ModelReturn (after camelize) + } + + // model name starts with number + if (name.matches("^\\d.*")) { + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + + ("model_" + name)); + name = "model_" + name; // e.g. 200Response => Model200Response (after camelize) + } + + return underscore(name); + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + // e.g. PetApi.go => pet_api.go + return "api_" + underscore(name); + } + + /** + * Overrides postProcessParameter to add a vendor extension "x-exportParamName". + * This is useful when paramName starts with a lowercase letter, but we need that + * param to be exportable (starts with an Uppercase letter). + * + * @param parameter CodegenParameter object to be processed. + */ + @Override + public void postProcessParameter(CodegenParameter parameter) { + + // Give the base class a chance to process + super.postProcessParameter(parameter); + + char nameFirstChar = parameter.paramName.charAt(0); + if (Character.isUpperCase(nameFirstChar)) { + // First char is already uppercase, just use paramName. + parameter.vendorExtensions.put("x-exportParamName", parameter.paramName); + } else { + // It's a lowercase first char, let's convert it to uppercase + StringBuilder sb = new StringBuilder(parameter.paramName); + sb.setCharAt(0, Character.toUpperCase(nameFirstChar)); + parameter.vendorExtensions.put("x-exportParamName", sb.toString()); + } + } + + @Override + public String getTypeDeclaration(Schema schema) { + if(schema instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema) schema; + Schema inner = arraySchema.getItems(); + if (inner instanceof ComposedSchema && schema.getExtensions() != null && schema.getExtensions().containsKey("x-schema-name")) { + final ComposedSchema composedSchema = (ComposedSchema) inner; + final String prefix; + if (composedSchema.getAllOf() != null && !composedSchema.getAllOf().isEmpty()) { + prefix = SchemaHandler.ALL_OF_PREFFIX; + } else if (composedSchema.getOneOf() != null && !composedSchema.getOneOf().isEmpty()) { + prefix = SchemaHandler.ONE_OF_PREFFIX; + } else { + prefix = SchemaHandler.ANY_OF_PREFFIX; + } + return "[]" + toModelName(prefix + schema.getExtensions().remove("x-schema-name")) + SchemaHandler.ARRAY_ITEMS_SUFFIX; + } else { + return "[]" + getTypeDeclaration(inner); + } + } else if (schema instanceof MapSchema && hasSchemaProperties(schema)) { + MapSchema mapSchema = (MapSchema) schema; + Schema inner = (Schema) mapSchema.getAdditionalProperties(); + + return getSchemaType(schema) + "[string]" + getTypeDeclaration(inner); + } else if (schema.get$ref() != null) { + final String simpleRefName = OpenAPIUtil.getSimpleRef(schema.get$ref()); + final Schema refSchema = OpenAPIUtil.getSchemaFromName(simpleRefName, this.openAPI); + if (refSchema != null && (refSchema instanceof ArraySchema || refSchema instanceof MapSchema)) { + refSchema.addExtension("x-schema-name", simpleRefName); + return getTypeDeclaration(refSchema); + } + } + // Not using the supertype invocation, because we want to UpperCamelize + // the type. + String schemaType = getSchemaType(schema); + if (typeMapping.containsKey(schemaType)) { + return typeMapping.get(schemaType); + } + if(typeMapping.containsValue(schemaType)) { + return schemaType; + } + if(languageSpecificPrimitives.contains(schemaType)) { + return schemaType; + } + return toModelName(schemaType); + } + + @Override + public String getSchemaType(Schema schema) { + String schemaType = super.getSchemaType(schema); + + if (schema.get$ref() != null) { + final Schema refSchema = OpenAPIUtil.getSchemaFromName(schemaType, this.openAPI); + if (refSchema != null && !isObjectSchema(refSchema) && refSchema.getEnum() == null) { + schemaType = super.getSchemaType(refSchema); + } + } + + String type; + if(typeMapping.containsKey(schemaType)) { + type = typeMapping.get(schemaType); + if(languageSpecificPrimitives.contains(type)) { + return type; + } + } else { + type = schemaType; + } + return type; + } + + @Override + public String toOperationId(String operationId) { + String sanitizedOperationId = sanitizeName(operationId); + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(sanitizedOperationId)) { + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + + camelize("call_" + operationId)); + sanitizedOperationId = "call_" + sanitizedOperationId; + } + return camelize(sanitizedOperationId); + } + + @Override + public Map postProcessOperations(Map objs) { + @SuppressWarnings("unchecked") + Map objectMap = (Map) objs.get("operations"); + @SuppressWarnings("unchecked") + List operations = (List) objectMap.get("operation"); + for (CodegenOperation operation : operations) { + // http method verb conversion (e.g. PUT => Put) + operation.httpMethod = camelize(operation.httpMethod.toLowerCase()); + } + + // remove model imports to avoid error + List> imports = (List>) objs.get("imports"); + if (imports == null) + return objs; + + Iterator> iterator = imports.iterator(); + while (iterator.hasNext()) { + String _import = iterator.next().get("import"); + if (_import.startsWith(apiPackage())) + iterator.remove(); + } + + // this will only import "fmt" if there are items in pathParams + for (CodegenOperation operation : operations) { + if (operation.pathParams != null && operation.pathParams.size() > 0) { + imports.add(createMapping("import", "fmt")); + break; //just need to import once + } + } + + boolean addedOptionalImport = false; + boolean addedTimeImport = false; + boolean addedOSImport = false; + for (CodegenOperation operation : operations) { + for (CodegenContent codegenContent : operation.getContents()) { + for (CodegenParameter param : codegenContent.getParameters()) { + // import "os" if the operation uses files + if (!addedOSImport && param.dataType == "*os.File") { + imports.add(createMapping("import", "os")); + addedOSImport = true; + } + + // import "time" if the operation has a required time parameter. + if (param.required) { + if (!addedTimeImport && param.dataType == "time.Time") { + imports.add(createMapping("import", "time")); + addedTimeImport = true; + } + } else { + if (!addedOptionalImport) { + imports.add(createMapping("import", "github.com/antihax/optional")); + addedOptionalImport = true; + } + // We need to specially map Time type to the optionals package + if (param.dataType == "time.Time") { + param.vendorExtensions.put("x-optionalDataType", "Time"); + continue; + } + // Map optional type to dataType + param.vendorExtensions.put("x-optionalDataType", param.dataType.substring(0, 1).toUpperCase() + param.dataType.substring(1)); + } + } + } + } + + // recursively add import for mapping one type to multiple imports + List> recursiveImports = (List>) objs.get("imports"); + if (recursiveImports == null) + return objs; + + ListIterator> listIterator = imports.listIterator(); + while (listIterator.hasNext()) { + String _import = listIterator.next().get("import"); + // if the import package happens to be found in the importMapping (key) + // add the corresponding import package to the list + if (importMapping.containsKey(_import)) { + listIterator.add(createMapping("import", importMapping.get(_import))); + } + } + + return objs; + } + + @Override + public Map postProcessModels(Map objs) { + // remove model imports to avoid error + List> imports = (List>) objs.get("imports"); + final String prefix = modelPackage(); + Iterator> iterator = imports.iterator(); + while (iterator.hasNext()) { + String _import = iterator.next().get("import"); + if (_import.startsWith(prefix)) + iterator.remove(); + } + + boolean addedTimeImport = false; + boolean addedOSImport = false; + List> models = (List>) objs.get("models"); + for (Map m : models) { + Object v = m.get("model"); + if (v instanceof CodegenModel) { + CodegenModel model = (CodegenModel) v; + for (CodegenProperty param : model.vars) { + if (!addedTimeImport && param.baseType == "time.Time") { + imports.add(createMapping("import", "time")); + addedTimeImport = true; + } + if (!addedOSImport && param.baseType == "*os.File") { + imports.add(createMapping("import", "os")); + addedOSImport = true; + } + } + } + } + // recursively add import for mapping one type to multiple imports + List> recursiveImports = (List>) objs.get("imports"); + if (recursiveImports == null) + return objs; + + ListIterator> listIterator = imports.listIterator(); + while (listIterator.hasNext()) { + String _import = listIterator.next().get("import"); + // if the import package happens to be found in the importMapping (key) + // add the corresponding import package to the list + if (importMapping.containsKey(_import)) { + listIterator.add(createMapping("import", importMapping.get(_import))); + } + } + + return postProcessModelsEnum(objs); + } + + @Override + public Map postProcessSupportingFileData(Map objs) { + OpenAPI openAPI = (OpenAPI)objs.get("openAPI"); + if(openAPI != null) { + try { + objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(openAPI)); + } catch (JsonProcessingException e) { + LOGGER.error(e.getMessage(), e); + } + } + return super.postProcessSupportingFileData(objs); + } + + @Override + protected boolean needToImport(String type) { + return !defaultIncludes.contains(type) && !languageSpecificPrimitives.contains(type); + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } + + public Map createMapping(String key, String value) { + Map customImport = new HashMap(); + customImport.put(key, value); + + return customImport; + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) { + return value; + } else { + return escapeText(value); + } + } + + @Override + public String toEnumDefaultValue(String value, String datatype) { + return datatype + "_" + value; + } + + @Override + public String toEnumVarName(String name, String datatype) { + if (name.length() == 0) { + return "EMPTY"; + } + + // number + if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) { + String varName = name; + varName = varName.replaceAll("-", "MINUS_"); + varName = varName.replaceAll("\\+", "PLUS_"); + varName = varName.replaceAll("\\.", "_DOT_"); + return varName; + } + + // for symbol, e.g. $, # + if (getSymbolName(name) != null) { + return getSymbolName(name).toUpperCase(); + } + + // string + String enumName = sanitizeName(underscore(name).toUpperCase()); + enumName = enumName.replaceFirst("^_", ""); + enumName = enumName.replaceFirst("_$", ""); + + if (isReservedWord(enumName) || enumName.matches("\\d.*")) { // reserved word or starts with number + return escapeReservedWord(enumName); + } else { + return enumName; + } + } + + @Override + public String toEnumName(CodegenProperty property) { + String enumName = underscore(toModelName(property.name)).toUpperCase(); + + // remove [] for array or map of enum + enumName = enumName.replace("[]", ""); + + if (enumName.matches("\\d.*")) { // starts with number + return "_" + enumName; + } else { + return enumName; + } + } + + public void setWithXml(boolean withXml) { + this.withXml = withXml; + } + + @Override + public CodegenModel fromModel(String name, Schema schema, Map allDefinitions) { + final CodegenModel codegenModel = super.fromModel(name, schema, allDefinitions); + if (!getBooleanValue(codegenModel, CodegenConstants.IS_ALIAS_EXT_NAME)) { + boolean isAlias = schema instanceof ArraySchema + || schema instanceof MapSchema + || (!isObjectSchema(schema) && schema.getEnum() == null); + + codegenModel.getVendorExtensions().put(CodegenConstants.IS_ALIAS_EXT_NAME, isAlias); + } + + + + return codegenModel; + } + + @Override + public ISchemaHandler getSchemaHandler() { + return new GoSchemaHandler(this); + } + + @Override + public boolean checkAliasModel() { + return true; + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/go/GoClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/go/GoClientCodegen.java new file mode 100644 index 0000000000..fa36b6438e --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/go/GoClientCodegen.java @@ -0,0 +1,125 @@ +package io.swagger.codegen.v3.generators.go; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.util.Arrays; +import java.util.Map; + +public class GoClientCodegen extends AbstractGoCodegen { + protected String packageVersion = "1.0.0"; + protected String apiDocPath = "docs/"; + protected String modelDocPath = "docs/"; + public static final String WITH_XML = "withXml"; + + public GoClientCodegen() { + this.outputFolder = "generated-code/go"; + this.modelTemplateFiles.put("model.mustache", ".go"); + this.apiTemplateFiles.put("api.mustache", ".go"); + this.modelDocTemplateFiles.put("model_doc.mustache", ".md"); + this.apiDocTemplateFiles.put("api_doc.mustache", ".md"); + this.hideGenerationTimestamp = Boolean.TRUE; + this.setReservedWordsLowerCase(Arrays.asList("string", "bool", "uint", "uint8", "uint16", "uint32", "uint64", "int", "int8", "int16", "int32", "int64", "float32", "float64", "complex64", "complex128", "rune", "byte", "uintptr", "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", "error", "ApiResponse", "nil")); + this.cliOptions.add((new CliOption("packageVersion", "Go package version.")).defaultValue("1.0.0")); + this.cliOptions.add(CliOption.newBoolean("withXml", "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)")); + } + + @Override + public String getDefaultTemplateDir() { + return "go"; + } + + public void processOpts() { + super.processOpts(); + + if (this.additionalProperties.containsKey("packageName")) { + this.setPackageName((String)this.additionalProperties.get("packageName")); + } else { + this.setPackageName("swagger"); + } + + if (this.additionalProperties.containsKey("packageVersion")) { + this.setPackageVersion((String)this.additionalProperties.get("packageVersion")); + } else { + this.setPackageVersion("1.0.0"); + } + + this.additionalProperties.put("packageName", this.packageName); + this.additionalProperties.put("packageVersion", this.packageVersion); + this.additionalProperties.put("apiDocPath", this.apiDocPath); + this.additionalProperties.put("modelDocPath", this.modelDocPath); + this.modelPackage = this.packageName; + this.apiPackage = this.packageName; + this.supportingFiles.add(new SupportingFile("swagger.mustache", "api", "swagger.yaml")); + this.supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + this.supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + this.supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); + this.supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.go")); + this.supportingFiles.add(new SupportingFile("client.mustache", "", "client.go")); + this.supportingFiles.add(new SupportingFile("response.mustache", "", "response.go")); + this.supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml")); + if (this.additionalProperties.containsKey("withXml")) { + this.setWithXml(Boolean.parseBoolean(this.additionalProperties.get("withXml").toString())); + if (this.withXml) { + this.additionalProperties.put("withXml", "true"); + } + } + + } + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "go"; + } + + public String getHelp() { + return "Generates a Go client library (beta)."; + } + + public String apiFileFolder() { + return this.outputFolder + File.separator; + } + + public String modelFileFolder() { + return this.outputFolder + File.separator; + } + + public String apiDocFileFolder() { + return (this.outputFolder + "/" + this.apiDocPath).replace('/', File.separatorChar); + } + + public String modelDocFileFolder() { + return (this.outputFolder + "/" + this.modelDocPath).replace('/', File.separatorChar); + } + + public String toModelDocFilename(String name) { + return this.toModelName(name); + } + + public String toApiDocFilename(String name) { + return this.toApiName(name); + } + + public void setPackageVersion(String packageVersion) { + this.packageVersion = packageVersion; + } + + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map schemas, OpenAPI openAPI) { + final CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, schemas, openAPI); + if (codegenOperation.getHasBodyParam() || codegenOperation.bodyParam != null) { + codegenOperation.getFormParams().clear(); + } + return codegenOperation; + } +} + diff --git a/src/main/java/io/swagger/codegen/v3/generators/go/GoSchemaHandler.java b/src/main/java/io/swagger/codegen/v3/generators/go/GoSchemaHandler.java new file mode 100644 index 0000000000..7b4fdbcf30 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/go/GoSchemaHandler.java @@ -0,0 +1,28 @@ +package io.swagger.codegen.v3.generators.go; + +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.SchemaHandler; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.Map; + +public class GoSchemaHandler extends SchemaHandler { + + public GoSchemaHandler(DefaultCodegenConfig codegenConfig) { + super(codegenConfig); + } + + protected void addInterfaces(List schemas, CodegenModel composedModel, Map allModels) { + for (Schema interfaceSchema : schemas) { + final String ref = interfaceSchema.get$ref(); + if (StringUtils.isBlank(ref)) { + continue; + } + final String schemaName = ref.substring(ref.lastIndexOf("/") + 1); + this.addInterfaceModel(composedModel, allModels.get(codegenConfig.toModelName(schemaName))); + } + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/go/GoServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/go/GoServerCodegen.java new file mode 100644 index 0000000000..1b7e8d77a6 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/go/GoServerCodegen.java @@ -0,0 +1,160 @@ +package io.swagger.codegen.v3.generators.go; + +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; + +import java.io.File; +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; + +public class GoServerCodegen extends AbstractGoCodegen { + + protected String apiVersion = "1.0.0"; + protected int serverPort = 8080; + protected String projectName = "swagger-server"; + protected String apiPath = "go"; + + public GoServerCodegen() { + super(); + + // set the output folder here + outputFolder = "generated-code/go"; + + /* + * Models. You can write model files using the modelTemplateFiles map. + * if you want to create one template for file, you can do so here. + * for multiple files for model, just put another entry in the `modelTemplateFiles` with + * a different extension + */ + modelTemplateFiles.put( + "model.mustache", + ".go"); + + /* + * Api classes. You can write classes for each Api file with the apiTemplateFiles map. + * as with models, add multiple entries with different extensions for multiple files per + * class + */ + apiTemplateFiles.put( + "controller-api.mustache", // the template to use + ".go"); // the extension for each file to write + + /* + * Reserved words. Override this with reserved words specific to your language + */ + setReservedWordsLowerCase( + Arrays.asList( + // data type + "string", "bool", "uint", "uint8", "uint16", "uint32", "uint64", + "int", "int8", "int16", "int32", "int64", "float32", "float64", + "complex64", "complex128", "rune", "byte", "uintptr", + + "break", "default", "func", "interface", "select", + "case", "defer", "go", "map", "struct", + "chan", "else", "goto", "package", "switch", + "const", "fallthrough", "if", "range", "type", + "continue", "for", "import", "return", "var", "error", "nil") + // Added "error" as it's used so frequently that it may as well be a keyword + ); + } + + @Override + public String getDefaultTemplateDir() { + return "go-server"; + } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) { + setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME)); + } + else { + setPackageName("swagger"); + } + + /* + * Additional Properties. These values can be passed to the templates and + * are available in models, apis, and supporting files + */ + additionalProperties.put("apiVersion", apiVersion); + additionalProperties.put("serverPort", serverPort); + additionalProperties.put("apiPath", apiPath); + additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); + + modelPackage = packageName; + apiPackage = packageName; + + /* + * Supporting Files. You can write single files for the generator with the + * entire object tree available. If the input file has a suffix of `.mustache + * it will be processed by the template engine. Otherwise, it will be copied + */ + supportingFiles.add(new SupportingFile("swagger.mustache", "api", "swagger.yaml")); + supportingFiles.add(new SupportingFile("Dockerfile", "", "Dockerfile")); + supportingFiles.add(new SupportingFile("main.mustache", "", "main.go")); + supportingFiles.add(new SupportingFile("routers.mustache", apiPath, "routers.go")); + supportingFiles.add(new SupportingFile("logger.mustache", apiPath, "logger.go")); + writeOptional(outputFolder, new SupportingFile("README.mustache", apiPath, "README.md")); + } + + @Override + public String apiPackage() { + return apiPath; + } + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see io.swagger.codegen.CodegenType + */ + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator + * to select the library with the -l flag. + * + * @return the friendly name for the generator + */ + @Override + public String getName() { + return "go-server"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help + * tips, parameters here + * + * @return A string value for the help message + */ + @Override + public String getHelp() { + return "Generates a Go server library using the swagger-tools project. By default, " + + "it will also generate service classes--which you can disable with the `-Dnoservice` environment variable."; + } + + /** + * Location to write api files. You can use the apiPackage() as defined when the class is + * instantiated + */ + @Override + public String apiFileFolder() { + return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar); + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + apiPackage().replace('.', File.separatorChar); + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/handlebars/StringUtilHelper.java b/src/main/java/io/swagger/codegen/v3/generators/handlebars/StringUtilHelper.java index 675a584790..ed5af816f0 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/handlebars/StringUtilHelper.java +++ b/src/main/java/io/swagger/codegen/v3/generators/handlebars/StringUtilHelper.java @@ -20,6 +20,19 @@ public String concat(String element, Options options) { return builder.toString(); } + public String toLowerCase(String string) { + return string.toLowerCase(); + } + + public String toQuotedWord(Object object) { + String string = object.toString(); + if (string.contains("\"")) { + return string; + } else { + return "\"" + string + "\""; + } + } + public String backSlash() { return "\\"; } diff --git a/src/main/java/io/swagger/codegen/v3/generators/handlebars/java/JavaHelper.java b/src/main/java/io/swagger/codegen/v3/generators/handlebars/java/JavaHelper.java index 7c6ba8b2a7..0135f50260 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/handlebars/java/JavaHelper.java +++ b/src/main/java/io/swagger/codegen/v3/generators/handlebars/java/JavaHelper.java @@ -79,20 +79,26 @@ public CharSequence getModelImports(Map templateData, Options op boolean withXml = Boolean.valueOf(String.valueOf(templateData.get("withXml"))); boolean parcelableModel = Boolean.valueOf(String.valueOf(templateData.get("parcelableModel"))); boolean useBeanValidation = Boolean.valueOf(String.valueOf(templateData.get("useBeanValidation"))); + boolean jakarta = Boolean.valueOf(String.valueOf(templateData.get("jakarta"))); if (serializableMode) { builder.append("import java.io.Serializable;\n"); } if (jackson && withXml) { builder.append("import com.fasterxml.jackson.dataformat.xml.annotation.*;\n"); } - if (withXml) { + if (withXml && jakarta) { + builder.append("import jakarta.xml.bind.annotation.*;\n"); + } else if (withXml) { builder.append("import javax.xml.bind.annotation.*;\n"); } if (parcelableModel) { builder.append("import android.os.Parcelable;\n"); builder.append("import android.os.Parcel;\n"); } - if (useBeanValidation) { + if (useBeanValidation && jakarta) { + builder.append("import jakarta.validation.constraints.*;\n"); + builder.append("import jakarta.validation.Valid;\n"); + } else if (useBeanValidation) { builder.append("import javax.validation.constraints.*;\n"); builder.append("import javax.validation.Valid;\n"); } diff --git a/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/CapitaliseLambda.java b/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/CapitaliseLambda.java new file mode 100644 index 0000000000..8f15842a31 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/CapitaliseLambda.java @@ -0,0 +1,23 @@ +package io.swagger.codegen.v3.generators.handlebars.lambda; + +import com.github.jknack.handlebars.Lambda; +import com.github.jknack.handlebars.Template; + +import java.io.IOException; + +/** + * @author Franz See + */ +public class CapitaliseLambda extends LowercaseLambda implements Lambda { + + @Override + public Object apply(Object o, Template template) throws IOException { + String text = (String) super.apply(o, template); + if (text.length() == 1) { + text = String.valueOf(Character.toUpperCase(text.charAt(0))); + } else if (text.length() > 1) { + text = Character.toUpperCase(text.charAt(0)) + text.substring(1); + } + return text; + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/EscapeDoubleQuotesLambda.java b/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/EscapeDoubleQuotesLambda.java new file mode 100644 index 0000000000..c579d3e4e7 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/EscapeDoubleQuotesLambda.java @@ -0,0 +1,39 @@ +package io.swagger.codegen.v3.generators.handlebars.lambda; + +import com.github.jknack.handlebars.Lambda; +import com.github.jknack.handlebars.Template; +import io.swagger.codegen.v3.CodegenConfig; + +import java.io.IOException; +import java.util.regex.Matcher; + +/** + * @author Franz See + */ +public class EscapeDoubleQuotesLambda implements Lambda { + + private CodegenConfig generator = null; + + public EscapeDoubleQuotesLambda() { + + } + + public EscapeDoubleQuotesLambda generator(final CodegenConfig generator) { + this.generator = generator; + return this; + } + + @Override + public Object apply(Object o, Template template) throws IOException { + String text = template.apply(o); + if (text == null || text.length() == 0) { + return text; + } + text = text.replaceAll("\"", Matcher.quoteReplacement("\\\"")); + if (generator != null && generator.reservedWords().contains(text)) { + text = generator.escapeReservedWord(text); + } + + return text; + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/RemoveLineBreakLambda.java b/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/RemoveLineBreakLambda.java new file mode 100644 index 0000000000..7535e0d133 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/handlebars/lambda/RemoveLineBreakLambda.java @@ -0,0 +1,38 @@ +package io.swagger.codegen.v3.generators.handlebars.lambda; + +import com.github.jknack.handlebars.Lambda; +import com.github.jknack.handlebars.Template; +import io.swagger.codegen.v3.CodegenConfig; + +import java.io.IOException; + +/** + * @author Franz See + */ +public class RemoveLineBreakLambda implements Lambda { + + private CodegenConfig generator = null; + + public RemoveLineBreakLambda() { + + } + + public RemoveLineBreakLambda generator(final CodegenConfig generator) { + this.generator = generator; + return this; + } + + @Override + public Object apply(Object o, Template template) throws IOException { + String text = template.apply(o); + if (text == null || text.length() == 0) { + return text; + } + text = text.replaceAll("\\r|\\n", ""); + if (generator != null && generator.reservedWords().contains(text)) { + text = generator.escapeReservedWord(text); + } + + return text; + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/html/HtmlSchemaHandler.java b/src/main/java/io/swagger/codegen/v3/generators/html/HtmlSchemaHandler.java new file mode 100644 index 0000000000..266eecb5e0 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/html/HtmlSchemaHandler.java @@ -0,0 +1,119 @@ +package io.swagger.codegen.v3.generators.html; + +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenModelFactory; +import io.swagger.codegen.v3.CodegenModelType; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.SchemaHandler; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; +import io.swagger.util.Json; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HtmlSchemaHandler extends SchemaHandler { + + public HtmlSchemaHandler(DefaultCodegenConfig codegenConfig) { + super(codegenConfig); + } + + public void processComposedSchemas(CodegenModel codegenModel, Schema schema, Map allModels) { + if(!(schema instanceof ComposedSchema)) { + super.processComposedSchemas(codegenModel, schema, allModels); + return; + } + final ComposedSchema composedSchema = (ComposedSchema) schema; + if (composedSchema.getAllOf() == null || composedSchema.getAllOf().isEmpty()) { + super.processComposedSchemas(codegenModel, composedSchema, allModels); + return; + } + final List codegenProperties = codegenModel.vars; + if (codegenProperties == null || codegenProperties.isEmpty()) { + return; + } + for (CodegenProperty codegenProperty : codegenProperties) { + if (codegenProperty.getIsListContainer()) { + Schema schemaProperty = OpenAPIUtil.getPropertyFromAllOfSchema(codegenProperty.baseName, composedSchema.getAllOf(), this.codegenConfig.getOpenAPI()); + if (schemaProperty == null || !(schemaProperty instanceof ArraySchema)) { + continue; + } + this.processArrayItemSchema(StringUtils.EMPTY, codegenProperty, (ArraySchema) schemaProperty, allModels); + break; + } + } + } + + @Override + protected CodegenModel processComposedSchema(CodegenModel codegenModel, ComposedSchema composedSchema, Map allModels) { + List schemas = composedSchema.getOneOf(); + CodegenModel composedModel = this.createComposedModel(ONE_OF_PREFFIX + codegenModel.getName(), schemas); + if (composedModel == null) { + schemas = composedSchema.getAnyOf(); + composedModel = this.createComposedModel(ANY_OF_PREFFIX + codegenModel.getName(), schemas); + if (composedModel == null) { + return null; + } + } + this.addInterfaceModel(codegenModel, composedModel); + this.addInterfaces(schemas, composedModel, allModels); + + if (composedModel.getName().startsWith(ONE_OF_PREFFIX)) { + codegenModel.vendorExtensions.put("oneOf-model", composedModel); + } else if (composedModel.getName().startsWith(ONE_OF_PREFFIX)) { + codegenModel.vendorExtensions.put("anyOf-model", composedModel); + } + return null; + } + + @Override + protected CodegenModel processComposedSchema(String codegenModelName, CodegenProperty codegenProperty, ComposedSchema composedSchema, Map allModels) { + List schemas = composedSchema.getOneOf(); + CodegenModel composedModel = this.createComposedModel(ONE_OF_PREFFIX + codegenModelName, schemas); + if (composedModel == null) { + schemas = composedSchema.getAnyOf(); + composedModel = this.createComposedModel(ANY_OF_PREFFIX + codegenModelName, schemas); + if (composedModel == null) { + return null; + } + } + if (composedModel.getName().startsWith(ONE_OF_PREFFIX)) { + codegenProperty.vendorExtensions.put("oneOf-model", composedModel); + + } else if (composedModel.getName().startsWith(ANY_OF_PREFFIX)) { + codegenProperty.vendorExtensions.put("anyOf-model", composedModel); + } + final List modelNames = new ArrayList<>(); + for (Schema interfaceSchema : schemas) { + if (StringUtils.isNotBlank(interfaceSchema.get$ref())) { + String schemaName = OpenAPIUtil.getSimpleRef(interfaceSchema.get$ref()); + modelNames.add(codegenConfig.toModelName(schemaName)); + } + } + composedModel.vendorExtensions.put("x-model-names", modelNames); + return null; + } + + @Override + protected CodegenModel processArrayItemSchema(CodegenModel codegenModel, ArraySchema arraySchema, Map allModels) { + final Schema itemsSchema = arraySchema.getItems(); + if (itemsSchema instanceof ComposedSchema) { + this.processComposedSchema(codegenModel, (ComposedSchema) itemsSchema, allModels); + } + return null; + } + + @Override + protected CodegenModel processArrayItemSchema(String codegenModelName, CodegenProperty codegenProperty, ArraySchema arraySchema, Map allModels) { + final Schema itemsSchema = arraySchema.getItems(); + if (itemsSchema instanceof ComposedSchema) { + this.processComposedSchema(codegenModelName, codegenProperty.items, (ComposedSchema) itemsSchema, allModels); + } + return null; + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/html/StaticDocCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/html/StaticDocCodegen.java index c7ae521ce5..4dc8f5dc0d 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/html/StaticDocCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/html/StaticDocCodegen.java @@ -80,8 +80,6 @@ public String getHelp() { @Override public void processOpts() { super.processOpts(); - - embeddedTemplateDir = templateDir = getTemplateDir(); } @Override diff --git a/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtml2Codegen.java b/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtml2Codegen.java index 5ad1d35c27..af44d9a70b 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtml2Codegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtml2Codegen.java @@ -149,13 +149,6 @@ public Map postProcessOperations(Map objs) { return objs; } - @Override - public void processOpts() { - super.processOpts(); - - embeddedTemplateDir = templateDir = getTemplateDir(); - } - @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); @@ -189,6 +182,9 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation op.returnType = normalizeType(op.returnType); } + op.operationId = op.operationId.replace(" ", "_"); + op.nickname = op.operationId; + // path is an unescaped variable in the mustache template api.mustache // line 82 '<&path>' op.path = sanitizePath(op.path); diff --git a/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtmlCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtmlCodegen.java index 2a50d45985..1220d9db61 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtmlCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/html/StaticHtmlCodegen.java @@ -8,6 +8,7 @@ import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.CodegenResponse; import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.ISchemaHandler; import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; import io.swagger.codegen.v3.utils.Markdown; @@ -17,7 +18,6 @@ import io.swagger.v3.oas.models.media.MapSchema; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; -import org.apache.commons.lang3.StringUtils; import java.util.HashMap; import java.util.HashSet; @@ -25,6 +25,9 @@ import java.util.Map; public class StaticHtmlCodegen extends DefaultCodegenConfig { + + public static final String DOCUMENT_NO_OBJECTS = "docNoObjects"; + protected String invokerPackage = "io.swagger.client"; protected String groupId = "io.swagger"; protected String artifactId = "swagger-client"; @@ -65,6 +68,17 @@ public StaticHtmlCodegen() { importMapping = new HashMap(); } + @Override + public void processOpts() { + super.processOpts(); + if (additionalProperties.get(DOCUMENT_NO_OBJECTS) != null) { + final String value = additionalProperties.get(DOCUMENT_NO_OBJECTS).toString(); + additionalProperties.put(DOCUMENT_NO_OBJECTS, Boolean.parseBoolean(value)); + } else { + additionalProperties.put(DOCUMENT_NO_OBJECTS, Boolean.FALSE); + } + } + /** * Convert Markdown (CommonMark) to HTML. This class also disables normal HTML * escaping in the Mustache engine (see processCompiler(Compiler) above.) @@ -131,14 +145,6 @@ public Map postProcessOperations(Map objs) { return objs; } - @Override - public void processOpts() { - super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - } - @Override public String escapeQuotationMark(String input) { // just return the original string @@ -155,7 +161,7 @@ public String escapeUnsafeCharacters(String input) { /** * Convert Markdown text to HTML - * + * * @param input * text in Markdown; may be null. * @return the text, converted to Markdown. For null input, "" is returned. @@ -201,4 +207,8 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert property.unescapedDescription = toHtml(property.unescapedDescription); } + @Override + public ISchemaHandler getSchemaHandler() { + return new HtmlSchemaHandler(this); + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegen.java index 782459fd71..07aa3cf3f7 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegen.java @@ -1,5 +1,10 @@ package io.swagger.codegen.v3.generators.java; +import static io.swagger.codegen.v3.CodegenConstants.HAS_ENUMS_EXT_NAME; +import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.generators.features.NotNullAnnotationFeatures.NOT_NULL_JACKSON_ANNOTATION; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + import com.github.jknack.handlebars.Handlebars; import io.swagger.codegen.v3.CliOption; import io.swagger.codegen.v3.CodegenArgument; @@ -8,25 +13,24 @@ import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.CodegenParameter; import io.swagger.codegen.v3.CodegenProperty; -import io.swagger.codegen.v3.generators.handlebars.java.JavaHelper; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.features.NotNullAnnotationFeatures; +import io.swagger.codegen.v3.generators.handlebars.java.JavaHelper; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.IntegerSchema; import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.MediaType; import io.swagger.v3.oas.models.media.NumberSchema; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.parser.util.SchemaTypeUtil; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.util.Arrays; import java.util.HashMap; @@ -35,11 +39,13 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.regex.Pattern; - -import static io.swagger.codegen.v3.CodegenConstants.HAS_ENUMS_EXT_NAME; -import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; -import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class AbstractJavaCodegen extends DefaultCodegenConfig { private static Logger LOGGER = LoggerFactory.getLogger(AbstractJavaCodegen.class); @@ -47,11 +53,19 @@ public abstract class AbstractJavaCodegen extends DefaultCodegenConfig { public static final String DEFAULT_LIBRARY = ""; public static final String DATE_LIBRARY = "dateLibrary"; public static final String JAVA8_MODE = "java8"; + public static final String JAVA11_MODE = "java11"; public static final String WITH_XML = "withXml"; public static final String SUPPORT_JAVA6 = "supportJava6"; + public static final String ERROR_ON_UNKNOWN_ENUM = "errorOnUnknownEnum"; + public static final String CHECK_DUPLICATED_MODEL_NAME = "checkDuplicatedModelName"; + + public static final String WIREMOCK_OPTION = "wiremock"; + + public static final String JAKARTA = "jakarta"; protected String dateLibrary = "threetenbp"; protected boolean java8Mode = false; + protected boolean java11Mode = false; protected boolean withXml = false; protected String invokerPackage = "io.swagger"; protected String groupId = "io.swagger"; @@ -80,6 +94,8 @@ public abstract class AbstractJavaCodegen extends DefaultCodegenConfig { protected String apiDocPath = "docs/"; protected String modelDocPath = "docs/"; protected boolean supportJava6= false; + protected boolean jakarta = false; + private NotNullAnnotationFeatures notNullOption; public AbstractJavaCodegen() { super(); @@ -149,10 +165,13 @@ public AbstractJavaCodegen() { cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC)); cliOptions.add(CliOption.newBoolean(WITH_XML, "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)")); cliOptions.add(CliOption.newBoolean(CodegenConstants.USE_OAS2, CodegenConstants.USE_OAS2_DESC)); - + if(this instanceof NotNullAnnotationFeatures){ + cliOptions.add(CliOption.newBoolean(NOT_NULL_JACKSON_ANNOTATION, "adds @JsonInclude(JsonInclude.Include.NON_NULL) annotation to model classes")); + } CliOption dateLibrary = new CliOption(DATE_LIBRARY, "Option. Date library to use"); Map dateOptions = new HashMap(); dateOptions.put("java8", "Java 8 native JSR310 (preferred for jdk 1.8+) - note: this also sets \"" + JAVA8_MODE + "\" to true"); + dateOptions.put("java11", "Java 11 native JSR384 (preferred for jdk 11+) - note: this also sets \"" + JAVA11_MODE + "\" to true"); dateOptions.put("threetenbp", "Backport of JSR310 (preferred for jdk < 1.8)"); dateOptions.put("java8-localdatetime", "Java 8 using LocalDateTime (for legacy app only)"); dateOptions.put("joda", "Joda (for legacy app only)"); @@ -166,6 +185,26 @@ public AbstractJavaCodegen() { java8ModeOptions.put("false", "Various third party libraries as needed"); java8Mode.setEnum(java8ModeOptions); cliOptions.add(java8Mode); + + CliOption java11Mode = new CliOption(JAVA11_MODE, "Option. Use Java11 classes instead of third party equivalents"); + Map java11ModeOptions = new HashMap(); + java11ModeOptions.put("true", "Use Java 11 classes"); + java11ModeOptions.put("false", "Various third party libraries as needed"); + java11Mode.setEnum(java11ModeOptions); + cliOptions.add(java11Mode); + + cliOptions.add(CliOption.newBoolean(CHECK_DUPLICATED_MODEL_NAME, "Check if there are duplicated model names (ignoring case)")); + + cliOptions.add(CliOption.newBoolean(WIREMOCK_OPTION, "Use wiremock to generate endpoint calls to mock on generated tests.")); + + cliOptions.add(CliOption.newBoolean(JAKARTA, "Use Jakarta EE (package jakarta.*) instead of Java EE (javax.*)")); + + CliOption jeeSpec = CliOption.newBoolean(JAKARTA, "Use Jakarta EE (package jakarta.*) instead of Java EE (javax.*)"); + Map jeeSpecModeOptions = new HashMap(); + jeeSpecModeOptions.put("true", "Use Jakarta EE (package jakarta.*)"); + jeeSpecModeOptions.put("false", "Use Java EE (javax.*)"); + jeeSpec.setEnum(jeeSpecModeOptions); + cliOptions.add(jeeSpec); } @Override @@ -174,16 +213,16 @@ public void processOpts() { this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); } else if (additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) { // guess from api package - String derviedInvokerPackage = deriveInvokerPackageName((String)additionalProperties.get(CodegenConstants.API_PACKAGE)); - this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derviedInvokerPackage); + String derivedInvokerPackage = deriveInvokerPackageName((String)additionalProperties.get(CodegenConstants.API_PACKAGE)); + this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derivedInvokerPackage); this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); - LOGGER.info("Invoker Package Name, originally not set, is now dervied from api package name: " + derviedInvokerPackage); + LOGGER.info("Invoker Package Name, originally not set, is now derived from api package name: " + derivedInvokerPackage); } else if (additionalProperties.containsKey(CodegenConstants.MODEL_PACKAGE)) { // guess from model package - String derviedInvokerPackage = deriveInvokerPackageName((String)additionalProperties.get(CodegenConstants.MODEL_PACKAGE)); - this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derviedInvokerPackage); + String derivedInvokerPackage = deriveInvokerPackageName((String)additionalProperties.get(CodegenConstants.MODEL_PACKAGE)); + this.additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, derivedInvokerPackage); this.setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); - LOGGER.info("Invoker Package Name, originally not set, is now dervied from model package name: " + derviedInvokerPackage); + LOGGER.info("Invoker Package Name, originally not set, is now derived from model package name: " + derivedInvokerPackage); } else if (StringUtils.isNotEmpty(invokerPackage)) { // not set in additionalProperties, add value from CodegenConfig in order to use it in templates additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage); @@ -198,7 +237,7 @@ public void processOpts() { apiDocTemplateFiles.put("api_doc.mustache", ".md"); if (additionalProperties.containsKey(SUPPORT_JAVA6)) { - this.setSupportJava6(Boolean.valueOf(additionalProperties.get(SUPPORT_JAVA6).toString())); + this.setSupportJava6(false); // JAVA 6 not supported } additionalProperties.put(SUPPORT_JAVA6, supportJava6); @@ -327,6 +366,27 @@ public void processOpts() { this.setFullJavaUtil(Boolean.valueOf(additionalProperties.get(FULL_JAVA_UTIL).toString())); } + if (additionalProperties.containsKey(ERROR_ON_UNKNOWN_ENUM)) { + boolean errorOnUnknownEnum = Boolean.parseBoolean(additionalProperties.get(ERROR_ON_UNKNOWN_ENUM).toString()); + additionalProperties.put(ERROR_ON_UNKNOWN_ENUM, errorOnUnknownEnum); + } + + if (additionalProperties.containsKey(WIREMOCK_OPTION)) { + final boolean useWireMock = additionalProperties.get(WIREMOCK_OPTION) != null && Boolean.parseBoolean(additionalProperties.get(WIREMOCK_OPTION).toString()); + additionalProperties.put(WIREMOCK_OPTION, useWireMock); + } + + if (this instanceof NotNullAnnotationFeatures) { + notNullOption = (NotNullAnnotationFeatures)this; + if (additionalProperties.containsKey(NOT_NULL_JACKSON_ANNOTATION)) { + notNullOption.setNotNullJacksonAnnotation(convertPropertyToBoolean(NOT_NULL_JACKSON_ANNOTATION)); + writePropertyBack(NOT_NULL_JACKSON_ANNOTATION, notNullOption.isNotNullJacksonAnnotation()); + if (notNullOption.isNotNullJacksonAnnotation()) { + importMapping.put("JsonInclude", "com.fasterxml.jackson.annotation.JsonInclude"); + } + } + } + if (fullJavaUtil) { javaUtilPrefix = "java.util."; } @@ -376,12 +436,13 @@ public void processOpts() { } else { importMapping.put("Schema", "io.swagger.v3.oas.annotations.media.Schema"); } - + importMapping.put("JsonProperty", "com.fasterxml.jackson.annotation.JsonProperty"); importMapping.put("JsonSubTypes", "com.fasterxml.jackson.annotation.JsonSubTypes"); importMapping.put("JsonTypeInfo", "com.fasterxml.jackson.annotation.JsonTypeInfo"); importMapping.put("JsonCreator", "com.fasterxml.jackson.annotation.JsonCreator"); importMapping.put("JsonValue", "com.fasterxml.jackson.annotation.JsonValue"); + importMapping.put("JsonTypeId", "com.fasterxml.jackson.annotation.JsonTypeId"); importMapping.put("SerializedName", "com.google.gson.annotations.SerializedName"); importMapping.put("TypeAdapter", "com.google.gson.TypeAdapter"); importMapping.put("JsonAdapter", "com.google.gson.annotations.JsonAdapter"); @@ -394,12 +455,10 @@ public void processOpts() { // used later in recursive import in postProcessingModels importMapping.put("com.fasterxml.jackson.annotation.JsonProperty", "com.fasterxml.jackson.annotation.JsonCreator"); - if(additionalProperties.containsKey(JAVA8_MODE)) { - setJava8Mode(Boolean.parseBoolean(additionalProperties.get(JAVA8_MODE).toString())); - if ( java8Mode ) { - additionalProperties.put("java8", "true"); - } - } + setJava8Mode(Boolean.parseBoolean(String.valueOf(additionalProperties.get(JAVA8_MODE)))); + additionalProperties.put(JAVA8_MODE, java8Mode); + setJava11Mode(Boolean.parseBoolean(String.valueOf(additionalProperties.get(JAVA11_MODE)))); + additionalProperties.put(JAVA11_MODE, java11Mode); if(additionalProperties.containsKey(WITH_XML)) { setWithXml(Boolean.parseBoolean(additionalProperties.get(WITH_XML).toString())); @@ -410,6 +469,8 @@ public void processOpts() { if (additionalProperties.containsKey(DATE_LIBRARY)) { setDateLibrary(additionalProperties.get("dateLibrary").toString()); + } else if (java8Mode) { + setDateLibrary("java8"); } if ("threetenbp".equals(dateLibrary)) { @@ -426,7 +487,7 @@ public void processOpts() { importMapping.put("LocalDate", "org.joda.time.LocalDate"); importMapping.put("DateTime", "org.joda.time.DateTime"); } else if (dateLibrary.startsWith("java8")) { - additionalProperties.put("java8", "true"); + additionalProperties.put("java8", true); additionalProperties.put("jsr310", "true"); typeMapping.put("date", "LocalDate"); importMapping.put("LocalDate", "java.time.LocalDate"); @@ -438,7 +499,12 @@ public void processOpts() { importMapping.put("OffsetDateTime", "java.time.OffsetDateTime"); } } else if (dateLibrary.equals("legacy")) { - additionalProperties.put("legacyDates", "true"); + additionalProperties.put("legacyDates", true); + } + + if (additionalProperties.containsKey(JAKARTA)) { + setJakarta(Boolean.parseBoolean(String.valueOf(additionalProperties.get(JAKARTA)))); + additionalProperties.put(JAKARTA, jakarta); } } @@ -462,6 +528,15 @@ private void sanitizeConfig() { } } + protected String escapeUnderscore(String name) { + // Java 8 discourages naming things _, but Java 9 does not allow it. + if("_".equals(name)) { + return "_u"; + } else { + return name; + } + } + @Override public String escapeReservedWord(String name) { if(this.reservedWordsMappings().containsKey(name)) { @@ -532,11 +607,9 @@ public String toVarName(String name) { return "propertyClass"; } - if("_".equals(name)) { - name = "_u"; - } + name = escapeUnderscore(name); - // if it's all uppper case, do nothing + // if it's all upper case, do nothing if (name.matches("^[A-Z_]*$")) { return name; } @@ -598,10 +671,10 @@ public String toParamName(String name) { public String toModelName(final String name) { // We need to check if import-mapping has a different model for this class, so we use it // instead of the auto-generated one. - if (importMapping.containsKey(name)) { + + if (!getIgnoreImportMapping() && importMapping.containsKey(name)) { return importMapping.get(name); } - final String sanitizedName = sanitizeName(name); String nameWithPrefixSuffix = sanitizedName; @@ -753,6 +826,8 @@ public String toDefaultValue(Schema schema) { return String.format("%sf", schema.getDefault().toString()); } else if (schema.getDefault() != null && SchemaTypeUtil.DOUBLE_FORMAT.equals(schema.getFormat())) { return String.format("%sd", schema.getDefault().toString()); + } else { + return String.format("new BigDecimal(%s)", schema.getDefault().toString()); } } } else if (schema instanceof StringSchema) { @@ -910,9 +985,25 @@ public CodegenModel fromModel(String name, Schema schema, Map al final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel, allSchemas); codegenModel = AbstractJavaCodegen.reconcileInlineEnums(codegenModel, parentCodegenModel); } + if (this instanceof NotNullAnnotationFeatures) { + if (this instanceof NotNullAnnotationFeatures) { + notNullOption = (NotNullAnnotationFeatures)this; + if (additionalProperties.containsKey(NOT_NULL_JACKSON_ANNOTATION)) { + if (notNullOption.isNotNullJacksonAnnotation()) { + codegenModel.imports.add("JsonInclude"); + } + } + } + } return codegenModel; } + @Override + protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) { + super.addAdditionPropertiesToCodeGenModel(codegenModel, schema); + addVars(codegenModel, schema.getProperties(), schema.getRequired()); + } + @Override public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { if(serializeBigDecimalAsString) { @@ -944,6 +1035,45 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert model.imports.add("Schema"); } } + if (model.discriminator != null && model.discriminator.getPropertyName().equals(property.baseName)) { + property.vendorExtensions.put("x-is-discriminator-property", true); + if (additionalProperties.containsKey("jackson")) { + model.imports.add("JsonTypeId"); + } + } + } + + @Override + protected void fixUpParentAndInterfaces(CodegenModel codegenModel, Map allModels) { + super.fixUpParentAndInterfaces(codegenModel, allModels); + if (codegenModel.vars == null || codegenModel.vars.isEmpty() || codegenModel.parentModel == null) { + return; + } + + for (CodegenProperty codegenProperty : codegenModel.vars) { + CodegenModel parentModel = codegenModel.parentModel; + + while (parentModel != null) { + if (parentModel.vars == null || parentModel.vars.isEmpty()) { + parentModel = parentModel.parentModel; + continue; + } + boolean hasConflict = parentModel.vars.stream() + .anyMatch(parentProperty -> + (parentProperty.name.equals(codegenProperty.name) || + parentProperty.getGetter().equals(codegenProperty.getGetter()) || + parentProperty.getSetter().equals(codegenProperty.getSetter()) && + !parentProperty.datatype.equals(codegenProperty.datatype))); + if (hasConflict) { + codegenProperty.name = toVarName(codegenModel.name + "_" + codegenProperty.name); + codegenProperty.nameInCamelCase = camelize(codegenProperty.name, false); + codegenProperty.getter = toGetter(codegenProperty.name); + codegenProperty.setter = toSetter(codegenProperty.name); + break; + } + parentModel = parentModel.parentModel; + } + } } @Override @@ -992,6 +1122,11 @@ public void preprocessOpenAPI(OpenAPI openAPI) { if (openAPI == null || openAPI.getPaths() == null){ return; } + boolean checkDuplicatedModelName = Boolean.parseBoolean(additionalProperties.get(CHECK_DUPLICATED_MODEL_NAME) != null ? additionalProperties.get(CHECK_DUPLICATED_MODEL_NAME).toString() : ""); + if (checkDuplicatedModelName) { + this.checkDuplicatedModelNameIgnoringCase(openAPI); + } + for (String pathname : openAPI.getPaths().keySet()) { PathItem pathItem = openAPI.getPaths().get(pathname); @@ -1050,15 +1185,103 @@ private static String getAccept(Operation operation) { protected boolean needToImport(String type) { return super.needToImport(type) && type.indexOf(".") < 0; } -/* - @Override - public String findCommonPrefixOfVars(List vars) { - String prefix = StringUtils.getCommonPrefix(vars.toArray(new String[vars.size()])); - // exclude trailing characters that should be part of a valid variable - // e.g. ["status-on", "status-off"] => "status-" (not "status-o") - return prefix.replaceAll("[a-zA-Z0-9]+\\z", ""); + + protected void checkDuplicatedModelNameIgnoringCase(OpenAPI openAPI) { + final Map schemas = openAPI.getComponents().getSchemas(); + final Map> schemasRepeated = new HashMap<>(); + + for (String schemaKey : schemas.keySet()) { + final Schema schema = schemas.get(schemaKey); + final String lowerKeyDefinition = schemaKey.toLowerCase(); + + if (schemasRepeated.containsKey(lowerKeyDefinition)) { + Map modelMap = schemasRepeated.get(lowerKeyDefinition); + if (modelMap == null) { + modelMap = new HashMap<>(); + schemasRepeated.put(lowerKeyDefinition, modelMap); + } + modelMap.put(schemaKey, schema); + } else { + schemasRepeated.put(lowerKeyDefinition, null); + } + } + for (String lowerKeyDefinition : schemasRepeated.keySet()) { + final Map modelMap = schemasRepeated.get(lowerKeyDefinition); + if (modelMap == null) { + continue; + } + int index = 1; + for (String name : modelMap.keySet()) { + final Schema schema = modelMap.get(name); + final String newModelName = name + index; + schemas.put(newModelName, schema); + replaceDuplicatedInPaths(openAPI.getPaths(), name, newModelName); + replaceDuplicatedInModelProperties(schemas, name, newModelName); + schemas.remove(name); + index++; + } + } + } + + protected void replaceDuplicatedInPaths(Paths paths, String modelName, String newModelName) { + if (paths == null || paths.isEmpty()) { + return; + } + paths.values().stream() + .flatMap(pathItem -> pathItem.readOperations().stream()) + .filter(operation -> { + final RequestBody requestBody = operation.getRequestBody(); + if (requestBody == null || requestBody.getContent() == null || requestBody.getContent().isEmpty()) { + return false; + } + final Optional mediaTypeOptional = requestBody.getContent().values().stream().findAny(); + if (!mediaTypeOptional.isPresent()) { + return false; + } + final MediaType mediaType = mediaTypeOptional.get(); + final Schema schema = mediaType.getSchema(); + if (schema.get$ref() != null) { + return true; + } + return false; + }) + .forEach(operation -> { + Schema schema = this.getSchemaFromBody(operation.getRequestBody()); + schema.set$ref(schema.get$ref().replace(modelName, newModelName)); + }); + paths.values().stream() + .flatMap(path -> path.readOperations().stream()) + .flatMap(operation -> operation.getResponses().values().stream()) + .filter(response -> { + if (response.getContent() == null || response.getContent().isEmpty()) { + return false; + } + final Optional mediaTypeOptional = response.getContent().values().stream().findFirst(); + if (!mediaTypeOptional.isPresent()) { + return false; + } + final MediaType mediaType = mediaTypeOptional.get(); + final Schema schema = mediaType.getSchema(); + if (schema.get$ref() != null) { + return true; + } + return false; + }).forEach(response -> { + final Optional mediaTypeOptional = response.getContent().values().stream().findFirst(); + final Schema schema = mediaTypeOptional.get().getSchema(); + schema.set$ref(schema.get$ref().replace(modelName, newModelName)); + }); + } + + protected void replaceDuplicatedInModelProperties(Map definitions, String modelName, String newModelName) { + definitions.values().stream() + .flatMap(model -> model.getProperties().values().stream()) + .filter(property -> ((Schema) property).get$ref() != null) + .forEach(property -> { + final Schema schema = (Schema) property; + schema.set$ref(schema.get$ref().replace(modelName, newModelName)); + }); } -*/ @Override public String toEnumName(CodegenProperty property) { @@ -1077,8 +1300,7 @@ public String toEnumVarName(String value, String datatype) { } // number - if ("Integer".equals(datatype) || "Long".equals(datatype) || - "Float".equals(datatype) || "Double".equals(datatype)) { + if ("Integer".equals(datatype) || "Long".equals(datatype) || "Float".equals(datatype) || "Double".equals(datatype) || "BigDecimal".equals(datatype)) { String varName = "NUMBER_" + value; varName = varName.replaceAll("-", "MINUS_"); varName = varName.replaceAll("\\+", "PLUS_"); @@ -1091,13 +1313,16 @@ public String toEnumVarName(String value, String datatype) { if (var.matches("\\d.*")) { return "_" + var; } else { - return var; + return escapeUnderscore(var).toUpperCase(); } } @Override public String toEnumValue(String value, String datatype) { - if ("Integer".equals(datatype) || "Double".equals(datatype)) { + if (value == null) { + return null; + } + if ("Integer".equals(datatype) || "Double".equals(datatype) || "Boolean".equals(datatype)) { return value; } else if ("Long".equals(datatype)) { // add l to number, e.g. 2048 => 2048l @@ -1105,6 +1330,8 @@ public String toEnumValue(String value, String datatype) { } else if ("Float".equals(datatype)) { // add f to number, e.g. 3.14 => 3.14f return value + "f"; + } else if ("BigDecimal".equals(datatype)) { + return "new BigDecimal(" + escapeText(value) + ")"; } else { return "\"" + escapeText(value) + "\""; } @@ -1131,16 +1358,17 @@ public String sanitizeVarName(String name) { .replaceAll("\\(", "_") .replaceAll("\\)", StringUtils.EMPTY) .replaceAll("\\.", "_") + .replaceAll("@", "_at_") .replaceAll("-", "_") .replaceAll(" ", "_"); // remove everything else other than word, number and _ // $php_variable => php_variable if (allowUnicodeIdentifiers) { //could be converted to a single line with ?: operator - name = Pattern.compile("\\W-[\\$]", Pattern.UNICODE_CHARACTER_CLASS).matcher(name).replaceAll(StringUtils.EMPTY); + name = Pattern.compile("[\\W&&[^$]]", Pattern.UNICODE_CHARACTER_CLASS).matcher(name).replaceAll(StringUtils.EMPTY); } else { - name = name.replaceAll("\\W-[\\$]", StringUtils.EMPTY); + name = name.replaceAll("[\\W&&[^$]]", StringUtils.EMPTY); } return name; } @@ -1174,7 +1402,12 @@ private static CodegenModel reconcileInlineEnums(CodegenModel codegenModel, Code while (iterator.hasNext()) { CodegenProperty codegenProperty = iterator.next(); isEnum = getBooleanValue(codegenProperty, IS_ENUM_EXT_NAME); - if (isEnum && codegenProperty.equals(parentModelCodegenPropery)) { + // we don't check for the full set of properties as they could be overridden + // e.g. in the child; if we used codegenProperty.equals, the result in this + // case would be `false` resulting on 2 different enums created on parent and + // child classes, used in same method. This means that the child class will use + // the enum defined in the parent, loosing any overridden property + if (isEnum && isSameEnum(codegenProperty, parentModelCodegenPropery)) { // We found an enum in the child class that is // a duplicate of the one in the parent, so remove it. iterator.remove(); @@ -1191,11 +1424,48 @@ private static CodegenModel reconcileInlineEnums(CodegenModel codegenModel, Code count += 1; codegenProperty.getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, (count < numVars) ? true : false); } + + if (!codegenProperties.isEmpty()) { + codegenModel.getVendorExtensions().put(CodegenConstants.HAS_VARS_EXT_NAME, true); + codegenModel.getVendorExtensions().put(CodegenConstants.HAS_ENUMS_EXT_NAME, false); + } else { + codegenModel.emptyVars = true; + codegenModel.getVendorExtensions().put(CodegenConstants.HAS_VARS_EXT_NAME, false); + codegenModel.getVendorExtensions().put(CodegenConstants.HAS_ENUMS_EXT_NAME, false); + } + + codegenModel.vars = codegenProperties; } return codegenModel; + + } + protected static boolean isSameEnum(CodegenProperty actual, CodegenProperty other) { + if (actual == null && other == null) { + return true; + } + if ((actual.name == null) ? (other.name != null) : !actual.name.equals(other.name)) { + return false; + } + if ((actual.baseName == null) ? (other.baseName != null) : !actual.baseName.equals(other.baseName)) { + return false; + } + if ((actual.datatype == null) ? (other.datatype != null) : !actual.datatype.equals(other.datatype)) { + return false; + } + if ((actual.datatypeWithEnum == null) ? (other.datatypeWithEnum != null) : !actual.datatypeWithEnum.equals(other.datatypeWithEnum)) { + return false; + } + if ((actual.baseType == null) ? (other.baseType != null) : !actual.baseType.equals(other.baseType)) { + return false; + } + if (!Objects.equals(actual.enumName, other.enumName)) { + return false; + } + return true; + } private static String sanitizePackageName(String packageName) { packageName = packageName.trim(); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_"); @@ -1306,6 +1576,14 @@ public void setJava8Mode(boolean enabled) { this.java8Mode = enabled; } + public void setJava11Mode(boolean java11Mode) { + this.java11Mode = java11Mode; + } + + public void setJakarta(boolean jakarta) { + this.jakarta = jakarta; + } + @Override public String escapeQuotationMark(String input) { // remove " to avoid code injection @@ -1339,7 +1617,7 @@ private String deriveInvokerPackageName(String input) { public void setSupportJava6(boolean value) { this.supportJava6 = value; } - + public String toRegularExpression(String pattern) { return escapeText(pattern); } @@ -1395,7 +1673,12 @@ public void setLanguageArguments(List languageArguments) { .value(Boolean.FALSE.toString())); } } - + super.setLanguageArguments(languageArguments); } + + @Override + public boolean checkAliasModel() { + return true; + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaJAXRSServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaJAXRSServerCodegen.java index 2b623f2c0e..5db5d36182 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaJAXRSServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/AbstractJavaJAXRSServerCodegen.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.io.File; import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; @@ -75,6 +76,10 @@ public CodegenType getTag() { public void processOpts() { super.processOpts(); + if (java11Mode) { + additionalProperties.put(JAKARTA, jakarta = true); + } + if (additionalProperties.containsKey(CodegenConstants.IMPL_FOLDER)) { implFolder = (String) additionalProperties.get(CodegenConstants.IMPL_FOLDER); } @@ -92,11 +97,12 @@ public void processOpts() { @Override public void preprocessOpenAPI(OpenAPI openAPI) { //this.openAPIUtil = new OpenAPIUtil(openAPI); + this.openAPI = openAPI; if (!this.additionalProperties.containsKey("serverPort")) { final URL urlInfo = URLPathUtil.getServerURL(openAPI); String port = "8080"; // Default value for a JEE Server - if ( urlInfo != null && urlInfo.getPort() != 0) { - port = String.valueOf(urlInfo.getPort()); + if ( urlInfo != null && urlInfo.getPort() > 0) { + port = String.valueOf(urlInfo.getPort()); } this.additionalProperties.put("serverPort", port); } @@ -223,11 +229,11 @@ public String apiFilename(String templateName, String tag) { String result = super.apiFilename(templateName, tag); if ( templateName.endsWith("Impl.mustache") ) { - int ix = result.lastIndexOf('/'); + int ix = result.lastIndexOf(File.separatorChar); result = result.substring(0, ix) + "/impl" + result.substring(ix, result.length() - 5) + "ServiceImpl.java"; result = result.replace(apiFileFolder(), implFileFolder(implFolder)); } else if ( templateName.endsWith("Factory.mustache") ) { - int ix = result.lastIndexOf('/'); + int ix = result.lastIndexOf(File.separatorChar); result = result.substring(0, ix) + "/factories" + result.substring(ix, result.length() - 5) + "ServiceFactory.java"; result = result.replace(apiFileFolder(), implFileFolder(implFolder)); } else if ( templateName.endsWith("Service.mustache") ) { @@ -245,5 +251,8 @@ public void setUseBeanValidation(boolean useBeanValidation) { this.useBeanValidation = useBeanValidation; } - + @Override + public String getArgumentsLocation() { + return "/arguments/server.yaml"; + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegen.java index a82fa3f1eb..1484e082bb 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegen.java @@ -67,10 +67,6 @@ public JavaCXFClientCodegen() { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - // clear model and api doc template as this codegen // does not support auto-generated markdown doc at the moment // TODO: add doc templates diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFServerCodegen.java index f839304190..cba90a9ff2 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaCXFServerCodegen.java @@ -99,10 +99,6 @@ public JavaCXFServerCodegen() { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - apiTemplateFiles.put("apiServiceImpl.mustache", ".java"); // clear model and api doc template as this codegen @@ -194,11 +190,6 @@ public void processOpts() { } } - @Override - public String getArgumentsLocation() { - return ""; - } - @Override public String getName() { return "jaxrs-cxf"; diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaClientCodegen.java index a9de566fa2..fbb1481470 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaClientCodegen.java @@ -10,7 +10,9 @@ import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.features.BeanValidationFeatures; import io.swagger.codegen.v3.generators.features.GzipFeatures; +import io.swagger.codegen.v3.generators.features.NotNullAnnotationFeatures; import io.swagger.codegen.v3.generators.features.PerformBeanValidationFeatures; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -31,13 +33,14 @@ import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; import static java.util.Collections.sort; -public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, PerformBeanValidationFeatures, GzipFeatures { +public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, PerformBeanValidationFeatures, GzipFeatures, NotNullAnnotationFeatures { static final String MEDIA_TYPE = "mediaType"; private static final Logger LOGGER = LoggerFactory.getLogger(JavaClientCodegen.class); public static final String USE_RX_JAVA = "useRxJava"; public static final String USE_RX_JAVA2 = "useRxJava2"; + public static final String USE_RX_JAVA3 = "useRxJava3"; public static final String DO_NOT_USE_RX = "doNotUseRx"; public static final String USE_PLAY_WS = "usePlayWS"; public static final String PLAY_VERSION = "playVersion"; @@ -53,6 +56,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida protected String gradleWrapperPackage = "gradle.wrapper"; protected boolean useRxJava = false; protected boolean useRxJava2 = false; + protected boolean useRxJava3 = false; protected boolean doNotUseRx = true; // backwards compatibility for swagger configs that specify neither rx1 nor rx2 (mustache does not allow for boolean operators so we need this extra field) protected boolean usePlayWS = false; protected String playVersion = PLAY_25; @@ -61,6 +65,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen implements BeanValida protected boolean performBeanValidation = false; protected boolean useGzipFeature = false; protected boolean useRuntimeException = false; + private boolean notNullJacksonAnnotation = false; public JavaClientCodegen() { @@ -73,25 +78,25 @@ public JavaClientCodegen() { cliOptions.add(CliOption.newBoolean(USE_RX_JAVA, "Whether to use the RxJava adapter with the retrofit2 library.")); cliOptions.add(CliOption.newBoolean(USE_RX_JAVA2, "Whether to use the RxJava2 adapter with the retrofit2 library.")); + cliOptions.add(CliOption.newBoolean(USE_RX_JAVA3, "Whether to use the RxJava3 adapter with the retrofit2 library.")); cliOptions.add(CliOption.newBoolean(PARCELABLE_MODEL, "Whether to generate models for Android that implement Parcelable with the okhttp-gson library.")); cliOptions.add(CliOption.newBoolean(USE_PLAY_WS, "Use Play! Async HTTP client (Play WS API)")); cliOptions.add(CliOption.newString(PLAY_VERSION, "Version of Play! Framework (possible values \"play24\", \"play25\")")); - cliOptions.add(CliOption.newBoolean(SUPPORT_JAVA6, "Whether to support Java6 with the Jersey1 library.")); cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations")); cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION, "Perform BeanValidation")); cliOptions.add(CliOption.newBoolean(USE_GZIP_FEATURE, "Send gzip-encoded requests")); cliOptions.add(CliOption.newBoolean(USE_RUNTIME_EXCEPTION, "Use RuntimeException instead of Exception")); - supportedLibraries.put("jersey1", "HTTP client: Jersey client 1.19.4. JSON processing: Jackson 2.8.9. Enable Java6 support using '-DsupportJava6=true'. Enable gzip request encoding using '-DuseGzipFeature=true'."); - supportedLibraries.put("feign", "HTTP client: OpenFeign 9.4.0. JSON processing: Jackson 2.8.9"); - supportedLibraries.put("jersey2", "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.8.9"); + supportedLibraries.put("jersey1", "HTTP client: Jersey client 1.19.4. JSON processing: Jackson 2.10.1. Enable gzip request encoding using '-DuseGzipFeature=true'."); + supportedLibraries.put("feign", "HTTP client: OpenFeign 9.4.0. JSON processing: Jackson 2.10.1"); + supportedLibraries.put("jersey2", "HTTP client: Jersey client 2.26. JSON processing: Jackson 2.10.1"); + supportedLibraries.put("jersey3", "HTTP client: Jersey client 3.0.10. JSON processing: Jackson 2.10.2"); supportedLibraries.put("okhttp-gson", "HTTP client: OkHttp 2.7.5. JSON processing: Gson 2.8.1. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'."); + supportedLibraries.put("okhttp4-gson", "HTTP client: OkHttp 4.10.0. JSON processing: Gson 2.10.1. Enable Parcelable models on Android using '-DparcelableModel=true'. Enable gzip request encoding using '-DuseGzipFeature=true'."); supportedLibraries.put(RETROFIT_1, "HTTP client: OkHttp 2.7.5. JSON processing: Gson 2.3.1 (Retrofit 1.9.0). IMPORTANT NOTE: retrofit1.x is no longer actively maintained so please upgrade to 'retrofit2' instead."); supportedLibraries.put(RETROFIT_2, "HTTP client: OkHttp 3.8.0. JSON processing: Gson 2.6.1 (Retrofit 2.3.0). Enable the RxJava adapter using '-DuseRxJava[2]=true'. (RxJava 1.x or 2.x)"); - supportedLibraries.put("resttemplate", "HTTP client: Spring RestTemplate 4.3.9-RELEASE. JSON processing: Jackson 2.8.9"); - supportedLibraries.put("resteasy", "HTTP client: Resteasy client 3.1.3.Final. JSON processing: Jackson 2.8.9"); - supportedLibraries.put("vertx", "HTTP client: VertX client 3.2.4. JSON processing: Jackson 2.8.9"); - supportedLibraries.put("google-api-client", "HTTP client: Google API client 1.23.0. JSON processing: Jackson 2.8.9"); + supportedLibraries.put("resttemplate", "HTTP client: Spring RestTemplate 4.3.9-RELEASE. JSON processing: Jackson 2.9.9"); + supportedLibraries.put("resteasy", "HTTP client: Resteasy client 3.1.3.Final. JSON processing: Jackson 2.9.9"); CliOption libraryOption = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); libraryOption.setEnum(supportedLibraries); @@ -119,21 +124,27 @@ public String getHelp() { @Override public void processOpts() { - super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - String templateVersion = getTemplateVersion(); - embeddedTemplateDir = templateDir = getTemplateDir(); + if (RETROFIT_1.equalsIgnoreCase(library)) { + dateLibrary = "joda"; + } + if ("jersey3".equalsIgnoreCase(library)) { + dateLibrary = "java8"; + additionalProperties.put(JAKARTA, true); } - if (additionalProperties.containsKey(USE_RX_JAVA) && additionalProperties.containsKey(USE_RX_JAVA2)) { - LOGGER.warn("You specified both RxJava versions 1 and 2 but they are mutually exclusive. Defaulting to v2."); - } else if (additionalProperties.containsKey(USE_RX_JAVA)) { + super.processOpts(); + + if (additionalProperties.containsKey(USE_RX_JAVA)) { this.setUseRxJava(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA).toString())); } if (additionalProperties.containsKey(USE_RX_JAVA2)) { this.setUseRxJava2(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA2).toString())); } - if (!useRxJava && !useRxJava2) { + if (additionalProperties.containsKey(USE_RX_JAVA3)) { + this.setUseRxJava3(Boolean.valueOf(additionalProperties.get(USE_RX_JAVA3).toString())); + } + + if (!useRxJava && !useRxJava2 && !useRxJava3) { additionalProperties.put(DO_NOT_USE_RX, true); } if (additionalProperties.containsKey(USE_PLAY_WS)) { @@ -175,7 +186,11 @@ public void processOpts() { //Common files writeOptional(outputFolder, new SupportingFile("pom.mustache", "", "pom.xml")); writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md")); - writeOptional(outputFolder, new SupportingFile("build.gradle.mustache", "", "build.gradle")); + if (java11Mode) { + writeOptional(outputFolder, new SupportingFile("build.gradle.java11.mustache", "", "build.gradle")); + } else { + writeOptional(outputFolder, new SupportingFile("build.gradle.mustache", "", "build.gradle")); + } writeOptional(outputFolder, new SupportingFile("build.sbt.mustache", "", "build.sbt")); writeOptional(outputFolder, new SupportingFile("settings.gradle.mustache", "", "settings.gradle")); writeOptional(outputFolder, new SupportingFile("gradle.properties.mustache", "", "gradle.properties")); @@ -186,14 +201,11 @@ public void processOpts() { supportingFiles.add(new SupportingFile("StringUtil.mustache", invokerFolder, "StringUtil.java")); } - // google-api-client doesn't use the Swagger auth, because it uses Google Credential directly (HttpRequestInitializer) - if (!"google-api-client".equals(getLibrary())) { + supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); + supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); + supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); + supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java")); - supportingFiles.add(new SupportingFile("auth/HttpBasicAuth.mustache", authFolder, "HttpBasicAuth.java")); - supportingFiles.add(new SupportingFile("auth/ApiKeyAuth.mustache", authFolder, "ApiKeyAuth.java")); - supportingFiles.add(new SupportingFile("auth/OAuth.mustache", authFolder, "OAuth.java")); - supportingFiles.add(new SupportingFile("auth/OAuthFlow.mustache", authFolder, "OAuthFlow.java")); - } supportingFiles.add(new SupportingFile( "gradlew.mustache", "", "gradlew") ); supportingFiles.add(new SupportingFile( "gradlew.bat.mustache", "", "gradlew.bat") ); supportingFiles.add(new SupportingFile( "gradle-wrapper.properties.mustache", @@ -214,7 +226,7 @@ public void processOpts() { apiDocTemplateFiles.remove("api_doc.mustache"); } - if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary() || "google-api-client".equals(getLibrary()))) { + if (!("feign".equals(getLibrary()) || "resttemplate".equals(getLibrary()) || usesAnyRetrofitLibrary())) { supportingFiles.add(new SupportingFile("apiException.mustache", invokerFolder, "ApiException.java")); supportingFiles.add(new SupportingFile("Configuration.mustache", invokerFolder, "Configuration.java")); supportingFiles.add(new SupportingFile("Pair.mustache", invokerFolder, "Pair.java")); @@ -225,7 +237,7 @@ public void processOpts() { additionalProperties.put("jackson", "true"); supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java")); supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java")); - } else if ("okhttp-gson".equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) { + } else if ("okhttp-gson".equals(getLibrary()) || "okhttp4-gson".equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) { // the "okhttp-gson" library template requires "ApiCallback.mustache" for async call supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java")); supportingFiles.add(new SupportingFile("ApiResponse.mustache", invokerFolder, "ApiResponse.java")); @@ -241,7 +253,7 @@ public void processOpts() { if ("retrofit2".equals(getLibrary()) && !usePlayWS) { supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java")); } - } else if ("jersey2".equals(getLibrary()) || "resteasy".equals(getLibrary())) { + } else if ("jersey3".equals(getLibrary()) || "jersey2".equals(getLibrary()) || "resteasy".equals(getLibrary())) { supportingFiles.add(new SupportingFile("JSON.mustache", invokerFolder, "JSON.java")); additionalProperties.put("jackson", "true"); } else if("jersey1".equals(getLibrary())) { @@ -249,18 +261,6 @@ public void processOpts() { } else if("resttemplate".equals(getLibrary())) { additionalProperties.put("jackson", "true"); supportingFiles.add(new SupportingFile("auth/Authentication.mustache", authFolder, "Authentication.java")); - } else if("vertx".equals(getLibrary())) { - typeMapping.put("file", "AsyncFile"); - importMapping.put("AsyncFile", "io.vertx.core.file.AsyncFile"); - setJava8Mode(true); - additionalProperties.put("java8", "true"); - additionalProperties.put("jackson", "true"); - - apiTemplateFiles.put("apiImpl.mustache", "Impl.java"); - apiTemplateFiles.put("rxApiImpl.mustache", ".java"); - supportingFiles.remove(new SupportingFile("manifest.mustache", projectFolder, "AndroidManifest.xml")); - } else if ("google-api-client".equals(getLibrary())) { - additionalProperties.put("jackson", "true"); } else { LOGGER.error("Unknown library option (-l/--library): " + getLibrary()); } @@ -396,16 +396,7 @@ && getBooleanValue(another, CodegenConstants.IS_PATH_PARAM_EXT_NAME)){ @Override public String apiFilename(String templateName, String tag) { - if("vertx".equals(getLibrary())) { - String suffix = apiTemplateFiles().get(templateName); - String subFolder = ""; - if (templateName.startsWith("rx")) { - subFolder = "/rxjava"; - } - return apiFileFolder() + subFolder + '/' + toApiFilename(tag) + suffix; - } else { - return super.apiFilename(templateName, tag); - } + return super.apiFilename(templateName, tag); } /** @@ -546,11 +537,12 @@ protected List> modelInheritanceSupportInGson(List allMod } } List> parentsList = new ArrayList<>(); - for (CodegenModel parentModel : byParent.keySet()) { + for (Map.Entry> parentModelEntry : byParent.entrySet()) { + CodegenModel parentModel = parentModelEntry.getKey(); List> childrenList = new ArrayList<>(); Map parent = new HashMap<>(); parent.put("classname", parentModel.classname); - List childrenModels = byParent.get(parentModel); + List childrenModels = parentModelEntry.getValue(); for (CodegenModel model : childrenModels) { Map child = new HashMap<>(); child.put("name", model.name); @@ -559,8 +551,13 @@ protected List> modelInheritanceSupportInGson(List allMod } parent.put("children", childrenList); parent.put("discriminator", parentModel.discriminator); + if(parentModel.discriminator != null && parentModel.discriminator.getMapping() != null) + { + parentModel.discriminator.getMapping().replaceAll((key, value) -> OpenAPIUtil.getSimpleRef(value)); + } parentsList.add(parent); } + return parentsList; } @@ -574,6 +571,11 @@ public void setUseRxJava2(boolean useRxJava2) { doNotUseRx = false; } + public void setUseRxJava3(boolean useRxJava3) { + this.useRxJava3 = useRxJava3; + doNotUseRx = false; + } + public void setDoNotUseRx(boolean doNotUseRx) { this.doNotUseRx = doNotUseRx; } @@ -630,4 +632,13 @@ static boolean isJsonVendorMimeType(String mime) { return mime != null && JSON_VENDOR_MIME_PATTERN.matcher(mime).matches(); } + @Override + public void setNotNullJacksonAnnotation(boolean notNullJacksonAnnotation) { + this.notNullJacksonAnnotation = notNullJacksonAnnotation; + } + + @Override + public boolean isNotNullJacksonAnnotation() { + return notNullJacksonAnnotation; + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaInflectorServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaInflectorServerCodegen.java index 8eb5cdb824..1bb5e8adc7 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaInflectorServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaInflectorServerCodegen.java @@ -73,9 +73,6 @@ public String getHelp() { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } writeOptional(outputFolder, new SupportingFile("pom.mustache", "", "pom.xml")); writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md")); writeOptional(outputFolder, new SupportingFile("web.mustache", "src/main/webapp/WEB-INF", "web.xml")); diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSCXFCDIServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSCXFCDIServerCodegen.java index 1f624d8755..3e632ba8e6 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSCXFCDIServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSCXFCDIServerCodegen.java @@ -5,8 +5,6 @@ import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.features.BeanValidationFeatures; -import org.apache.commons.lang3.StringUtils; - import java.io.File; /** @@ -45,14 +43,18 @@ public String getName() { @Override public void processOpts() { - // Set the template dir first, before super.processOpts(), otherwise it is going to - // be set to /spec location. - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } super.processOpts(); + if (additionalProperties.containsKey(JAKARTA)) { + setJakarta(convertPropertyToBoolean(JAKARTA)); + } + if (jakarta) { + importMapping.put("Valid", "jakarta.validation.Valid"); + } else { + importMapping.put("Valid", "javax.validation.Valid"); + } + // Three API templates to support CDI injection apiTemplateFiles.put("apiService.mustache", ".java"); apiTemplateFiles.put("apiServiceImpl.mustache", ".java"); @@ -84,6 +86,13 @@ public void processOpts() { @Override public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { super.postProcessModelProperty(model, property); + if (useBeanValidation) { + final boolean importValidAnnotation = property.getIsContainer() && !property.getIsPrimitiveType() && !property.getIsEnum() + || !property.getIsContainer() && !property.getIsPrimitiveType(); + if (importValidAnnotation) { + model.imports.add("Valid"); + } + } // Reinstate JsonProperty model.imports.add("JsonProperty"); @@ -92,7 +101,7 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert @Override public String getHelp() { return "[WORK IN PROGRESS: generated code depends from Swagger v2 libraries] " - + "Generates a Java JAXRS Server according to JAXRS 2.0 specification, assuming an " + + "Generates a Java JAXRS Server according to JAXRS 2.0 specification, assuming an " + "Apache CXF runtime and a Java EE runtime with CDI enabled."; } diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSSpecServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSSpecServerCodegen.java index bd5efdabe5..b87d66b0b3 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSSpecServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJAXRSSpecServerCodegen.java @@ -6,7 +6,6 @@ import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.SupportingFile; -import io.swagger.codegen.v3.generators.util.OpenAPIUtil; import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -76,14 +75,15 @@ public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - modelTemplateFiles.put("model.mustache", ".java"); apiTemplateFiles.put("api.mustache", ".java"); - apiPackage = "io.swagger.api"; - modelPackage = "io.swagger.model"; + + if (StringUtils.isEmpty(apiPackage)) { + apiPackage = "io.swagger.api"; + } + if (StringUtils.isEmpty(modelPackage)) { + modelPackage = "io.swagger.model"; + } apiTestTemplateFiles.clear(); // TODO: add api test template modelTestTemplateFiles.clear(); // TODO: add model test template @@ -104,11 +104,6 @@ public void processOpts() { } } - @Override - public String getArgumentsLocation() { - return ""; - } - @Override public String getDefaultTemplateDir() { return JAXRS_TEMPLATE_DIRECTORY_NAME + "/spec"; diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyDIServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyDIServerCodegen.java index eca57e79be..58d748bf69 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyDIServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyDIServerCodegen.java @@ -30,7 +30,7 @@ public void addTemplateFiles() { apiTestTemplateFiles.clear(); // TODO: add test template // clear model and api doc template as this codegen - // does not support auto-generated markdown doc at the moment + // does not support auto-generated markdown doc at the moment. // TODO: add doc templates modelDocTemplateFiles.remove("model_doc.mustache"); apiDocTemplateFiles.remove("api_doc.mustache"); diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyServerCodegen.java index 29d373623e..1f13d120a0 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaJerseyServerCodegen.java @@ -45,7 +45,6 @@ public JavaJerseyServerCodegen() { library.setDefault(DEFAULT_JERSEY_LIBRARY); cliOptions.add(library); - cliOptions.add(CliOption.newBoolean(SUPPORT_JAVA6, "Whether to support Java6 with the Jersey1/2 library.")); cliOptions.add(CliOption.newBoolean(USE_TAGS, "use tags for creating interface and controller classnames")); } @@ -87,10 +86,6 @@ public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - addTemplateFiles(); // use default library if unset @@ -147,11 +142,6 @@ public void addSupportingFiles() { supportingFiles.add(new SupportingFile("StringUtil.mustache", (sourceFolder + '/' + apiPackage).replace(".", "/"), "StringUtil.java")); } - @Override - public String getArgumentsLocation() { - return ""; - } - @Override public String getDefaultTemplateDir() { return JAXRS_TEMPLATE_DIRECTORY_NAME; diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyEapServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyEapServerCodegen.java index cb8f878161..25a702521e 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyEapServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyEapServerCodegen.java @@ -59,10 +59,6 @@ public String getHelp() { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - apiTemplateFiles.put("apiServiceImpl.mustache", ".java"); apiTestTemplateFiles.clear(); // TODO: add test template @@ -109,11 +105,6 @@ public void processOpts() { } - @Override - public String getArgumentsLocation() { - return ""; - } - @Override public String getDefaultTemplateDir() { return JAXRS_TEMPLATE_DIRECTORY_NAME + "/resteasy/eap"; diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyServerCodegen.java index 15748a0d5f..b95eefe073 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaResteasyServerCodegen.java @@ -51,10 +51,6 @@ public String getHelp() { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - apiTemplateFiles.put("apiService.mustache", ".java"); apiTemplateFiles.put("apiServiceImpl.mustache", ".java"); apiTestTemplateFiles.clear(); // TODO: add test template @@ -98,12 +94,6 @@ else if (dateLibrary.startsWith("java8")) { supportingFiles.add(new SupportingFile("LocalDateProvider.mustache", (sourceFolder + '/' + apiPackage).replace(".", "/"), "LocalDateProvider.java")); } } - - - @Override - public String getArgumentsLocation() { - return ""; - } @Override public String getDefaultTemplateDir() { diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/JavaVertXServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/JavaVertXServerCodegen.java new file mode 100644 index 0000000000..6c8ec792f5 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/java/JavaVertXServerCodegen.java @@ -0,0 +1,408 @@ +package io.swagger.codegen.v3.generators.java; + +import static io.swagger.codegen.v3.CodegenConstants.HAS_ENUMS_EXT_NAME; +import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +import com.github.jknack.handlebars.Lambda; +import com.google.common.collect.ImmutableMap; +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.generators.features.BeanValidationFeatures; +import io.swagger.codegen.v3.generators.features.NotNullAnnotationFeatures; +import io.swagger.codegen.v3.generators.handlebars.lambda.UppercaseLambda; +import io.swagger.codegen.v3.utils.URLPathUtil; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.PathItem.HttpMethod; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.media.Schema; +import java.io.File; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JavaVertXServerCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, NotNullAnnotationFeatures { + + private static final Logger LOGGER = LoggerFactory.getLogger(JavaVertXServerCodegen.class); + + private static final String ROOT_PACKAGE = "rootPackage"; + private static final String VERTICLE_PACKAGE = "verticlePackage"; + private static final String SPEC_LOCATION = "openapi.yaml"; + private static final String OPENAPI_EXTENSION = "x-vertx-event-bus"; + private static final String OPENAPI_EXTENSION_ADDRESS = "address"; + private static final String OPENAPI_EXTENSION_METHOD_NAME = "method"; + private static final String TITLE = "title"; + + public static final String RX_INTERFACE_OPTION = "rxInterface"; + public static final String USE_DATAOBJECT_OPTION = "useDataObject"; + public static final String MOUNT_OPERATION_FROM_OPTION = "mountOperationFrom"; + public static final String MOUNT_OPERATION_FROM_EXTENSIONS = "mountFromExtensions"; + public static final String MOUNT_OPERATION_FROM_INTERFACE = "mountFromInterface"; + public static final String SPEC_LOCATION_OPTION = "specLocation"; + + public static final String USE_FUTURE_OPTION = "useFuture"; + + protected String rootPackage = "io.swagger.server.api"; + protected String apiVerticle; + protected String apiVersion = "1.0.0-SNAPSHOT"; + + protected boolean useDataObject = false; + protected boolean mountFromExtensions = false; + protected boolean mountFromInterface = false; + protected String title = null; + protected boolean useBeanValidation = false; + protected boolean notNullJacksonAnnotation = false; + + /** + * A Java Vert.X generator. It can be configured with CLI options : + *
    + *
  • rxInterface : type Boolean if true, API interfaces are generated with RX and methods return + * Single and Comparable. default : false
  • + * + *
  • useDataObject : type Boolean if true, models objects are generated with @DataObject
  • + * + *
  • mountOperationFrom : type String, define how routes are mounted.
  • + * + *
  • specLocation : define spec location, default as {@link JavaVertXServerCodegen#SPEC_LOCATION}.
  • + * + *
  • useFuture : define use services as future, default false.
  • + *
+ */ + public JavaVertXServerCodegen() { + super(); + + // set the output folder here + outputFolder = "generated-code" + File.separator + "javaVertXServer"; + + apiPackage = rootPackage + ".service"; + apiVerticle = rootPackage + ".verticle"; + modelPackage = rootPackage + ".model"; + + additionalProperties.put(ROOT_PACKAGE, rootPackage); + additionalProperties.put(VERTICLE_PACKAGE, apiVerticle); + + groupId = "io.swagger"; + artifactId = "swagger-java-vertx-server"; + artifactVersion = apiVersion; + + cliOptions.add(CliOption.newBoolean(RX_INTERFACE_OPTION, + "When specified, API interfaces are generated with RX " + + "and methods return Single<> and Comparable.")); + cliOptions.add(CliOption.newBoolean(USE_DATAOBJECT_OPTION, + "When specified, models objects are generated with @DataObject")); + + // add option to mount with operation id ? + CliOption operationsOption = CliOption.newString(MOUNT_OPERATION_FROM_OPTION,"When specified, defines how operations are mounted. Default with @WebApiServiceGen"); + Map mountOperationFromEnum = new HashMap<>(); + mountOperationFromEnum.put(MOUNT_OPERATION_FROM_EXTENSIONS, "Mount operations from extensions with web-api-service module & @WebApiServiceGen. open api contract must define x-vertx-event-bus extension to be mounted"); + mountOperationFromEnum.put(MOUNT_OPERATION_FROM_INTERFACE, "Mount operations from interface with web-api-service module & Interfaces implementing operations. event bus address will be #{tag}.address"); + operationsOption.setEnum(mountOperationFromEnum); + operationsOption.setDefault(MOUNT_OPERATION_FROM_EXTENSIONS); + cliOptions.add(operationsOption); + + CliOption specLocation = CliOption.newString(SPEC_LOCATION_OPTION, + "When specified, define spec location. Default as " + SPEC_LOCATION); + specLocation.setDefault(SPEC_LOCATION); + cliOptions.add(specLocation); + + CliOption useFutureOption = CliOption.newBoolean(USE_FUTURE_OPTION, + "When specified, describe service as future or not. Default as false"); + useFutureOption.setDefault(Boolean.FALSE.toString()); + cliOptions.add(useFutureOption); + + cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations")); + } + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see CodegenType + */ + public CodegenType getTag() { + return CodegenType.SERVER; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator to select + * the library with the -l flag. + * + * @return the friendly name for the generator + */ + public String getName() { + return "java-vertx"; + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help tips, + * parameters here + * + * @return A string value for the help message + */ + public String getHelp() { + return "Generates a java-Vert.X Server library."; + } + + @Override + public String getDefaultTemplateDir() { + return "JavaVertXServer"; + } + + @Override + public void processOpts() { + + if (dateLibrary.equals("legacy")){ + // can't use legacy format + LOGGER.warn("Legacy date library could not be used. Replaced to java8 as default"); + setDateLibrary("java8"); + } + + super.processOpts(); + + modelTemplateFiles.clear(); + modelTemplateFiles.put("model.mustache", ".java"); + + apiTemplateFiles.clear(); + apiTemplateFiles.put("api.mustache", ".java"); + + apiTestTemplateFiles.clear(); + modelDocTemplateFiles.clear(); + apiDocTemplateFiles.clear(); + + if (additionalProperties.containsKey(USE_DATAOBJECT_OPTION)) { + this.useDataObject = (Boolean.valueOf(additionalProperties.get(USE_DATAOBJECT_OPTION).toString())); + } + + + if (additionalProperties.containsKey(MOUNT_OPERATION_FROM_OPTION)) { + if (MOUNT_OPERATION_FROM_INTERFACE.equals(additionalProperties.get(MOUNT_OPERATION_FROM_OPTION))) { + this.mountFromInterface = true; + additionalProperties.put(MOUNT_OPERATION_FROM_INTERFACE, true); + } + } + if (!this.mountFromInterface) { + this.mountFromExtensions = true; + additionalProperties.put(MOUNT_OPERATION_FROM_EXTENSIONS, true); + } + + if (!additionalProperties.containsKey(SPEC_LOCATION_OPTION)) { + additionalProperties.put(SPEC_LOCATION_OPTION, SPEC_LOCATION); + } + + supportingFiles.clear(); + supportingFiles.add(new SupportingFile("MainApiVerticle.mustache", sourceFolder + File.separator + rootPackage.replace(".", File.separator), "MainApiVerticle.java")); + + supportingFiles.add(new SupportingFile("package-info-service.mustache", sourceFolder + File.separator + apiPackage.replace(".", File.separator), "package-info.java")); + + if (this.useDataObject) { + supportingFiles.add(new SupportingFile("package-info-model.mustache", sourceFolder + File.separator + modelPackage.replace(".", File.separator), "package-info.java")); + supportingFiles.add(new SupportingFile("json-mappers.mustache", projectFolder + File.separator + "resources/META-INF/vertx", "json-mappers.properties")); + supportingFiles.add(new SupportingFile("DataObjectMapper.mustache", sourceFolder + File.separator + modelPackage.replace(".", File.separator), "DataObjectMapper.java")); + } + + writeOptional(outputFolder, new SupportingFile("pom.mustache", "", "pom.xml")); + writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md")); + + addHandlebarsLambdas(additionalProperties); + } + + @Override + public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { + super.postProcessModelProperty(model, property); + + boolean isEnum = getBooleanValue(model, IS_ENUM_EXT_NAME); + if (!Boolean.TRUE.equals(isEnum)) { + model.imports.add("JsonProperty"); + boolean hasEnums = getBooleanValue(model, HAS_ENUMS_EXT_NAME); + if (Boolean.TRUE.equals(hasEnums)) { + model.imports.add("JsonValue"); + } + } + + // not use + model.imports.remove("Schema"); + } + + @Override + public CodegenModel fromModel(String name, Schema schema, Map allSchemas) { + CodegenModel codegenModel = super.fromModel(name, schema, allSchemas); + codegenModel.imports.remove("ApiModel"); + codegenModel.imports.remove("ApiModelProperty"); + return codegenModel; + } + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + + final URL urlInfo = URLPathUtil.getServerURL(openAPI); + String port = "8080"; + if (urlInfo != null && urlInfo.getPort() > 0) { + port = String.valueOf(urlInfo.getPort()); + } + + this.additionalProperties.put("serverPort", port); + + // From the title, compute a reasonable name for the package and the API + String title = openAPI.getInfo().getTitle(); + + // Drop any API suffix + title = title.trim().replace(" ", "-"); + if (title.toUpperCase().endsWith("API")) { + title = title.substring(0, title.length() - 3); + } + + title = camelize(sanitizeName(title)); + additionalProperties.put(TITLE, title); + supportingFiles.add(new SupportingFile("apiVerticle.mustache", sourceFolder + File.separator + apiVerticle.replace(".", File.separator), title + "Verticle.java")); + + /* + * manage operation & custom serviceId because operationId field is not + * required and may be empty + */ + Paths paths = openAPI.getPaths(); + if (paths != null) { + for (Entry entry : paths.entrySet()) { + manageOperations(entry.getValue(), entry.getKey()); + } + } + this.additionalProperties.remove("gson"); + } + + public void setUseBeanValidation(boolean useBeanValidation) { + this.useBeanValidation = useBeanValidation; + } + + @Override + public void setNotNullJacksonAnnotation(boolean notNullJacksonAnnotation) { + this.notNullJacksonAnnotation = notNullJacksonAnnotation; + } + + @Override + public boolean isNotNullJacksonAnnotation() { + return notNullJacksonAnnotation; + } + + private void addHandlebarsLambdas(Map objs) { + Map lambdas = new ImmutableMap.Builder() + .put("uppercase", new UppercaseLambda()) + .build(); + + if (objs.containsKey("lambda")) { + LOGGER.warn("An property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + + "You'll likely need to use a custom template, " + + "see https://github.com/swagger-api/swagger-codegen#modifying-the-client-library-format. "); + objs.put("_lambda", lambdas); + } else { + objs.put("lambda", lambdas); + } + } + + private void manageOperations(PathItem pathItem, String pathname) { + Map operationMap = pathItem.readOperationsMap(); + if (operationMap != null) { + for (Entry entry : operationMap.entrySet()) { + String serviceId = null; + + if (this.mountFromExtensions) { + // read extension "x-vertx-event-bus" to write api service from address, not by tag + // Cases: from vertx doc + // 1. both strings or path extension null: operation extension overrides all + // 2. path extension map and operation extension string: path extension interpreted as delivery options and operation extension as address + // 3. path extension string and operation extension map: path extension interpreted as address + // 4. both maps: extension map overrides path map elements + // 5. operation extension null: path extension overrides all + Object pathExtension = getExtension(pathItem.getExtensions()); + Object operationExtension = getExtension(entry.getValue().getExtensions()); + + String address = null; + + if ((operationExtension instanceof String && pathExtension instanceof String) || pathExtension == null) { + if (operationExtension instanceof String) { + address = (String) operationExtension; + } else if (operationExtension instanceof Map) { + address = (String) ((Map) operationExtension).get(OPENAPI_EXTENSION_ADDRESS); + serviceId = (String) ((Map) operationExtension).get(OPENAPI_EXTENSION_METHOD_NAME); + } + } else if (operationExtension instanceof String && pathExtension instanceof Map) { + address = (((Map) pathExtension).containsKey(OPENAPI_EXTENSION_ADDRESS)) + ? (String) ((Map) pathExtension).get(OPENAPI_EXTENSION_ADDRESS) + : (String) operationExtension; + } else if (operationExtension instanceof Map && pathExtension instanceof String) { + address = (String) pathExtension; + serviceId = (String) ((Map) operationExtension).get(OPENAPI_EXTENSION_METHOD_NAME); + } else if (operationExtension instanceof Map && pathExtension instanceof Map) { + Map busExtension = new LinkedHashMap<>( + (Map) pathExtension); + busExtension.putAll((Map) operationExtension); + address = (String) (busExtension).get(OPENAPI_EXTENSION_ADDRESS); + serviceId = (String) (busExtension).get(OPENAPI_EXTENSION_METHOD_NAME); + } else if (operationExtension == null && pathExtension instanceof String) { + address = (String) pathExtension; + } else if (operationExtension == null && pathExtension instanceof Map) { + address = (String) ((Map) pathExtension).get(OPENAPI_EXTENSION_ADDRESS); + serviceId = (String) ((Map) pathExtension).get(OPENAPI_EXTENSION_METHOD_NAME); + } + + if (null != address) { + entry.getValue().addExtension("x-event-bus-address", address); + // codegen use tag to generate api, so we save tags & replace with event bus address + entry.getValue().setTags(Collections.singletonList(address)); + } else { + LOGGER.warn("event bus address not found on operationId {}, will not be mount", entry.getValue().getOperationId()); + } + } + + if (null == serviceId) { + serviceId = computeServiceId(pathname, entry); + } + entry.getValue().addExtension("x-serviceid", sanitizeOperationId(serviceId)); + } + } + } + + private Object getExtension(Map extensions) { + return null != extensions ? extensions.get(OPENAPI_EXTENSION) : null; + } + + /** + * @see io.vertx.ext.web.openapi.impl.OpenAPI3Utils#sanitizeOperationId + */ + private String sanitizeOperationId(String operationId) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < operationId.length(); i++) { + char c = operationId.charAt(i); + if (c == '-' || c == ' ' || c == '_') { + try { + while (c == '-' || c == ' ' || c == '_') { + i++; + c = operationId.charAt(i); + } + result.append(Character.toUpperCase(operationId.charAt(i))); + } catch (StringIndexOutOfBoundsException e) { + } + } else { + result.append(c); + } + } + return result.toString(); + } + + private String computeServiceId(String pathname, Entry entry) { + String operationId = entry.getValue().getOperationId(); + return (operationId != null) ? operationId + : entry.getKey().name() + + pathname.replaceAll("-", "_").replaceAll("/", "_").replaceAll("[{}]", ""); + } + +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/MicronautCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/MicronautCodegen.java new file mode 100644 index 0000000000..41d6d4ad40 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/java/MicronautCodegen.java @@ -0,0 +1,567 @@ +package io.swagger.codegen.v3.generators.java; + +import com.github.jknack.handlebars.Handlebars; +import com.github.jknack.handlebars.Lambda; +import com.google.common.collect.ImmutableMap; +import io.swagger.codegen.v3.*; +import io.swagger.codegen.v3.generators.features.BeanValidationFeatures; +import io.swagger.codegen.v3.generators.features.OptionalFeatures; +import io.swagger.codegen.v3.generators.handlebars.lambda.*; +import io.swagger.codegen.v3.utils.URLPathUtil; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; + +import static io.swagger.codegen.v3.CodegenConstants.HAS_ENUMS_EXT_NAME; +import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; +import static java.util.Collections.singletonList; + +/** + * @author Franz See + */ +public class MicronautCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, OptionalFeatures { + + private static Logger LOGGER = LoggerFactory.getLogger(MicronautCodegen.class); + private static final String DEFAULT_LIBRARY = "rxjava3"; + private static final String RXJAVA3_LIBRARY = "rxjava3"; + private static final String RXJAVA2_LIBRARY = "rxjava2"; + private static final String REACTOR_LIBRARY = "reactor"; + private static final String TITLE = "title"; + private static final String CONFIG_PACKAGE = "configPackage"; + private static final String BASE_PACKAGE = "basePackage"; + private static final String USE_TAGS = "useTags"; + private static final String USE_RXJAVA = "useRxJava"; + private static final String USE_RXJAVA2 = "useRxJava2"; + private static final String USE_RXJAVA3 = "useRxJava3"; + private static final String USE_REACTOR = "useReactor"; + private static final String IMPLICIT_HEADERS = "implicitHeaders"; + private static final String SKIP_SUPPORT_FILES = "skipSupportFiles"; + + private String title = "swagger-petstore"; + private String configPackage = "io.swagger.configuration"; + private String basePackage = "io.swagger"; + private boolean useTags = false; + private boolean useBeanValidation = true; + private boolean implicitHeaders = false; + private boolean useOptional = false; + + @SuppressWarnings("unused") + public MicronautCodegen() { + super(); + init(); + } + + private void init() { + outputFolder = "generated-code/javaMicronaut"; + apiPackage = "io.swagger.api"; + modelPackage = "io.swagger.model"; + invokerPackage = "io.swagger.api"; + artifactId = "swagger-micronaut"; + + additionalProperties.put(CONFIG_PACKAGE, configPackage); + additionalProperties.put(BASE_PACKAGE, basePackage); + + // micronaut uses the jackson lib + additionalProperties.put("jackson", "true"); + + cliOptions.add(new CliOption(TITLE, "server title name or client service name")); + cliOptions.add(new CliOption(CONFIG_PACKAGE, "configuration package for generated code")); + cliOptions.add(new CliOption(BASE_PACKAGE, "base package (invokerPackage) for generated code")); + cliOptions.add(new CliOption(SKIP_SUPPORT_FILES, "skip support files such as pom.xml, mvnw, etc from code generation.")); + cliOptions.add(CliOption.newBoolean(USE_TAGS, "use tags for creating interface and controller classnames")); + + CliOption useBeanValidation = CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations"); + useBeanValidation.setDefault("true"); + cliOptions.add(useBeanValidation); + + cliOptions.add(CliOption.newBoolean(IMPLICIT_HEADERS, "Use of @ApiImplicitParams for headers.")); + cliOptions.add(CliOption.newBoolean(USE_OPTIONAL, + "Use Optional container for optional parameters")); + + supportedLibraries.put(DEFAULT_LIBRARY, "Java Micronaut Server application with RxJava3 reactive streams implementation"); + supportedLibraries.put(USE_RXJAVA2, "Java Micronaut Server application with RxJava2 reactive streams implementation"); + supportedLibraries.put(REACTOR_LIBRARY, "Java Micronaut Server application with Project Reactor reactive streams implementation"); + setLibrary(DEFAULT_LIBRARY); + + CliOption library = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); + library.setEnum(supportedLibraries); + library.setDefault(DEFAULT_LIBRARY); + cliOptions.add(library); + } + + @Override + public CodegenType getTag() { + return CodegenType.SERVER; + } + + @Override + public String getName() { + return "micronaut"; + } + + @Override + public String getHelp() { + return "Generates a Java Micronaut Server application."; + } + + @Override + public void processOpts() { + setUseOas2(false); + additionalProperties.put(CodegenConstants.USE_OAS2, false); + + if (additionalProperties.containsKey("httpMethod")) { + String httpMethod = (String) additionalProperties.get("httpMethod"); + String httpMethodNormalCase = Character.toUpperCase(httpMethod.charAt(0)) + httpMethod.substring(1); + additionalProperties.put("httpMethodNormalCase", httpMethodNormalCase); + } + + + // set invokerPackage as basePackage + if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { + this.setBasePackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); + additionalProperties.put(BASE_PACKAGE, basePackage); + LOGGER.info("Set base package to invoker package (" + basePackage + ")"); + } + + super.processOpts(); + + // clear model and api doc template as this codegen + // does not support auto-generated markdown doc at the moment + //TODO: add doc templates + modelDocTemplateFiles.remove("model_doc.mustache"); + apiDocTemplateFiles.remove("api_doc.mustache"); + + if (additionalProperties.containsKey(TITLE)) { + this.setTitle((String) additionalProperties.get(TITLE)); + } + + if (additionalProperties.containsKey(CONFIG_PACKAGE)) { + this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE)); + } + + if (additionalProperties.containsKey(BASE_PACKAGE)) { + this.setBasePackage((String) additionalProperties.get(BASE_PACKAGE)); + } + + if (additionalProperties.get(USE_TAGS) != null) { + this.setUseTags(Boolean.parseBoolean(additionalProperties.get(USE_TAGS).toString())); + } + + if (additionalProperties.containsKey(USE_BEANVALIDATION)) { + this.setUseBeanValidation(convertPropertyToBoolean(USE_BEANVALIDATION)); + } + + if (additionalProperties.containsKey(USE_OPTIONAL)) { + this.setUseOptional(convertPropertyToBoolean(USE_OPTIONAL)); + } + + boolean skipSupportFiles = false; + if (additionalProperties.get(SKIP_SUPPORT_FILES) != null) { + skipSupportFiles = Boolean.parseBoolean(additionalProperties.get(SKIP_SUPPORT_FILES).toString()); + } + + writePropertyBack(USE_BEANVALIDATION, useBeanValidation); + + if (additionalProperties.get(IMPLICIT_HEADERS) != null) { + this.setImplicitHeaders(Boolean.parseBoolean(additionalProperties.get(IMPLICIT_HEADERS).toString())); + } + + writePropertyBack(USE_OPTIONAL, useOptional); + if (isRxJava2Library()) { + additionalProperties.put(USE_RXJAVA2, true); + } else { + additionalProperties.put(USE_RXJAVA3, isRxJava3Library()); + } + additionalProperties.put(USE_REACTOR, isReactorLibrary()); + + if (!skipSupportFiles) { + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("mvnw", "", "mvnw")); + supportingFiles.add(new SupportingFile("mvnw.cmd", "", "mvnw.cmd")); + supportingFiles.add(new SupportingFile("unsupportedOperationExceptionHandler.mustache", + (sourceFolder + File.separator + configPackage).replace(".", File.separator), "UnsupportedOperationExceptionHandler.java")); + supportingFiles.add(new SupportingFile("mainApplication.mustache", (sourceFolder + File.separator + basePackage).replace(".", File.separator), "MainApplication.java")); + apiTemplateFiles.put("apiController.mustache", "Controller.java"); + } + addHandlebarsLambdas(additionalProperties); + } + + private void addHandlebarsLambdas(Map objs) { + Map lambdas = new ImmutableMap.Builder() + .put("lowercase", new LowercaseLambda().generator(this)) + .put("uppercase", new UppercaseLambda()) + .put("titlecase", new TitlecaseLambda()) + .put("camelcase", new CamelCaseLambda().generator(this)) + .put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true)) + .put("indented", new IndentedLambda()) + .put("indented_8", new IndentedLambda(8, " ")) + .put("indented_12", new IndentedLambda(12, " ")) + .put("indented_16", new IndentedLambda(16, " ")) + .put("capitalise", new CapitaliseLambda()) + .put("escapeDoubleQuote", new EscapeDoubleQuotesLambda()) + .put("removeLineBreak", new RemoveLineBreakLambda()) + .build(); + + if (objs.containsKey("lambda")) { + LOGGER.warn("An property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + + "You'll likely need to use a custom template, " + + "see https://github.com/swagger-api/swagger-codegen#modifying-the-client-library-format. "); + objs.put("_lambda", lambdas); + } else { + objs.put("lambda", lambdas); + } + } + + @Override + public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { + if(!useTags) { + String basePath = resourcePath; + if (basePath.startsWith("/")) { + basePath = basePath.substring(1); + } + int pos = basePath.indexOf("/"); + if (pos > 0) { + basePath = basePath.substring(0, pos); + } + + if (basePath.equals("")) { + basePath = "default"; + } else { + co.subresourceOperation = !co.path.isEmpty(); + } + List opList = operations.computeIfAbsent(basePath, k -> new ArrayList<>()); + opList.add(co); + co.baseName = basePath; + } else { + super.addOperationToGroup(tag, resourcePath, operation, co, operations); + } + } + + @Override + public String getArgumentsLocation() { + return null; + } + + @Override + public String getDefaultTemplateDir() { + return "JavaMicronaut"; + } + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + + if(!additionalProperties.containsKey(TITLE)) { + // From the title, compute a reasonable name for the package and the API + String title = openAPI.getInfo().getTitle(); + + // Drop any API suffix + if (title != null) { + title = title.trim().replace(" ", "-"); + if (title.toUpperCase().endsWith("API")) { + title = title.substring(0, title.length() - 3); + } + + this.title = camelize(sanitizeName(title), true); + } + additionalProperties.put(TITLE, this.title); + } + + final URL urlInfo = URLPathUtil.getServerURL(openAPI); + String port = "8080"; // Default value for a JEE Server + if ( urlInfo != null && urlInfo.getPort() != 0) { + port = String.valueOf(urlInfo.getPort()); + } + + this.additionalProperties.put("serverPort", port); + if (openAPI.getPaths() != null) { + for (String pathname : openAPI.getPaths().keySet()) { + PathItem pathItem = openAPI.getPaths().get(pathname); + final List operations = pathItem.readOperations(); + for (Operation operation : operations) { + if (operation.getTags() != null) { + List> tags = new ArrayList<>(); + for (String tag : operation.getTags()) { + Map value = new HashMap<>(); + value.put("tag", tag); + value.put("hasMore", "true"); + tags.add(value); + } + if (tags.size() > 0) { + tags.get(tags.size() - 1).remove("hasMore"); + } + if (operation.getTags().size() > 0) { + String tag = operation.getTags().get(0); + operation.setTags(singletonList(tag)); + } + operation.addExtension("x-tags", tags); + } + } + } + } + } + + @Override + public Map postProcessOperations(Map objs) { + @SuppressWarnings("unchecked") Map operations = (Map) objs.get("operations"); + if (operations != null) { + @SuppressWarnings("unchecked") List ops = (List) operations.get("operation"); + for (final CodegenOperation operation : ops) { + List responses = operation.responses; + if (responses != null) { + for (final CodegenResponse resp : responses) { + if ("0".equals(resp.code)) { + resp.code = "200"; + } + doDataTypeAssignment(resp.dataType, new DataTypeAssigner() { + @Override + public void setReturnType(final String returnType) { + resp.dataType = returnType; + } + + @Override + public void setReturnContainer(final String returnContainer) { + resp.containerType = returnContainer; + } + }); + } + } + + doDataTypeAssignment(operation.returnType, new DataTypeAssigner() { + + @Override + public void setReturnType(final String returnType) { + operation.returnType = returnType; + } + + @Override + public void setReturnContainer(final String returnContainer) { + operation.returnContainer = returnContainer; + } + }); + + if(implicitHeaders){ + removeHeadersFromAllParams(operation.allParams); + removeHeadersFromContents(operation.contents); + } + } + } + + return objs; + } + + private interface DataTypeAssigner { + void setReturnType(String returnType); + void setReturnContainer(String returnContainer); + } + + /** + * + * @param returnType The return type that needs to be converted + * @param dataTypeAssigner An object that will assign the data to the respective fields in the model. + */ + private void doDataTypeAssignment(final String returnType, DataTypeAssigner dataTypeAssigner) { + if (returnType == null) { + dataTypeAssigner.setReturnType("Void"); + } else if (returnType.startsWith("List")) { + int end = returnType.lastIndexOf(">"); + if (end > 0) { + dataTypeAssigner.setReturnType(returnType.substring("List<".length(), end).trim()); + dataTypeAssigner.setReturnContainer("List"); + } + } else if (returnType.startsWith("Map")) { + int end = returnType.lastIndexOf(">"); + if (end > 0) { + dataTypeAssigner.setReturnType(returnType.substring("Map<".length(), end).split(",")[1].trim()); + dataTypeAssigner.setReturnContainer("Map"); + } + } else if (returnType.startsWith("Set")) { + int end = returnType.lastIndexOf(">"); + if (end > 0) { + dataTypeAssigner.setReturnType(returnType.substring("Set<".length(), end).trim()); + dataTypeAssigner.setReturnContainer("Set"); + } + } + } + + /** + * This method removes header parameters from the list of parameters and also + * corrects last allParams hasMore state. + * @param allParams list of all parameters + */ + private void removeHeadersFromAllParams(List allParams) { + if(allParams.isEmpty()){ + return; + } + final ArrayList copy = new ArrayList<>(allParams); + allParams.clear(); + + for(CodegenParameter p : copy){ + if(!getBooleanValue(p, CodegenConstants.IS_HEADER_PARAM_EXT_NAME)){ + allParams.add(p); + } + } + allParams.get(allParams.size()-1).getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, Boolean.FALSE); + } + + private void removeHeadersFromContents(List contents) { + if(contents == null || contents.isEmpty()){ + return; + } + for (final CodegenContent codegenContent : contents) { + final List parameters = codegenContent.getParameters(); + if (parameters == null || parameters.isEmpty()) { + continue; + } + final List filteredParameters = parameters.stream() + .filter(codegenParameter -> !getBooleanValue(codegenParameter, CodegenConstants.IS_HEADER_PARAM_EXT_NAME)) + .collect(Collectors.toList()); + parameters.clear(); + parameters.addAll(filteredParameters); + parameters.get(parameters.size() - 1).getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, Boolean.FALSE); + } + } + + @Override + public Map postProcessSupportingFileData(Map objs) { + @SuppressWarnings("unchecked") List authMethods = (List) objs.get("authMethods"); + if (authMethods != null) { + for (CodegenSecurity authMethod : authMethods) { + authMethod.name = camelize(sanitizeName(authMethod.name), true); + } + } + return objs; + } + + @Override + public String toApiName(String name) { + if (name.length() == 0) { + return "DefaultApi"; + } + name = sanitizeName(name); + return camelize(name) + "Api"; + } + + @Override + public String toApiTestFilename(String name) { + return toApiName(name) + "ControllerTest"; + } + + public String toBooleanGetter(String name) { + return getterAndSetterCapitalize(name); + } + + @SuppressWarnings("WeakerAccess") + public void setTitle(String title) { + this.title = title; + } + + @SuppressWarnings("WeakerAccess") + public void setConfigPackage(String configPackage) { + this.configPackage = configPackage; + } + + @SuppressWarnings("WeakerAccess") + public void setBasePackage(String configPackage) { + this.basePackage = configPackage; + } + + @SuppressWarnings("WeakerAccess") + public void setUseTags(boolean useTags) { + this.useTags = useTags; + } + + @SuppressWarnings("WeakerAccess") + public void setImplicitHeaders(boolean implicitHeaders) { + this.implicitHeaders = implicitHeaders; + } + + @Override + public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { + super.postProcessModelProperty(model, property); + + if ("null".equals(property.example)) { + property.example = null; + } + + //Add imports for Jackson + boolean isEnum = getBooleanValue(model, IS_ENUM_EXT_NAME); + if (!Boolean.TRUE.equals(isEnum)) { + model.imports.add("JsonProperty"); + boolean hasEnums = getBooleanValue(model, HAS_ENUMS_EXT_NAME); + if (Boolean.TRUE.equals(hasEnums)) { + model.imports.add("JsonValue"); + } + } else { // enum class + //Needed imports for Jackson's JsonCreator + if (additionalProperties.containsKey("jackson")) { + model.imports.add("JsonCreator"); + } + } + if (model.discriminator != null && model.discriminator.getPropertyName().equals(property.baseName)) { + property.vendorExtensions.put("x-is-discriminator-property", true); + + //model.imports.add("JsonTypeId"); + } + } + + @Override + public Map postProcessModelsEnum(Map objs) { + objs = super.postProcessModelsEnum(objs); + + //Add imports for Jackson + @SuppressWarnings("unchecked") List> imports = (List>)objs.get("imports"); + @SuppressWarnings("unchecked") List models = (List) objs.get("models"); + for (Object _mo : models) { + @SuppressWarnings("unchecked") Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + // for enum model + boolean isEnum = getBooleanValue(cm, IS_ENUM_EXT_NAME); + if (Boolean.TRUE.equals(isEnum) && cm.allowableValues != null) { + cm.imports.add(importMapping.get("JsonValue")); + Map item = new HashMap<>(); + item.put("import", importMapping.get("JsonValue")); + imports.add(item); + } + } + + return objs; + } + + public void setUseBeanValidation(boolean useBeanValidation) { + this.useBeanValidation = useBeanValidation; + } + + @Override + public void setUseOptional(boolean useOptional) { + this.useOptional = useOptional; + } + + @Override + public void addHandlebarHelpers(Handlebars handlebars) { + handlebars.setInfiniteLoops(true); + super.addHandlebarHelpers(handlebars); + } + + private boolean isRxJava2Library() { + return library.equals(RXJAVA2_LIBRARY); + } + + private boolean isRxJava3Library() { + return library.equals(RXJAVA3_LIBRARY); + } + + private boolean isReactorLibrary() { + return library.equals(REACTOR_LIBRARY); + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/java/SpringCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/java/SpringCodegen.java index 11436ffea0..29b7276a4f 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/java/SpringCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/java/SpringCodegen.java @@ -14,14 +14,16 @@ import io.swagger.codegen.v3.CodegenType; import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.features.BeanValidationFeatures; +import io.swagger.codegen.v3.generators.features.NotNullAnnotationFeatures; import io.swagger.codegen.v3.generators.features.OptionalFeatures; -import io.swagger.codegen.v3.templates.MustacheTemplateEngine; -import io.swagger.codegen.v3.templates.TemplateEngine; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; import io.swagger.codegen.v3.utils.URLPathUtil; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; -import org.apache.commons.lang3.StringUtils; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +34,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -41,7 +45,7 @@ import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; -public class SpringCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, OptionalFeatures { +public class SpringCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, OptionalFeatures, NotNullAnnotationFeatures { static Logger LOGGER = LoggerFactory.getLogger(SpringCodegen.class); public static final String DEFAULT_LIBRARY = "spring-boot"; public static final String TITLE = "title"; @@ -50,14 +54,22 @@ public class SpringCodegen extends AbstractJavaCodegen implements BeanValidation public static final String INTERFACE_ONLY = "interfaceOnly"; public static final String DELEGATE_PATTERN = "delegatePattern"; public static final String SINGLE_CONTENT_TYPES = "singleContentTypes"; - public static final String JAVA_8 = "java8"; public static final String ASYNC = "async"; public static final String RESPONSE_WRAPPER = "responseWrapper"; public static final String USE_TAGS = "useTags"; public static final String SPRING_MVC_LIBRARY = "spring-mvc"; public static final String SPRING_CLOUD_LIBRARY = "spring-cloud"; + public static final String SPRING_BOOT_3_LIBRARY = "spring-boot3"; public static final String IMPLICIT_HEADERS = "implicitHeaders"; public static final String SWAGGER_DOCKET_CONFIG = "swaggerDocketConfig"; + public static final String TARGET_OPENFEIGN = "generateForOpenFeign"; + public static final String DEFAULT_INTERFACES = "defaultInterfaces"; + public static final String SPRING_BOOT_VERSION = "springBootVersion"; + public static final String SPRING_BOOT_VERSION_2 = "springBootV2"; + public static final String DATE_PATTERN = "datePattern"; + public static final String DATE_TIME_PATTERN = "dateTimePattern"; + + public static final String THROWS_EXCEPTION = "throwsException"; protected String title = "swagger-petstore"; protected String configPackage = "io.swagger.configuration"; @@ -67,6 +79,7 @@ public class SpringCodegen extends AbstractJavaCodegen implements BeanValidation protected boolean delegateMethod = false; protected boolean singleContentTypes = false; protected boolean java8 = false; + protected boolean java11 = false; protected boolean async = false; protected String responseWrapper = ""; protected boolean useTags = false; @@ -74,6 +87,11 @@ public class SpringCodegen extends AbstractJavaCodegen implements BeanValidation protected boolean implicitHeaders = false; protected boolean swaggerDocketConfig = false; protected boolean useOptional = false; + protected boolean openFeign = false; + protected boolean defaultInterfaces = true; + protected String springBootVersion = "2.1.16.RELEASE"; + protected boolean throwsException = false; + private boolean notNullJacksonAnnotation = false; public SpringCodegen() { super(); @@ -95,7 +113,6 @@ public SpringCodegen() { cliOptions.add(CliOption.newBoolean(INTERFACE_ONLY, "Whether to generate only API interface stubs without the server files.")); cliOptions.add(CliOption.newBoolean(DELEGATE_PATTERN, "Whether to generate the server files using the delegate pattern")); cliOptions.add(CliOption.newBoolean(SINGLE_CONTENT_TYPES, "Whether to select only one produces/consumes content-type by operation.")); - cliOptions.add(CliOption.newBoolean(JAVA_8, "use java8 default interface")); cliOptions.add(CliOption.newBoolean(ASYNC, "use async Callable controllers")); cliOptions.add(new CliOption(RESPONSE_WRAPPER, "wrap the responses in given type (Future,Callable,CompletableFuture,ListenableFuture,DeferredResult,HystrixCommand,RxObservable,RxSingle or fully qualified type)")); cliOptions.add(CliOption.newBoolean(USE_TAGS, "use tags for creating interface and controller classnames")); @@ -104,8 +121,14 @@ public SpringCodegen() { cliOptions.add(CliOption.newBoolean(SWAGGER_DOCKET_CONFIG, "Generate Spring Swagger Docket configuration class.")); cliOptions.add(CliOption.newBoolean(USE_OPTIONAL, "Use Optional container for optional parameters")); + cliOptions.add(CliOption.newBoolean(TARGET_OPENFEIGN,"Generate for usage with OpenFeign (instead of feign)")); + cliOptions.add(CliOption.newBoolean(DEFAULT_INTERFACES, "Generate default implementations for interfaces").defaultValue("true")); + cliOptions.add(CliOption.newBoolean(THROWS_EXCEPTION, "Throws Exception in operation methods").defaultValue("false")); + cliOptions.add(CliOption.newBoolean(DATE_PATTERN, "use pattern for date parameters").defaultValue("true")); + cliOptions.add(CliOption.newBoolean(DATE_TIME_PATTERN, "use pattern for date time parameters").defaultValue("true")); supportedLibraries.put(DEFAULT_LIBRARY, "Spring-boot Server application using the SpringFox integration."); + supportedLibraries.put(SPRING_BOOT_3_LIBRARY, "Spring-boot v3 Server application."); supportedLibraries.put(SPRING_MVC_LIBRARY, "Spring-MVC Server application using the SpringFox integration."); supportedLibraries.put(SPRING_CLOUD_LIBRARY, "Spring-Cloud-Feign client with Spring-Boot auto-configured settings."); setLibrary(DEFAULT_LIBRARY); @@ -115,6 +138,29 @@ public SpringCodegen() { library.setEnum(supportedLibraries); library.setDefault(DEFAULT_LIBRARY); cliOptions.add(library); + + CliOption springBootVersionOption = new CliOption(SPRING_BOOT_VERSION, "Spring boot version"); + Map springBootEnum = new HashMap<>(); + springBootEnum.put("1.5.22.RELEASE", "1.5.22.RELEASE"); + springBootEnum.put("2.1.7.RELEASE", "2.1.7.RELEASE"); + springBootVersionOption.setEnum(springBootEnum); + cliOptions.add(springBootVersionOption); + + } + + @Override + protected void addCodegenContentParameters(CodegenOperation codegenOperation, List codegenContents) { + for (CodegenContent content : codegenContents) { + addParameters(content, codegenOperation.headerParams); + addParameters(content, codegenOperation.queryParams); + addParameters(content, codegenOperation.pathParams); + addParameters(content, codegenOperation.cookieParams); + if (content.getIsForm()) { + addParameters(content, codegenOperation.formParams); + } else { + addParameters(content, codegenOperation.bodyParams); + } + } } @Override @@ -134,21 +180,35 @@ public String getHelp() { @Override public void processOpts() { - setUseOas2(true); - additionalProperties.put(CodegenConstants.USE_OAS2, true); - // Process java8 option before common java ones to change the default dateLibrary to java8. - if (additionalProperties.containsKey(JAVA_8)) { - this.setJava8(Boolean.valueOf(additionalProperties.get(JAVA_8).toString())); + if (additionalProperties.containsKey(JAVA8_MODE)) { + this.setJava8(Boolean.valueOf(additionalProperties.get(JAVA8_MODE).toString())); + } + + if (additionalProperties.containsKey(DATE_LIBRARY)) { + if (additionalProperties.get(DATE_LIBRARY).toString().startsWith("java8")) { + this.setJava8(true); + } } if (this.java8) { additionalProperties.put("javaVersion", "1.8"); - additionalProperties.put("jdk8", "true"); + additionalProperties.put("jdk8", true); if (!additionalProperties.containsKey(DATE_LIBRARY)) { setDateLibrary("java8"); } } + if (additionalProperties.containsKey(JAVA11_MODE)) { + this.setJava11(Boolean.valueOf(additionalProperties.get(JAVA11_MODE).toString())); + } + if (this.java11) { + additionalProperties.put("javaVersion", "11"); + additionalProperties.put("jdk11", "true"); + } + + additionalProperties.put("isJava8or11", this.java8 || this.java11); + this.defaultInterfaces = this.java8 || this.java11; + // set invokerPackage as basePackage if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { this.setBasePackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); @@ -156,12 +216,12 @@ public void processOpts() { LOGGER.info("Set base package to invoker package (" + basePackage + ")"); } - super.processOpts(); - - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); + if (isSpringBoot3Library()) { + setDateLibrary("java8"); } + super.processOpts(); + // clear model and api doc template as this codegen // does not support auto-generated markdown doc at the moment //TODO: add doc templates @@ -184,6 +244,11 @@ public void processOpts() { this.setInterfaceOnly(Boolean.valueOf(additionalProperties.get(INTERFACE_ONLY).toString())); } + if (additionalProperties.containsKey(THROWS_EXCEPTION)) { + this.setThrowsException(Boolean.valueOf(additionalProperties.get(THROWS_EXCEPTION).toString())); + additionalProperties.put(THROWS_EXCEPTION, throwsException); + } + if (additionalProperties.containsKey(DELEGATE_PATTERN)) { this.setDelegatePattern(Boolean.valueOf(additionalProperties.get(DELEGATE_PATTERN).toString())); } @@ -192,10 +257,6 @@ public void processOpts() { this.setSingleContentTypes(Boolean.valueOf(additionalProperties.get(SINGLE_CONTENT_TYPES).toString())); } - if (additionalProperties.containsKey(JAVA_8)) { - this.setJava8(Boolean.valueOf(additionalProperties.get(JAVA_8).toString())); - } - if (additionalProperties.containsKey(ASYNC)) { this.setAsync(Boolean.valueOf(additionalProperties.get(ASYNC).toString())); } @@ -216,6 +277,24 @@ public void processOpts() { this.setUseOptional(convertPropertyToBoolean(USE_OPTIONAL)); } + if (additionalProperties.containsKey(TARGET_OPENFEIGN)) { + this.setOpenFeign(convertPropertyToBoolean(TARGET_OPENFEIGN)); + } + + if (additionalProperties.containsKey(DEFAULT_INTERFACES)) { + this.setDefaultInterfaces(Boolean.valueOf(additionalProperties.get(DEFAULT_INTERFACES).toString())); + } + additionalProperties.put(DEFAULT_INTERFACES, this.defaultInterfaces); + + if (additionalProperties.containsKey(SPRING_BOOT_VERSION)) { + this.springBootVersion = additionalProperties.get(SPRING_BOOT_VERSION).toString(); + } + additionalProperties.put(SPRING_BOOT_VERSION, this.springBootVersion); + if (springBootVersion.startsWith("2")) { + additionalProperties.put(SPRING_BOOT_VERSION_2, true); + this.setOpenFeign(true); + } + if (useBeanValidation) { writePropertyBack(USE_BEANVALIDATION, useBeanValidation); } @@ -229,6 +308,7 @@ public void processOpts() { } typeMapping.put("file", "Resource"); + typeMapping.put("binary", "Resource"); importMapping.put("Resource", "org.springframework.core.io.Resource"); if (useOptional) { @@ -242,7 +322,7 @@ public void processOpts() { } else { throw new IllegalArgumentException( String.format("Can not generate code with `%s` and `%s` true while `%s` is false.", - DELEGATE_PATTERN, INTERFACE_ONLY, JAVA_8)); + DELEGATE_PATTERN, INTERFACE_ONLY, JAVA8_MODE)); } } @@ -250,18 +330,31 @@ public void processOpts() { supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); if (!this.interfaceOnly) { - - if (library.equals(DEFAULT_LIBRARY)) { + if (isSpringBoot3Library()) { + useOas2 = false; + additionalProperties.remove("threetenbp"); + additionalProperties.put(JAKARTA, jakarta = true); + apiTestTemplateFiles.clear(); + supportingFiles.add(new SupportingFile("homeController.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "HomeController.java")); + supportingFiles.add(new SupportingFile("openAPISpringBoot.mustache", (sourceFolder + File.separator + basePackage).replace(".", java.io.File.separator), "OpenAPISpringBoot.java")); + supportingFiles.add(new SupportingFile("swaggerUiConfiguration.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerUiConfiguration.java")); + supportingFiles.add(new SupportingFile("application.mustache", ("src.main.resources").replace(".", java.io.File.separator), "application.properties")); + } + if (isDefaultLibrary()) { + apiTestTemplateFiles.clear(); supportingFiles.add(new SupportingFile("homeController.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "HomeController.java")); supportingFiles.add(new SupportingFile("swagger2SpringBoot.mustache", (sourceFolder + File.separator + basePackage).replace(".", java.io.File.separator), "Swagger2SpringBoot.java")); supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", (sourceFolder + File.separator + basePackage).replace(".", java.io.File.separator), "RFC3339DateFormat.java")); + supportingFiles.add(new SupportingFile("swaggerUiConfiguration.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerUiConfiguration.java")); supportingFiles.add(new SupportingFile("application.mustache", ("src.main.resources").replace(".", java.io.File.separator), "application.properties")); } - if (library.equals(SPRING_MVC_LIBRARY)) { + if (isSpringMvcLibrary()) { + forceOas2(); supportingFiles.add(new SupportingFile("webApplication.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "WebApplication.java")); supportingFiles.add(new SupportingFile("webMvcConfiguration.mustache", @@ -270,21 +363,33 @@ public void processOpts() { (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerUiConfiguration.java")); supportingFiles.add(new SupportingFile("RFC3339DateFormat.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "RFC3339DateFormat.java")); - supportingFiles.add(new SupportingFile("application.properties", + supportingFiles.add(new SupportingFile("application.properties.mustache", ("src.main.resources").replace(".", java.io.File.separator), "swagger.properties")); } - if (library.equals(SPRING_CLOUD_LIBRARY)) { + if (isSpringCloudLibrary()) { + forceOas2(); supportingFiles.add(new SupportingFile("apiKeyRequestInterceptor.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "ApiKeyRequestInterceptor.java")); supportingFiles.add(new SupportingFile("clientConfiguration.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "ClientConfiguration.java")); - supportingFiles.add(new SupportingFile("Application.mustache", - (testFolder + File.separator + basePackage).replace(".", java.io.File.separator), "Application.java")); apiTemplateFiles.put("apiClient.mustache", "Client.java"); if (!additionalProperties.containsKey(SINGLE_CONTENT_TYPES)) { additionalProperties.put(SINGLE_CONTENT_TYPES, "true"); this.setSingleContentTypes(true); } + if (additionalProperties.containsKey(CodegenConstants.GENERATE_API_TESTS)) { + if (Boolean.valueOf(additionalProperties.get(CodegenConstants.GENERATE_API_TESTS).toString())) { + // TODO Api Tests are not currently supported in spring-cloud template + apiTestTemplateFiles.clear(); + supportingFiles.add(new SupportingFile("application-test.mustache", + ("src.test.resources").replace(".", java.io.File.separator), "application.yml")); + supportingFiles.add(new SupportingFile("TestUtils.mustache", + (testFolder + File.separator + basePackage).replace(".", java.io.File.separator), "TestUtils.java")); + supportingFiles.add(new SupportingFile("Application.mustache", + (testFolder + File.separator + basePackage).replace(".", java.io.File.separator), "Application.java")); + + } + } } else { apiTemplateFiles.put("apiController.mustache", "Controller.java"); supportingFiles.add(new SupportingFile("apiException.mustache", @@ -295,24 +400,33 @@ public void processOpts() { (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "NotFoundException.java")); supportingFiles.add(new SupportingFile("apiOriginFilter.mustache", (sourceFolder + File.separator + apiPackage).replace(".", java.io.File.separator), "ApiOriginFilter.java")); - supportingFiles.add(new SupportingFile("swaggerDocumentationConfig.mustache", + if (!isSpringBoot3Library()) { + supportingFiles.add(new SupportingFile("swaggerDocumentationConfig.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerDocumentationConfig.java")); + } + supportingFiles.add(new SupportingFile("LocalDateConverter.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "LocalDateConverter.java")); + supportingFiles.add(new SupportingFile("LocalDateTimeConverter.mustache", + (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "LocalDateTimeConverter.java")); } - } else if ( this.swaggerDocketConfig && !library.equals(SPRING_CLOUD_LIBRARY)) { + } else if ( this.swaggerDocketConfig && !isSpringCloudLibrary() && !isSpringBoot3Library()) { supportingFiles.add(new SupportingFile("swaggerDocumentationConfig.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "SwaggerDocumentationConfig.java")); } + if (this.interfaceOnly) { + apiTestTemplateFiles.clear(); + } if ("threetenbp".equals(dateLibrary)) { supportingFiles.add(new SupportingFile("customInstantDeserializer.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "CustomInstantDeserializer.java")); - if (library.equals(DEFAULT_LIBRARY) || library.equals(SPRING_CLOUD_LIBRARY)) { + if (isDefaultLibrary() || isSpringCloudLibrary()) { supportingFiles.add(new SupportingFile("jacksonConfiguration.mustache", (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "JacksonConfiguration.java")); } } - if ((!this.delegatePattern && this.java8) || this.delegateMethod) { + if ((!this.delegatePattern && (this.java8 || this.java11)) || this.delegateMethod) { additionalProperties.put("jdk8-no-delegate", true); } @@ -323,8 +437,6 @@ public void processOpts() { } if (this.java8) { - additionalProperties.put("javaVersion", "1.8"); - additionalProperties.put("jdk8", "true"); if (this.async) { additionalProperties.put(RESPONSE_WRAPPER, "CompletableFuture"); } @@ -332,6 +444,10 @@ public void processOpts() { additionalProperties.put(RESPONSE_WRAPPER, "Callable"); } + if(this.openFeign){ + additionalProperties.put("isOpenFeign", true); + } + // Some well-known Spring or Spring-Cloud response wrappers switch (this.responseWrapper) { case "Future": @@ -371,11 +487,28 @@ public void execute(Template.Fragment fragment, Writer writer) throws IOExceptio writer.write(fragment.execute().replaceAll("\\r|\\n", "")); } }); + + if ((this.java8 && !this.defaultInterfaces) || !this.java8) { + additionalProperties.put("fullController", true); + } + } + + @Override + public CodegenProperty fromProperty(String name, Schema propertySchema) { + CodegenProperty codegenProperty = super.fromProperty(name, propertySchema); + if (propertySchema != null && propertySchema.get$ref() != null) { + Schema refSchema = OpenAPIUtil.getSchemaFromRefSchema(propertySchema, this.openAPI); + if (refSchema != null && !isObjectSchema(refSchema) && !(refSchema instanceof ArraySchema) && !(refSchema instanceof MapSchema) && refSchema.getEnum() == null) { + setSchemaProperties(name, codegenProperty, refSchema); + processPropertySchemaTypes(name, codegenProperty, refSchema); + } + } + return codegenProperty; } @Override public void addOperationToGroup(String tag, String resourcePath, Operation operation, CodegenOperation co, Map> operations) { - if((library.equals(DEFAULT_LIBRARY) || library.equals(SPRING_MVC_LIBRARY)) && !useTags) { + if((isDefaultLibrary() || isSpringMvcLibrary()) && !useTags) { String basePath = resourcePath; if (basePath.startsWith("/")) { basePath = basePath.substring(1); @@ -404,7 +537,7 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera @Override public String getArgumentsLocation() { - return null; + return "/arguments/spring.yaml"; } @Override @@ -434,7 +567,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { final URL urlInfo = URLPathUtil.getServerURL(openAPI); String port = "8080"; // Default value for a JEE Server - if ( urlInfo != null && urlInfo.getPort() != 0) { + if (urlInfo != null && urlInfo.getPort() > 0) { port = String.valueOf(urlInfo.getPort()); } @@ -478,6 +611,10 @@ public Map postProcessOperations(Map objs) { if ("0".equals(resp.code)) { resp.code = "200"; } + if (resp.baseType == null) { + // set vendorExtensions.x-java-is-response-void to true as baseType is set to "Void" + resp.vendorExtensions.put("x-java-is-response-void", true); + } doDataTypeAssignment(resp.dataType, new DataTypeAssigner() { @Override public void setReturnType(final String returnType) { @@ -509,12 +646,35 @@ public void setReturnContainer(final String returnContainer) { removeHeadersFromAllParams(operation.allParams); removeHeadersFromContents(operation.contents); } + if (operation.examples != null){ + for (Map example : operation.examples) + { + for (Map.Entry entry : example.entrySet()) + { + // Replace " with \", \r, \n with \\r, \\n + String val = entry.getValue().replace("\"", "\\\"") + .replace("\r","\\r") + .replace("\n","\\n"); + entry.setValue(val); + } + } + } } } return objs; } + @Override + public void setNotNullJacksonAnnotation(boolean notNullJacksonAnnotation) { + this.notNullJacksonAnnotation = notNullJacksonAnnotation; + } + + @Override + public boolean isNotNullJacksonAnnotation() { + return notNullJacksonAnnotation; + } + private interface DataTypeAssigner { void setReturnType(String returnType); void setReturnContainer(String returnContainer); @@ -538,7 +698,10 @@ private void doDataTypeAssignment(String returnType, SpringCodegen.DataTypeAssig } else if (rt.startsWith("Map")) { int end = rt.lastIndexOf(">"); if (end > 0) { - dataTypeAssigner.setReturnType(rt.substring("Map<".length(), end).split(",")[1].trim()); + String mapTypes = rt.substring("Map<".length(), end); + String mapKey = mapTypes.split(",")[0]; + String mapValue = mapTypes.substring(mapKey.length() + 1).trim(); + dataTypeAssigner.setReturnType(mapValue); dataTypeAssigner.setReturnContainer("Map"); } } else if (rt.startsWith("Set")) { @@ -589,9 +752,35 @@ private void removeHeadersFromContents(List contents) { } } + /** + * Forces Oas2 specification, use it when Oas3 is not supported. + */ + private void forceOas2() { + setUseOas2(true); + additionalProperties.put(CodegenConstants.USE_OAS2, true); + importMapping.put("ApiModelProperty", "io.swagger.annotations.ApiModelProperty"); + importMapping.put("ApiModel", "io.swagger.annotations.ApiModel"); + importMapping.remove("Schema"); + } + + private boolean isSpringCloudLibrary() { + return library.equals(SPRING_CLOUD_LIBRARY); + } + + private boolean isSpringMvcLibrary() { + return library.equals(SPRING_MVC_LIBRARY); + } + + private boolean isDefaultLibrary() { + return library.equals(DEFAULT_LIBRARY); + } + private boolean isSpringBoot3Library() { + return library.equals(SPRING_BOOT_3_LIBRARY); + } + @Override public Map postProcessSupportingFileData(Map objs) { - if(library.equals(SPRING_CLOUD_LIBRARY)) { + if (isSpringCloudLibrary()) { List authMethods = (List) objs.get("authMethods"); if (authMethods != null) { for (CodegenSecurity authMethod : authMethods) { @@ -613,10 +802,10 @@ public String toApiName(String name) { @Override public String toApiTestFilename(String name) { - if(library.equals(SPRING_MVC_LIBRARY)) { + if (isSpringMvcLibrary()) { return toApiName(name) + "ControllerIT"; } - if(library.equals(SPRING_CLOUD_LIBRARY)) { + if (isSpringCloudLibrary()) { return toApiName(name) + "Test"; } return toApiName(name) + "ControllerIntegrationTest"; @@ -648,10 +837,6 @@ public void setParameterExampleValue(CodegenParameter p) { } } - public String toBooleanGetter(String name) { - return getterAndSetterCapitalize(name); - } - public void setTitle(String title) { this.title = title; } @@ -674,6 +859,8 @@ public void setSingleContentTypes(boolean singleContentTypes) { public void setJava8(boolean java8) { this.java8 = java8; } + public void setJava11(boolean java11) { this.java11 = java11; } + public void setAsync(boolean async) { this.async = async; } public void setResponseWrapper(String responseWrapper) { this.responseWrapper = responseWrapper; } @@ -712,11 +899,65 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert model.imports.add("JsonCreator"); } } - if (model.discriminator != null && model.discriminator.getPropertyName().equals(property.baseName)) { - property.vendorExtensions.put("x-is-discriminator-property", true); + } - //model.imports.add("JsonTypeId"); + @Override + public Map postProcessAllModels(Map objs) { + Map allProcessedModels = super.postProcessAllModels(objs); + + List allModels = new ArrayList(); + for (String name: allProcessedModels.keySet()) { + Map models = (Map)allProcessedModels.get(name); + try { + allModels.add(((List) models.get("models")).get(0)); + } catch (Exception e){ + e.printStackTrace(); + } } + + additionalProperties.put("parent", modelInheritanceSupport(allModels)); + + return allProcessedModels; + } + + protected List> modelInheritanceSupport(List allModels) { + Map> byParent = new LinkedHashMap<>(); + for (Object model : allModels) { + Map entry = (Map) model; + CodegenModel parent = ((CodegenModel)entry.get("model")).parentModel; + if(null!= parent) { + byParent.computeIfAbsent(parent, k -> new LinkedList<>()).add((CodegenModel)entry.get("model")); + } + } + + List> parentsList = new ArrayList<>(); + for (Map.Entry> parentModelEntry : byParent.entrySet()) { + CodegenModel parentModel = parentModelEntry.getKey(); + List> childrenList = new ArrayList<>(); + Map parent = new HashMap<>(); + parent.put("classname", parentModel.classname); + List childrenModels = byParent.get(parentModel); + + if (childrenModels == null || childrenModels.isEmpty()) { + continue; + } + + for (CodegenModel model : childrenModels) { + Map child = new HashMap<>(); + child.put("name", model.name); + child.put("classname", model.classname); + childrenList.add(child); + } + parent.put("children", childrenList); + parent.put("discriminator", parentModel.discriminator); + if(parentModel.discriminator != null && parentModel.discriminator.getMapping() != null) + { + parentModel.discriminator.getMapping().replaceAll((key, value) -> OpenAPIUtil.getSimpleRef(value)); + } + parentsList.add(parent); + } + + return parentsList; } @Override @@ -750,4 +991,16 @@ public void setUseBeanValidation(boolean useBeanValidation) { public void setUseOptional(boolean useOptional) { this.useOptional = useOptional; } + + public void setOpenFeign(boolean openFeign) { + this.openFeign = openFeign; + } + + public void setDefaultInterfaces(boolean defaultInterfaces) { + this.defaultInterfaces = defaultInterfaces; + } + + public void setThrowsException(boolean throwsException) { + this.throwsException = throwsException; + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/javascript/JavaScriptClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/javascript/JavaScriptClientCodegen.java new file mode 100644 index 0000000000..a5813fb2ee --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/javascript/JavaScriptClientCodegen.java @@ -0,0 +1,1463 @@ +package io.swagger.codegen.v3.generators.javascript; + +import com.google.common.base.Strings; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenParameter; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.BooleanSchema; +import io.swagger.v3.oas.models.media.DateSchema; +import io.swagger.v3.oas.models.media.DateTimeSchema; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.NumberSchema; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import static io.swagger.codegen.v3.CodegenConstants.HAS_ENUMS_EXT_NAME; +import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +public class JavaScriptClientCodegen extends DefaultCodegenConfig { + @SuppressWarnings("hiding") + private static final Logger LOGGER = LoggerFactory.getLogger(JavaScriptClientCodegen.class); + + public static final String PROJECT_NAME = "projectName"; + public static final String MODULE_NAME = "moduleName"; + public static final String PROJECT_DESCRIPTION = "projectDescription"; + public static final String PROJECT_VERSION = "projectVersion"; + public static final String USE_PROMISES = "usePromises"; + public static final String USE_INHERITANCE = "useInheritance"; + public static final String EMIT_MODEL_METHODS = "emitModelMethods"; + public static final String EMIT_JS_DOC = "emitJSDoc"; + public static final String USE_ES6 = "useES6"; + public static final String LOAD_TEST_DATA_FROM_FILE = "loadTestDataFromFile"; + public static final String TEST_DATA_FILE = "testDataFile"; + public static final String PRESERVE_LEADING_PARAM_CHAR = "preserveLeadingParamChar"; + + final String[][] JAVASCRIPT_ES6_SUPPORTING_FILES = new String[][] { + new String[] {"package.mustache", "package.json"}, + new String[] {"index.mustache", "index.js"}, + new String[] {"ApiClient.mustache", "ApiClient.js"}, + new String[] {"git_push.sh.mustache", "git_push.sh"}, + new String[] {"README.mustache", "README.md"}, + new String[] {"mocha.opts", "mocha.opts"}, + new String[] {"travis.yml", ".travis.yml"}, + new String[] {"assert-equals.js", "assert-equals.js"}, + new String[] {".babelrc.mustache", ".babelrc"} + }; + + static final String[][] JAVASCRIPT_SUPPORTING_FILES = new String[][] { + new String[] {"package.mustache", "package.json"}, + new String[] {"index.mustache", "index.js"}, + new String[] {"ApiClient.mustache", "ApiClient.js"}, + new String[] {"git_push.sh.mustache", "git_push.sh"}, + new String[] {"README.mustache", "README.md"}, + new String[] {"mocha.opts", "mocha.opts"}, + new String[] {"travis.yml", ".travis.yml"}, + new String[] {"assert-equals.js", "assert-equals.js"}, + + }; + + static final Collection INVOKER_PKG_SUPPORTING_FILES = Arrays.asList("ApiClient.mustache", "index.mustache"); + static final Collection TEST_SUPPORTING_FILES = Arrays.asList("assert-equals.js"); + + protected String projectName; + protected String moduleName; + protected String projectDescription; + protected String projectVersion; + protected String licenseName; + + protected String invokerPackage; + protected String sourceFolder = "src"; + protected String localVariablePrefix = ""; + protected boolean usePromises; + protected boolean emitModelMethods; + protected boolean emitJSDoc = true; + protected String apiDocPath = "docs/"; + protected String modelDocPath = "docs/"; + protected String apiTestPath = "api/"; + protected String modelTestPath = "model/"; + protected boolean useES6 = true; + private String modelPropertyNaming = "camelCase"; + + protected boolean loadTestDataFromFile = false; + protected File testDataFile = null; + protected boolean preserveLeadingParamChar = false; + + public JavaScriptClientCodegen() { + super(); + outputFolder = "generated-code/js"; + modelTemplateFiles.put("model.mustache", ".js"); + modelTestTemplateFiles.put("model_test.mustache", ".js"); + apiTemplateFiles.put("api.mustache", ".js"); + apiTestTemplateFiles.put("api_test.mustache", ".js"); + apiPackage = "api"; + modelPackage = "model"; + modelDocTemplateFiles.put("model_doc.mustache", ".md"); + apiDocTemplateFiles.put("api_doc.mustache", ".md"); + + // default HIDE_GENERATION_TIMESTAMP to true + hideGenerationTimestamp = Boolean.TRUE; + + // reference: http://www.w3schools.com/js/js_reserved.asp + setReservedWordsLowerCase( + Arrays.asList( + "abstract", "arguments", "boolean", "break", "byte", + "case", "catch", "char", "class", "const", + "continue", "debugger", "default", "delete", "do", + "double", "else", "enum", "eval", "export", + "extends", "false", "final", "finally", "float", + "for", "function", "goto", "if", "implements", + "import", "in", "instanceof", "int", "interface", + "let", "long", "native", "new", "null", + "package", "private", "protected", "public", "return", + "short", "static", "super", "switch", "synchronized", + "this", "throw", "throws", "transient", "true", + "try", "typeof", "var", "void", "volatile", + "while", "with", "yield", + "Array", "Date", "eval", "function", "hasOwnProperty", + "Infinity", "isFinite", "isNaN", "isPrototypeOf", + "Math", "NaN", "Number", "Object", + "prototype", "String", "toString", "undefined", "valueOf") + ); + + languageSpecificPrimitives = new HashSet( + Arrays.asList("String", "Boolean", "Number", "Array", "Object", "Date", "File", "Blob") + ); + defaultIncludes = new HashSet(languageSpecificPrimitives); + + instantiationTypes.put("array", "Array"); + instantiationTypes.put("list", "Array"); + instantiationTypes.put("map", "Object"); + typeMapping.clear(); + typeMapping.put("array", "Array"); + typeMapping.put("map", "Object"); + typeMapping.put("List", "Array"); + typeMapping.put("boolean", "Boolean"); + typeMapping.put("string", "String"); + typeMapping.put("int", "Number"); + typeMapping.put("float", "Number"); + typeMapping.put("number", "Number"); + typeMapping.put("BigDecimal", "Number"); + typeMapping.put("DateTime", "Date"); + typeMapping.put("date", "Date"); + typeMapping.put("long", "Number"); + typeMapping.put("short", "Number"); + typeMapping.put("char", "String"); + typeMapping.put("double", "Number"); + typeMapping.put("object", "Object"); + typeMapping.put("integer", "Number"); + // binary not supported in JavaScript client right now, using String as a workaround + typeMapping.put("ByteArray", "Blob"); // I don't see ByteArray defined in the Swagger docs. + typeMapping.put("binary", "File"); + typeMapping.put("binary", "Blob"); + typeMapping.put("file", "File"); + typeMapping.put("URI", "String"); + typeMapping.put("UUID", "String"); + + importMapping.clear(); + + cliOptions.add(new CliOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC).defaultValue("src")); + cliOptions.add(new CliOption(CodegenConstants.LOCAL_VARIABLE_PREFIX, CodegenConstants.LOCAL_VARIABLE_PREFIX_DESC)); + cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC)); + cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC)); + cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC)); + cliOptions.add(new CliOption(PROJECT_NAME, + "name of the project (Default: generated from info.title or \"swagger-js-client\")")); + cliOptions.add(new CliOption(MODULE_NAME, + "module name for AMD, Node or globals (Default: generated from )")); + cliOptions.add(new CliOption(PROJECT_DESCRIPTION, + "description of the project (Default: using info.description or \"Client library of \")")); + cliOptions.add(new CliOption(PROJECT_VERSION, + "version of the project (Default: using info.version or \"1.0.0\")")); + cliOptions.add(new CliOption(CodegenConstants.LICENSE_NAME, + "name of the license the project uses (Default: using info.license.name)")); + cliOptions.add(new CliOption(USE_PROMISES, + "use Promises as return values from the client API, instead of superagent callbacks") + .defaultValue(Boolean.FALSE.toString())); + cliOptions.add(new CliOption(EMIT_MODEL_METHODS, + "generate getters and setters for model properties") + .defaultValue(Boolean.FALSE.toString())); + cliOptions.add(new CliOption(EMIT_JS_DOC, + "generate JSDoc comments") + .defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(USE_INHERITANCE, + "use JavaScript prototype chains & delegation for inheritance") + .defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC) + .defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(USE_ES6, + "use JavaScript ES6 (ECMAScript 6) (beta). Default is ES5.") + .defaultValue(Boolean.FALSE.toString())); + cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); + cliOptions.add(CliOption.newBoolean(LOAD_TEST_DATA_FROM_FILE, "Load test data from a JSON file")); + cliOptions.add(CliOption.newString(TEST_DATA_FILE, "JSON file to contain test data")); + cliOptions.add(CliOption.newString(PRESERVE_LEADING_PARAM_CHAR, "Preserves leading $ and _ characters in parameter names.")); + } + + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public String getName() { + return "javascript"; + } + + @Override + public String getHelp() { + return "Generates a Javascript client library."; + } + + @Override + public void processOpts() { + if (additionalProperties.containsKey(USE_ES6)) { + setUseES6(convertPropertyToBooleanAndWriteBack(USE_ES6)); + } + super.processOpts(); + + if (additionalProperties.containsKey(PROJECT_NAME)) { + setProjectName(((String) additionalProperties.get(PROJECT_NAME))); + } + if (additionalProperties.containsKey(MODULE_NAME)) { + setModuleName(((String) additionalProperties.get(MODULE_NAME))); + } + if (additionalProperties.containsKey(PROJECT_DESCRIPTION)) { + setProjectDescription(((String) additionalProperties.get(PROJECT_DESCRIPTION))); + } + if (additionalProperties.containsKey(PROJECT_VERSION)) { + setProjectVersion(((String) additionalProperties.get(PROJECT_VERSION))); + } + if (additionalProperties.containsKey(CodegenConstants.LICENSE_NAME)) { + setLicenseName(((String) additionalProperties.get(CodegenConstants.LICENSE_NAME))); + } + if (additionalProperties.containsKey(CodegenConstants.LOCAL_VARIABLE_PREFIX)) { + setLocalVariablePrefix((String) additionalProperties.get(CodegenConstants.LOCAL_VARIABLE_PREFIX)); + } + if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) { + setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER)); + } + if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) { + setInvokerPackage((String) additionalProperties.get(CodegenConstants.INVOKER_PACKAGE)); + } + if (additionalProperties.containsKey(USE_PROMISES)) { + setUsePromises(convertPropertyToBooleanAndWriteBack(USE_PROMISES)); + } + if (additionalProperties.containsKey(USE_INHERITANCE)) { + setUseInheritance(convertPropertyToBooleanAndWriteBack(USE_INHERITANCE)); + } else { + supportsInheritance = true; + supportsMixins = true; + } + if (additionalProperties.containsKey(EMIT_MODEL_METHODS)) { + setEmitModelMethods(convertPropertyToBooleanAndWriteBack(EMIT_MODEL_METHODS)); + } + if (additionalProperties.containsKey(EMIT_JS_DOC)) { + setEmitJSDoc(convertPropertyToBooleanAndWriteBack(EMIT_JS_DOC)); + } + if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) { + setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING)); + } + boolean loadTestDataFromFile = convertPropertyToBooleanAndWriteBack(LOAD_TEST_DATA_FROM_FILE); + this.setLoadTestDataFromFile(loadTestDataFromFile); + if (loadTestDataFromFile) { + String testDataFileStr; + if (additionalProperties.containsKey(TEST_DATA_FILE)) + testDataFileStr = (String) additionalProperties.get(TEST_DATA_FILE); + else + testDataFileStr = outputFolder() + "/test/test-data.json"; + testDataFileStr = testDataFileStr.replace('/', File.separatorChar); + try { + File testDataFile = new File(testDataFileStr).getCanonicalFile(); + testDataFileStr = testDataFile.getPath(); + additionalProperties.put(TEST_DATA_FILE, testDataFileStr.replaceAll("\\\\", "\\\\\\\\")); + setTestDataFile(testDataFile); + } catch (IOException e) { + throw new RuntimeException("Failed to canonicalize file " + testDataFileStr, e); + } + } + boolean preserveLeadingParamChar = convertPropertyToBooleanAndWriteBack(PRESERVE_LEADING_PARAM_CHAR); + this.setPreserveLeadingParamChar(preserveLeadingParamChar); + } + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + + if (openAPI.getInfo() != null) { + Info info = openAPI.getInfo(); + if (StringUtils.isBlank(projectName) && info.getTitle() != null) { + // when projectName is not specified, generate it from info.title + projectName = sanitizeName(dashize(info.getTitle())); + } + if (StringUtils.isBlank(projectVersion)) { + // when projectVersion is not specified, use info.version + projectVersion = escapeUnsafeCharacters(escapeQuotationMark(info.getVersion())); + } + if (projectDescription == null) { + // when projectDescription is not specified, use info.description + projectDescription = sanitizeName(info.getDescription()); + } + + // when licenceName is not specified, use info.license + if (additionalProperties.get(CodegenConstants.LICENSE_NAME) == null && info.getLicense() != null) { + License license = info.getLicense(); + licenseName = license.getName(); + } + } + + // default values + if (StringUtils.isBlank(projectName)) { + projectName = "swagger-js-client"; + } + if (StringUtils.isBlank(moduleName)) { + moduleName = camelize(underscore(projectName)); + } + if (StringUtils.isBlank(projectVersion)) { + projectVersion = "1.0.0"; + } + if (projectDescription == null) { + projectDescription = "Client library of " + projectName; + } + if (StringUtils.isBlank(licenseName)) { + licenseName = "Unlicense"; + } + + additionalProperties.put(PROJECT_NAME, projectName); + additionalProperties.put(MODULE_NAME, moduleName); + additionalProperties.put(PROJECT_DESCRIPTION, escapeText(projectDescription)); + additionalProperties.put(PROJECT_VERSION, projectVersion); + additionalProperties.put(CodegenConstants.LICENSE_NAME, licenseName); + additionalProperties.put(CodegenConstants.API_PACKAGE, apiPackage); + additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage); + additionalProperties.put(CodegenConstants.LOCAL_VARIABLE_PREFIX, localVariablePrefix); + additionalProperties.put(CodegenConstants.MODEL_PACKAGE, modelPackage); + additionalProperties.put(CodegenConstants.SOURCE_FOLDER, sourceFolder); + additionalProperties.put(USE_PROMISES, usePromises); + additionalProperties.put(USE_INHERITANCE, supportsInheritance); + additionalProperties.put(EMIT_MODEL_METHODS, emitModelMethods); + additionalProperties.put(EMIT_JS_DOC, emitJSDoc); + additionalProperties.put(USE_ES6, useES6); + + // make api and model doc path available in mustache template + additionalProperties.put("apiDocPath", apiDocPath); + additionalProperties.put("modelDocPath", modelDocPath); + + String[][] supportingTemplateFiles = useES6 ? JAVASCRIPT_ES6_SUPPORTING_FILES : JAVASCRIPT_SUPPORTING_FILES; + for (String[] supportingTemplateFile : supportingTemplateFiles) { + String templateFile = supportingTemplateFile[0]; + String folder; + if (INVOKER_PKG_SUPPORTING_FILES.contains(templateFile)) + // #1150: index.js & ApiClient.js must be generated to invokerPackage, otherwise nothing works! + folder = createPath(sourceFolder, invokerPackage); + else if (TEST_SUPPORTING_FILES.contains(templateFile)) + folder = createPath("test"); + else + folder = ""; + supportingFiles.add(new SupportingFile(templateFile, folder, supportingTemplateFile[1])); + } + } + + @Override + public String escapeReservedWord(String name) { + if(this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return "_" + name; + } + + /** + * Concatenates an array of path segments into a path string. + * @param segments The path segments to concatenate. A segment may contain either of the file separator characters '\' or '/'. + * A segment is ignored if it is null, empty or ".". + * @return A path string using the correct platform-specific file separator character. + */ + private String createPath(String... segments) { + StringBuilder buf = new StringBuilder(); + for (String segment : segments) { + if (!StringUtils.isEmpty(segment) && !segment.equals(".")) { + if (buf.length() != 0) + buf.append(File.separatorChar); + buf.append(segment); + } + } + for (int i = 0; i < buf.length(); i++) { + char c = buf.charAt(i); + if ((c == '/' || c == '\\') && c != File.separatorChar) + buf.setCharAt(i, File.separatorChar); + } + return buf.toString(); + } + + @Override + public String apiTestFileFolder() { + return (outputFolder + "/test/" + apiTestPath).replace('/', File.separatorChar); + } + + @Override + public String modelTestFileFolder() { + return (outputFolder + "/test/" + modelTestPath).replace('/', File.separatorChar); + } + + @Override + public String apiFileFolder() { + return createPath(outputFolder, sourceFolder, invokerPackage, apiPackage()); + } + + @Override + public String modelFileFolder() { + return createPath(outputFolder, sourceFolder, invokerPackage, modelPackage()); + } + + public String getInvokerPackage() { + return invokerPackage; + } + + public void setInvokerPackage(String invokerPackage) { + this.invokerPackage = invokerPackage; + } + + public void setSourceFolder(String sourceFolder) { + this.sourceFolder = sourceFolder; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setLocalVariablePrefix(String localVariablePrefix) { + this.localVariablePrefix = localVariablePrefix; + } + + public void setModuleName(String moduleName) { + this.moduleName = moduleName; + } + + public void setProjectDescription(String projectDescription) { + this.projectDescription = projectDescription; + } + + public void setProjectVersion(String projectVersion) { + this.projectVersion = projectVersion; + } + + public void setLicenseName(String licenseName) { + this.licenseName = licenseName; + } + + public void setUsePromises(boolean usePromises) { + this.usePromises = usePromises; + } + + public void setUseES6(boolean useES6) { + this.useES6 = useES6; + if (useES6) { + embeddedTemplateDir = templateDir = "Javascript/es6"; + LOGGER.info("Using JS ES6 templates"); + } else { + embeddedTemplateDir = templateDir = "Javascript"; + LOGGER.info("Using JS ES5 templates"); + } + } + + public void setUseInheritance(boolean useInheritance) { + this.supportsInheritance = useInheritance; + this.supportsMixins = useInheritance; + } + + public void setEmitModelMethods(boolean emitModelMethods) { + this.emitModelMethods = emitModelMethods; + } + + public void setEmitJSDoc(boolean emitJSDoc) { + this.emitJSDoc = emitJSDoc; + } + + @Override + public String apiDocFileFolder() { + return createPath(outputFolder, apiDocPath); + } + + @Override + public String modelDocFileFolder() { + return createPath(outputFolder, modelDocPath); + } + + @Override + public String toApiDocFilename(String name) { + return toApiName(name); + } + + @Override + public String toModelDocFilename(String name) { + return toModelName(name); + } + + @Override + public String toApiTestFilename(String name) { + return toApiName(name) + ".spec"; + } + + @Override + public String toModelTestFilename(String name) { + return toModelName(name) + ".spec"; + } + + public String getModelPropertyNaming() { + return this.modelPropertyNaming; + } + + private String getNameUsingModelPropertyNaming(String name) { + switch (CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.valueOf(getModelPropertyNaming())) { + case original: return name; + case camelCase: return camelize(name, true); + case PascalCase: return camelize(name); + case snake_case: return underscore(name); + default: throw new IllegalArgumentException("Invalid model property naming '" + + name + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + } + + @Override + public String toVarName(String name) { + char first = name.charAt(0); + + // sanitize name + name = sanitizeName(name); // FIXME parameter should not be assigned. Also declare it as "final" + + if("_".equals(name)) { + name = "_u"; + } + + // if it's all upper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + // camelize (lower first character) the variable name + // pet_id => petId + name = getNameUsingModelPropertyNaming(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + // $ and _ characters are legal in JavaScript identifiers, so no need to strip them. + if (preserveLeadingParamChar && (first == '$' || first == '_')) + name = first + name; + + return name; + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String name) { + if (name == null) { + return "Object"; + } + name = sanitizeName(name); // FIXME parameter should not be assigned. Also declare it as "final" + + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + + // camelize the model name + // phone_number => PhoneNumber + name = camelize(name); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + String modelName = "Model" + name; + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + // model name starts with number + if (name.matches("^\\d.*")) { + String modelName = "Model" + name; // e.g. 200Response => Model200Response (after camelize) + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + return name; + } + + @Override + public String toModelFilename(String name) { + // should be the same as the model name + return toModelName(name); + } + + @Override + public String toModelImport(String name) { + return name; + } + + @Override + public String toApiImport(String name) { + return toApiName(name); + } + + @Override + public String getTypeDeclaration(Schema schema) { + if (schema instanceof ArraySchema) { + ArraySchema ap = (ArraySchema) schema; + Schema inner = ap.getItems(); + return "[" + getTypeDeclaration(inner) + "]"; + } else if (schema instanceof MapSchema && hasSchemaProperties(schema)) { + MapSchema mapSchema = (MapSchema) schema; + Schema inner = (Schema) mapSchema.getAdditionalProperties(); + return "{String: " + getTypeDeclaration(inner) + "}"; + } else if (schema instanceof MapSchema && hasTrueAdditionalProperties(schema)) { + Schema inner = new ObjectSchema(); + return "{String: " + getTypeDeclaration(inner) + "}"; + } + return super.getTypeDeclaration(schema); + } + + @Override + public String toDefaultValue(Schema propertySchema) { + if (propertySchema instanceof StringSchema) { + StringSchema stringSchema = (StringSchema) propertySchema; + if (stringSchema.getDefault() != null) { + return "'" + stringSchema.getDefault() + "'"; + } + } else if (propertySchema instanceof BooleanSchema) { + BooleanSchema booleanSchema = (BooleanSchema) propertySchema; + if (booleanSchema.getDefault() != null) { + return booleanSchema.getDefault().toString(); + } + } else if (propertySchema instanceof DateSchema) { + // TODO + } else if (propertySchema instanceof DateTimeSchema) { + // TODO + } else if (propertySchema instanceof NumberSchema) { + NumberSchema numberSchema = (NumberSchema) propertySchema; + if (numberSchema.getDefault() != null) { + return numberSchema.getDefault().toString(); + } + } else if (propertySchema instanceof IntegerSchema) { + IntegerSchema integerSchema = (IntegerSchema) propertySchema; + if (integerSchema.getDefault() != null) { + return integerSchema.getDefault().toString(); + } + } + + return null; + } + + public void setModelPropertyNaming(String naming) { + if ("original".equals(naming) || "camelCase".equals(naming) || + "PascalCase".equals(naming) || "snake_case".equals(naming)) { + this.modelPropertyNaming = naming; + } else { + throw new IllegalArgumentException("Invalid model property naming '" + + naming + "'. Must be 'original', 'camelCase', " + + "'PascalCase' or 'snake_case'"); + } + } + + @Override + public String toDefaultValueWithParam(String name, Schema schema) { + String typeDeclaration = getTypeDeclaration(schema); + String type = normalizeType(typeDeclaration); + if (!StringUtils.isEmpty(schema.get$ref()) && !isPrimitiveType(typeDeclaration.toLowerCase())) { + return " = " + type + ".constructFromObject(data['" + name + "']);"; + } + return " = ApiClient.convertToType(data['" + name + "'], " + type + ");"; + } + + @Override + public void setParameterExampleValue(CodegenParameter p) { + String example; + + if (p.defaultValue == null) { + example = p.example; + } else { + example = p.defaultValue; + } + + String type = p.baseType; + if (type == null) { + type = p.dataType; + } + + if ("String".equals(type)) { + if (example == null) { + example = p.paramName + "_example"; + } + example = "\"" + escapeText(example) + "\""; + } else if ("Integer".equals(type)) { + if (example == null) { + example = "56"; + } + } else if ("Number".equals(type)) { + if (example == null) { + example = "3.4"; + } + } else if ("Boolean".equals(type)) { + if (example == null) { + example = "true"; + } + } else if ("Blob".equals(type)) { + if (example == null || example.equals("B")) { + example = "QmFzZTY0IGV4YW1wbGU="; + } + example = "\"" + escapeText(example) + "\""; + } else if ("File".equals(type)) { + if (example == null) { + example = "/path/to/file"; + } + example = "\"" + escapeText(example) + "\""; + } else if ("Date".equals(type)) { + if (example == null) { + example = "2013-10-20T19:20:30+01:00"; + } + example = "new Date(\"" + escapeText(example) + "\")"; + } else if (!languageSpecificPrimitives.contains(type)) { + // type is a model class, e.g. User + example = "new " + moduleName + "." + type + "()"; + } + + if (example == null) { + example = "null"; + } else if (getBooleanValue(p, CodegenConstants.IS_LIST_CONTAINER_EXT_NAME)) { + example = "[" + example + "]"; + } else if (getBooleanValue(p, CodegenConstants.IS_MAP_CONTAINER_EXT_NAME)) { + example = "{key: " + example + "}"; + } + + p.example = example; + } + + /** + * Normalize type by wrapping primitive types with single quotes. + * + * @param type Primitive type + * @return Normalized type + */ + public String normalizeType(String type) { + return type.replaceAll("\\b(Boolean|Integer|Number|String|Date|Blob)\\b", "'$1'"); + } + + @Override + public String getSchemaType(Schema schema) { + String swaggerType = super.getSchemaType(schema); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (!needToImport(type)) { + return type; + } + } else { + type = swaggerType; + } + if (null == type) { + LOGGER.error("No Type defined for Property " + schema); + } + return toModelName(type); + } + + @Override + public String toOperationId(String operationId) { + // throw exception if method name is empty + if (StringUtils.isEmpty(operationId)) { + throw new RuntimeException("Empty method/operation name (operationId) not allowed"); + } + + operationId = camelize(sanitizeName(operationId), true); + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + String newOperationId = camelize("call_" + operationId, true); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId); + return newOperationId; + } + + return operationId; + } + + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map schemas, OpenAPI openAPI) { + CodegenOperation op = super.fromOperation(path, httpMethod, operation, schemas, openAPI); + if (op.returnType != null) { + op.returnType = normalizeType(op.returnType); + } + + //path is an unescaped variable in the mustache template api.mustache line 82 '<&path>' + op.path = sanitizePath(op.path); + + // Set vendor-extension to be used in template: + // x-codegen-hasMoreRequired + // x-codegen-hasMoreOptional + // x-codegen-hasRequiredParams + CodegenParameter lastRequired = null; + CodegenParameter lastOptional = null; + for (CodegenParameter p : op.allParams) { + if (p.required) { + lastRequired = p; + } else { + lastOptional = p; + } + } + for (CodegenParameter p : op.allParams) { + if (p == lastRequired) { + p.vendorExtensions.put("x-codegen-hasMoreRequired", false); + } else if (p == lastOptional) { + p.vendorExtensions.put("x-codegen-hasMoreOptional", false); + } else { + p.vendorExtensions.put("x-codegen-hasMoreRequired", true); + p.vendorExtensions.put("x-codegen-hasMoreOptional", true); + } + } + op.vendorExtensions.put("x-codegen-hasRequiredParams", lastRequired != null); + + return op; + } + + @Override + public CodegenModel fromModel(String name, Schema schema, Map allSchemas) { + CodegenModel codegenModel = super.fromModel(name, schema, allSchemas); + + boolean hasEnums = getBooleanValue(codegenModel, HAS_ENUMS_EXT_NAME); + if (allSchemas != null && codegenModel != null && codegenModel.parent != null && hasEnums) { + final Schema parentModel = allSchemas.get(codegenModel.parentSchema); + final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, parentModel, allSchemas); + codegenModel = JavaScriptClientCodegen.reconcileInlineEnums(codegenModel, parentCodegenModel); + } + if (schema instanceof ArraySchema) { + final Schema items = ((ArraySchema) schema).getItems(); + if (items != null) { + codegenModel.vendorExtensions.put("x-isArray", true); + codegenModel.vendorExtensions.put("x-itemType", getSchemaType(items)); + } + + } else if (schema instanceof MapSchema && hasSchemaProperties(schema)) { + if (schema.getAdditionalProperties() != null) { + codegenModel.vendorExtensions.put("x-isMap", true); + codegenModel.vendorExtensions.put("x-itemType", getSchemaType((Schema) schema.getAdditionalProperties())); + } else { + String type = schema.getType(); + if (isPrimitiveType(type)){ + codegenModel.vendorExtensions.put("x-isPrimitive", true); + } + } + } + + return codegenModel; + } + + @Override + protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) { + super.addAdditionPropertiesToCodeGenModel(codegenModel, schema); + if (schema.getAdditionalProperties() != null && schema.getAdditionalProperties() instanceof Schema) { + codegenModel.additionalPropertiesType = getSchemaType((Schema) schema.getAdditionalProperties()); + } + } + + private String sanitizePath(String p) { + //prefer replace a ', instead of a fuLL URL encode for readability + return p.replaceAll("'", "%27"); + } + + private String trimBrackets(String s) { + if (s != null) { + int beginIdx = s.charAt(0) == '[' ? 1 : 0; + int endIdx = s.length(); + if (s.charAt(endIdx - 1) == ']') + endIdx--; + return s.substring(beginIdx, endIdx); + } + return null; + } + + private String getModelledType(String dataType) { + return "module:" + (StringUtils.isEmpty(invokerPackage) ? "" : (invokerPackage + "/")) + + (StringUtils.isEmpty(modelPackage) ? "" : (modelPackage + "/")) + dataType; + } + + @Override + public String getDefaultTemplateDir() { + if (useES6) { + return "javascript/es6"; + } + return "javascript"; + } + + private String getJSDocType(CodegenModel cm, CodegenProperty cp) { + if (getBooleanValue(cp, CodegenConstants.IS_CONTAINER_EXT_NAME)) { + if (cp.containerType.equals("array")) + return "Array.<" + getJSDocType(cm, cp.items) + ">"; + else if (cp.containerType.equals("map")) + return "Object."; + } + String dataType = trimBrackets(cp.datatypeWithEnum); + + boolean isEnum = getBooleanValue(cp, IS_ENUM_EXT_NAME); + if (isEnum) { + dataType = cm.classname + '.' + dataType; + } + if (isModelledType(cp)) + dataType = getModelledType(dataType); + return dataType; + } + + private boolean isModelledType(CodegenProperty cp) { + // N.B. enums count as modelled types, file is not modelled (SuperAgent uses some 3rd party library). + boolean isEnum = getBooleanValue(cp, IS_ENUM_EXT_NAME); + return isEnum || !languageSpecificPrimitives.contains(cp.baseType == null ? cp.datatype : cp.baseType); + } + + private String getJSDocType(CodegenParameter cp) { + String dataType = trimBrackets(cp.dataType); + if (isModelledType(cp)) + dataType = getModelledType(dataType); + if (getBooleanValue(cp, CodegenConstants.IS_LIST_CONTAINER_EXT_NAME)) { + return "Array.<" + dataType + ">"; + } else if (getBooleanValue(cp, CodegenConstants.IS_MAP_CONTAINER_EXT_NAME)) { + return "Object."; + } + return dataType; + } + + private boolean isModelledType(CodegenParameter cp) { + // N.B. enums count as modelled types, file is not modelled (SuperAgent uses some 3rd party library). + boolean isEnum = getBooleanValue(cp, IS_ENUM_EXT_NAME); + return isEnum || !languageSpecificPrimitives.contains(cp.baseType == null ? cp.dataType : cp.baseType); + } + + private String getJSDocType(CodegenOperation co) { + String returnType = trimBrackets(co.returnType); + if (returnType != null) { + if (isModelledType(co)) + returnType = getModelledType(returnType); + if (getBooleanValue(co, CodegenConstants.IS_LIST_CONTAINER_EXT_NAME)) { + return "Array.<" + returnType + ">"; + } else if (getBooleanValue(co, CodegenConstants.IS_MAP_CONTAINER_EXT_NAME)) { + return "Object."; + } + } + return returnType; + } + + private boolean isModelledType(CodegenOperation co) { + // This seems to be the only way to tell whether an operation return type is modelled. + return !Boolean.TRUE.equals(co.returnTypeIsPrimitive); + } + + private boolean isPrimitiveType(String type) { + final String[] primitives = {"number", "integer", "string", "boolean", "null"}; + return Arrays.asList(primitives).contains(type); + } + + @SuppressWarnings("unchecked") + @Override + public Map postProcessOperations(Map objs) { + // Generate and store argument list string of each operation into + // vendor-extension: x-codegen-arg-list. + Map operations = (Map) objs.get("operations"); + if (operations != null) { + List ops = (List) operations.get("operation"); + for (CodegenOperation operation : ops) { + List argList = new ArrayList(); + boolean hasOptionalParams = false; + for (CodegenParameter p : operation.allParams) { + if (p.required) { + argList.add(p.paramName); + } else { + hasOptionalParams = true; + } + } + if (hasOptionalParams) { + argList.add("opts"); + } + operation.vendorExtensions.put("x-codegen-arg-list", StringUtils.join(argList, ", ")); + + // Store JSDoc type specification into vendor-extension: x-jsdoc-type. + for (CodegenParameter cp : operation.allParams) { + String jsdocType = getJSDocType(cp); + cp.vendorExtensions.put("x-jsdoc-type", jsdocType); + } + String jsdocType = getJSDocType(operation); + operation.vendorExtensions.put("x-jsdoc-type", jsdocType); + } + } + return objs; + } + + @Override + public Map postProcessOperationsWithModels(Map objs, List allModels) { + objs = super.postProcessOperationsWithModels(objs, allModels); + + // Map the models so we can look them up by name. + Map cgModels = new HashMap<>(); + for (Object model : allModels) { + @SuppressWarnings("unchecked") + CodegenModel cgModel = ((Map) model).get("model"); + /** todo: let's handle this with handlebar helpers + cgModel.vendorExtensions.put("x-indent", indent); + */ + cgModels.put(cgModel.classname, cgModel); + } + + // Provide access to all parameter models. + @SuppressWarnings("unchecked") + Map operations = (Map) objs.get("operations"); + if (operations != null) { + @SuppressWarnings("unchecked") + List ops = (List) operations.get("operation"); + for (CodegenOperation op : ops) { + CodegenModel cgModel = cgModels.get(op.returnBaseType); + if (cgModel != null) + op.vendorExtensions.put("x-codegen-model", cgModel); + op.vendorExtensions.put("x-expect-js-type", getExpectJsItemType(op.returnBaseType)); + op.vendorExtensions.put("x-is-container", op.getIsListContainer() || op.getIsMapContainer()); + /** todo: let's handle this with handlebar helpers + op.vendorExtensions.put("x-indent", indent); + */ + postProcessParameters(op.allParams, cgModels); + postProcessParameters(op.requiredParams, cgModels); + } + } + + // Provide access to all property models. + for (CodegenModel cgModel : cgModels.values()) { + detectRecursiveModel(cgModel.allVars, cgModel.classname, cgModels); + postProcessProperties(cgModel.vars, cgModels); + if (cgModel.allVars != cgModel.vars) { + postProcessProperties(cgModel.allVars, cgModels); + } + } + + return objs; + } + + private void postProcessParameters(Collection cgParams, Map cgModels) { + for (CodegenParameter cgParam : cgParams) { + if (cgParam.items != null) + cgParam.items.vendorExtensions.put("x-is-param-item", true); + if (!cgParam.getIsPrimitiveType() && !cgParam.vendorExtensions.containsKey("x-codegen-model")) { + CodegenModel paramType = cgModels.get(cgParam.baseType); + if (paramType != null) + cgParam.vendorExtensions.put("x-codegen-model", paramType); + } + if (cgParam.getIsEnum()) { + cgParam.vendorExtensions.put("x-first-enum-value", + ((List>) cgParam.allowableValues.get("enumVars")).get(0).get("value")); + } + /** todo: let's handle this with handlebar helpers + cgParam.vendorExtensions.put("x-cache-current-param", cacheCurrentParam); + cgParam.vendorExtensions.put("x-indent", indent); + */ + } + } + + private void postProcessProperties(Collection cgProps, Map cgModels) { + for (CodegenProperty cgProp : cgProps) { + if (!cgProp.getIsPrimitiveType() && !cgProp.vendorExtensions.containsKey("x-codegen-model")) { + CodegenModel propType = cgModels.get(cgProp.complexType); + if (propType != null) + cgProp.vendorExtensions.put("x-codegen-model", propType); + } + if (cgProp.getIsEnum() && cgProp.allowableValues != null && !cgProp.allowableValues.isEmpty()) { + cgProp.vendorExtensions.put("x-first-enum-value", cgProp.allowableValues.values().stream().findFirst().get()); + } + cgProp.vendorExtensions.put("x-expect-js-type", getExpectJsItemType(cgProp.baseType)); + /** todo: let's handle this with handlebar helpers + cgProp.vendorExtensions.put("x-is-param-required", isParamRequired); + cgProp.vendorExtensions.put("x-is-param-list-container", isParamListContainer); + cgProp.vendorExtensions.put("x-is-param-map-container", isParamMapContainer); + cgProp.vendorExtensions.put("x-cache-current-context", cacheCurrentContext); + cgProp.vendorExtensions.put("x-stash-cached-contexts", stashCachedContexts); + cgProp.vendorExtensions.put("x-execute-for-cached-contexts", executeForCachedContexts); + cgProp.vendorExtensions.put("x-execute-for-cached-parent-context", executeForCachedParentContext); + */ + //cgProp.vendorExtensions.put("x-indent", indent); + boolean isContainer = cgProp.getIsListContainer() || cgProp.getIsMapContainer(); + if (isContainer) { + cgProp.vendorExtensions.put("x-is-container", true); + cgProp.items.vendorExtensions.put("x-is-prop-item", true); + postProcessProperties(Collections.singleton(cgProp.items), cgModels); + } + // Ensure string examples are quoted. + if (cgProp.getIsString() && cgProp.example != null // split + && !cgProp.example.startsWith("\"") && !cgProp.example.endsWith("\"")) { + + cgProp.example = '"' + cgProp.example + '"'; + } + } + } + + private String getExpectJsItemType(String baseType) { + String type = baseType; + if (baseType != null) { + switch (baseType) { + case "Boolean": + type = "'boolean'"; + break; + case "Number": + type = "'number'"; + break; + case "String": + type = "'string'"; + break; + } + } + return type; + } + + /** todo: let's handle this with handlebar helpers + // The api-test-param-complex and api-test-property-complex templates need to know whether a parameter is required, + // but they cannot use normal inheritance to determine this, because CodegenProperty.required in the current context + // shadows CodegenParameter.required in the ancestor context. Also, they can't use a vendor extension property on + // the CodegenParameter, as compound tags are not resolved recursively. So the only way is to use Lambdas. + + private CodegenParameter cgParam; + + private Lambda cacheCurrentParam = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + cgParam = (CodegenParameter) frag.context(); + frag.execute(out); + cgParam = null; + } + }; + + private Lambda isParamRequired = new InvertibleLambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + if (cgParam != null && cgParam.required) + frag.execute(out); + } + + @Override + public void executeInverse(Fragment frag, Writer out) throws IOException { + if (cgParam == null || !cgParam.required) + frag.execute(out); + } + }; + + private Lambda isParamListContainer = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + if (cgParam != null && cgParam.isListContainer) + frag.execute(out); + } + }; + + private Lambda isParamMapContainer = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + if (cgParam.isMapContainer) + frag.execute(out); + } + }; + + private Deque> contexts = new ArrayDeque<>(); + + { + contexts.push(new ArrayList<>()); + } + + private Lambda cacheCurrentContext = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + List list = contexts.peek(); + list.add(frag.context()); + frag.execute(out); + list.remove(list.size() - 1); + } + }; + + private Lambda stashCachedContexts = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + contexts.push(new ArrayList<>()); + frag.execute(out); + contexts.pop(); + } + }; + + private Lambda executeForCachedContexts = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + frag.execute(contexts.peek(), out); + } + }; + + private Lambda executeForCachedParentContext = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + List list = contexts.peek(); + int index = list.indexOf(frag.context()); + if (index > 0) + frag.execute(list.get(index - 1), out); + } + }; + + private static final String INDENT = " "; + private static final String NL = System.getProperty("line.separator"); + + private Lambda indent = new Lambda() { + @Override + public void execute(Fragment frag, Writer out) throws IOException { + StringWriter sw = new StringWriter(); + frag.execute(sw); + BufferedReader br = new BufferedReader(new StringReader(sw.toString())); + String line; + while ((line = br.readLine()) != null) { + out.write(INDENT); + out.write(line); + out.write(NL); + } + } + }; + + @Override + public Compiler processCompiler(Compiler compiler) { + return super.processCompiler(compiler).escapeHTML(false); + } + */ + + public void setLoadTestDataFromFile(boolean loadTestDataFromFile) { + this.loadTestDataFromFile = loadTestDataFromFile; + } + + public void setTestDataFile(File testDataFile) { + this.testDataFile = testDataFile; + } + + public void setPreserveLeadingParamChar(boolean preserveLeadingParamChar) { + this.preserveLeadingParamChar = preserveLeadingParamChar; + } + + @SuppressWarnings("unchecked") + @Override + public Map postProcessModels(Map objs) { + objs = super.postProcessModelsEnum(objs); + List models = (List) objs.get("models"); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + + // Collect each model's required property names in *document order*. + // NOTE: can't use 'mandatory' as it is built from ModelImpl.getRequired(), which sorts names + // alphabetically and in any case the document order of 'required' and 'properties' can differ. + List required = new ArrayList<>(); + List allRequired = supportsInheritance || supportsMixins ? new ArrayList() : required; + cm.vendorExtensions.put("x-required", required); + cm.vendorExtensions.put("x-all-required", allRequired); + + for (CodegenProperty var : cm.vars) { + // Add JSDoc @type value for this property. + String jsDocType = getJSDocType(cm, var); + var.vendorExtensions.put("x-jsdoc-type", jsDocType); + + if (Boolean.TRUE.equals(var.required)) { + required.add(var); + } + } + + if (supportsInheritance || supportsMixins) { + for (CodegenProperty var : cm.allVars) { + if (Boolean.TRUE.equals(var.required)) { + allRequired.add(var); + } + } + } + + // set vendor-extension: x-codegen-hasMoreRequired + CodegenProperty lastRequired = null; + for (CodegenProperty var : cm.vars) { + if (var.required) { + lastRequired = var; + } + } + for (CodegenProperty var : cm.vars) { + if (var == lastRequired) { + var.vendorExtensions.put("x-codegen-hasMoreRequired", false); + } else if (var.required) { + var.vendorExtensions.put("x-codegen-hasMoreRequired", true); + } + } + } + return objs; + } + + public void detectRecursiveModel(List allVars, String className, Map allModels) { + if (allVars == null || allVars.isEmpty()) { + return; + } + for (CodegenProperty codegenProperty : allVars) { + if (codegenProperty.getIsPrimitiveType()) { + continue; + } + if (codegenProperty.getIsListContainer() || codegenProperty.getIsMapContainer()) { + if (className.equalsIgnoreCase(codegenProperty.items.datatype)) { + codegenProperty.items.vendorExtensions.put("x-is-recursive-model", Boolean.TRUE); + continue; + } + } + if (className.equalsIgnoreCase(codegenProperty.datatype)) { + codegenProperty.vendorExtensions.put("x-is-recursive-model", Boolean.TRUE); + continue; + } + } + } + + @Override + protected void addImport(CodegenModel model, String type) { + if (type != null && !model.classname.equals(type) && needToImport(type)) { + model.imports.add(type); + } + } + + @Override + protected boolean needToImport(String type) { + return !defaultIncludes.contains(type) + && !languageSpecificPrimitives.contains(type); + } + + private static CodegenModel reconcileInlineEnums(CodegenModel codegenModel, CodegenModel parentCodegenModel) { + // This generator uses inline classes to define enums, which breaks when + // dealing with models that have subTypes. To clean this up, we will analyze + // the parent and child models, look for enums that match, and remove + // them from the child models and leave them in the parent. + // Because the child models extend the parents, the enums will be available via the parent. + + // Only bother with reconciliation if the parent model has enums. + boolean hasEnums = getBooleanValue(parentCodegenModel, HAS_ENUMS_EXT_NAME); + if (hasEnums) { + + // Get the properties for the parent and child models + final List parentModelCodegenProperties = parentCodegenModel.vars; + List codegenProperties = codegenModel.vars; + + // Iterate over all of the parent model properties + boolean removedChildEnum = false; + for (CodegenProperty parentModelCodegenProperty : parentModelCodegenProperties) { + // Look for enums + boolean isEnum = getBooleanValue(parentModelCodegenProperty, IS_ENUM_EXT_NAME); + if (isEnum) { + // Now that we have found an enum in the parent class, + // and search the child class for the same enum. + Iterator iterator = codegenProperties.iterator(); + while (iterator.hasNext()) { + CodegenProperty codegenProperty = iterator.next(); + if (getBooleanValue(codegenProperty, IS_ENUM_EXT_NAME) && codegenProperty.equals(parentModelCodegenProperty)) { + // We found an enum in the child class that is + // a duplicate of the one in the parent, so remove it. + iterator.remove(); + removedChildEnum = true; + } + } + } + } + + if(removedChildEnum) { + // If we removed an entry from this model's vars, we need to ensure hasMore is updated + int count = 0, numVars = codegenProperties.size(); + for(CodegenProperty codegenProperty : codegenProperties) { + count += 1; + codegenProperty.getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, (count < numVars) ? true : false); + } + codegenModel.vars = codegenProperties; + } + } + + return codegenModel; + } + + private static String sanitizePackageName(String packageName) { // FIXME parameter should not be assigned. Also declare it as "final" + packageName = packageName.trim(); + packageName = packageName.replaceAll("[^a-zA-Z0-9_\\.]", "_"); + if(Strings.isNullOrEmpty(packageName)) { + return "invalidPackageName"; + } + return packageName; + } + + @Override + public String toEnumName(CodegenProperty property) { + return sanitizeName(camelize(property.name)) + "Enum"; + } + + @Override + public String toEnumVarName(String value, String datatype) { + if (value.length() == 0) { + return "empty"; + } + + // for symbol, e.g. $, # + if (getSymbolName(value) != null) { + return (getSymbolName(value)).toUpperCase(); + } + + return toVarName(value); + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("Integer".equals(datatype) || "Number".equals(datatype) || "Boolean".equals(datatype)) { + return value; + } else { + return "\"" + escapeText(value) + "\""; + } + } + + + @Override + public String escapeQuotationMark(String input) { + // remove ', " to avoid code injection + return input.replace("\"", "").replace("'", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } + +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/kotlin/AbstractKotlinCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/kotlin/AbstractKotlinCodegen.java index cbfadce32b..d42ae0a90c 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/kotlin/AbstractKotlinCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/kotlin/AbstractKotlinCodegen.java @@ -1,14 +1,20 @@ package io.swagger.codegen.v3.generators.kotlin; +import com.github.jknack.handlebars.helper.ConditionalHelpers; import io.swagger.codegen.v3.CliOption; import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.MapSchema; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.github.jknack.handlebars.helper.StringHelpers; +import com.github.jknack.handlebars.Handlebars; import java.io.File; import java.util.Arrays; @@ -17,14 +23,12 @@ import java.util.Map; import java.util.Set; -public abstract class AbstractKotlinCodegen extends DefaultCodegenConfig { +public abstract class AbstractKotlinCodegen extends DefaultCodegenConfig { private static Logger LOGGER = LoggerFactory.getLogger(AbstractKotlinCodegen.class); private Set instantiationLibraryFunction; - - protected String artifactId; protected String artifactVersion = "1.0.0"; protected String groupId = "io.swagger"; @@ -35,13 +39,11 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegenConfig { protected String apiDocPath = "docs/"; protected String modelDocPath = "docs/"; - protected CodegenConstants.ENUM_PROPERTY_NAMING_TYPE enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.camelCase; - public AbstractKotlinCodegen() { super(); supportsInheritance = true; - languageSpecificPrimitives = new HashSet(Arrays.asList( + languageSpecificPrimitives = new HashSet<>(Arrays.asList( "kotlin.Any", "kotlin.Byte", "kotlin.Short", @@ -55,13 +57,22 @@ public AbstractKotlinCodegen() { "kotlin.Array", "kotlin.collections.List", "kotlin.collections.Map", - "kotlin.collections.Set" + "kotlin.collections.Set", + "kotlin.ByteArray", + "kotlin.CharArray", + "kotlin.ShortArray", + "kotlin.IntArray", + "kotlin.LongArray", + "kotlin.FloatArray", + "kotlin.DoubleArray", + "kotlin.BooleanArray" )); // this includes hard reserved words defined by https://github.com/JetBrains/kotlin/blob/master/core/descriptors/src/org/jetbrains/kotlin/renderer/KeywordStringsGenerated.java // as well as keywords from https://kotlinlang.org/docs/reference/keyword-reference.html - reservedWords = new HashSet(Arrays.asList( + reservedWords = new HashSet<>(Arrays.asList( "abstract", + "actual", "annotation", "as", "break", @@ -78,6 +89,7 @@ public AbstractKotlinCodegen() { "do", "else", "enum", + "expect", "external", "false", "final", @@ -126,7 +138,7 @@ public AbstractKotlinCodegen() { "while" )); - defaultIncludes = new HashSet(Arrays.asList( + defaultIncludes = new HashSet<>(Arrays.asList( "kotlin.Byte", "kotlin.Short", "kotlin.Int", @@ -138,15 +150,23 @@ public AbstractKotlinCodegen() { "kotlin.Array", "kotlin.collections.List", "kotlin.collections.Set", - "kotlin.collections.Map" + "kotlin.collections.Map", + "kotlin.ByteArray", + "kotlin.CharArray", + "kotlin.ShortArray", + "kotlin.IntArray", + "kotlin.LongArray", + "kotlin.FloatArray", + "kotlin.DoubleArray", + "kotlin.BooleanArray" )); - instantiationLibraryFunction = new HashSet(Arrays.asList( + instantiationLibraryFunction = new HashSet<>(Arrays.asList( "arrayOf", "mapOf" )); - typeMapping = new HashMap(); + typeMapping = new HashMap<>(); typeMapping.put("string", "kotlin.String"); typeMapping.put("boolean", "kotlin.Boolean"); typeMapping.put("integer", "kotlin.Int"); @@ -155,21 +175,22 @@ public AbstractKotlinCodegen() { typeMapping.put("double", "kotlin.Double"); typeMapping.put("number", "java.math.BigDecimal"); typeMapping.put("date-time", "java.time.LocalDateTime"); - typeMapping.put("date", "java.time.LocalDateTime"); + typeMapping.put("date", "java.time.LocalDate"); typeMapping.put("file", "java.io.File"); typeMapping.put("array", "kotlin.Array"); typeMapping.put("list", "kotlin.Array"); typeMapping.put("map", "kotlin.collections.Map"); typeMapping.put("object", "kotlin.Any"); typeMapping.put("binary", "kotlin.Array"); - typeMapping.put("Date", "java.time.LocalDateTime"); + typeMapping.put("Date", "java.time.LocalDate"); typeMapping.put("DateTime", "java.time.LocalDateTime"); + typeMapping.put("ByteArray", "kotlin.ByteArray"); instantiationTypes.put("array", "arrayOf"); instantiationTypes.put("list", "arrayOf"); instantiationTypes.put("map", "mapOf"); - importMapping = new HashMap(); + importMapping = new HashMap<>(); importMapping.put("BigDecimal", "java.math.BigDecimal"); importMapping.put("UUID", "java.util.UUID"); importMapping.put("File", "java.io.File"); @@ -181,6 +202,7 @@ public AbstractKotlinCodegen() { importMapping.put("LocalTime", "java.time.LocalTime"); specialCharReplacements.put(";", "Semicolon"); + specialCharReplacements.put(":", "Colon"); cliOptions.clear(); addOption(CodegenConstants.SOURCE_FOLDER, CodegenConstants.SOURCE_FOLDER_DESC, sourceFolder); @@ -188,9 +210,6 @@ public AbstractKotlinCodegen() { addOption(CodegenConstants.GROUP_ID, "Generated artifact package's organization (i.e. maven groupId).", groupId); addOption(CodegenConstants.ARTIFACT_ID, "Generated artifact id (name of jar).", artifactId); addOption(CodegenConstants.ARTIFACT_VERSION, "Generated artifact's package version.", artifactVersion); - - CliOption enumPropertyNamingOpt = new CliOption(CodegenConstants.ENUM_PROPERTY_NAMING, CodegenConstants.ENUM_PROPERTY_NAMING_DESC); - cliOptions.add(enumPropertyNamingOpt.defaultValue(enumPropertyNaming.name())); } protected void addOption(String key, String description) { @@ -241,24 +260,10 @@ public String escapeUnsafeCharacters(String input) { return input.replace("*/", "*_/").replace("/*", "/_*"); } - public CodegenConstants.ENUM_PROPERTY_NAMING_TYPE getEnumPropertyNaming() { - return this.enumPropertyNaming; - } - - /** - * Sets the naming convention for Kotlin enum properties - * - * @param enumPropertyNamingType The string representation of the naming convention, as defined by {@link CodegenConstants.ENUM_PROPERTY_NAMING_TYPE} - */ - public void setEnumPropertyNaming(final String enumPropertyNamingType) { - try { - this.enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.valueOf(enumPropertyNamingType); - } catch (IllegalArgumentException ex) { - StringBuilder sb = new StringBuilder(enumPropertyNamingType + " is an invalid enum property naming option. Please choose from:"); - for (CodegenConstants.ENUM_PROPERTY_NAMING_TYPE t : CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.values()) { - sb.append("\n ").append(t.name()); - } - throw new RuntimeException(sb.toString()); + protected void updateCodegenModelEnumVars(CodegenModel codegenModel) { + super.updateCodegenModelEnumVars(codegenModel); + for (CodegenProperty var : codegenModel.allVars) { + updateCodegenPropertyEnum(var); } } @@ -272,7 +277,7 @@ public void setEnumPropertyNaming(final String enumPropertyNamingType) { public String getTypeDeclaration(Schema propertySchema) { if (propertySchema instanceof ArraySchema) { return getArrayTypeDeclaration((ArraySchema) propertySchema); - } else if (propertySchema instanceof MapSchema && hasSchemaProperties(propertySchema)) { + } else if (propertySchema instanceof MapSchema && hasSchemaProperties(propertySchema)) { Schema inner = (Schema) propertySchema.getAdditionalProperties(); if (inner == null) { LOGGER.warn(propertySchema.getName() + "(map property) does not have a proper inner type defined"); @@ -335,10 +340,6 @@ public Map postProcessModels(Map objs) { public void processOpts() { super.processOpts(); - if (additionalProperties.containsKey(CodegenConstants.ENUM_PROPERTY_NAMING)) { - setEnumPropertyNaming((String) additionalProperties.get(CodegenConstants.ENUM_PROPERTY_NAMING)); - } - if (additionalProperties.containsKey(CodegenConstants.SOURCE_FOLDER)) { this.setSourceFolder((String) additionalProperties.get(CodegenConstants.SOURCE_FOLDER)); } else { @@ -421,36 +422,34 @@ public String toEnumVarName(String value, String datatype) { modified = sanitizeKotlinSpecificNames(modified); } - switch (getEnumPropertyNaming()) { - case original: - // NOTE: This is provided as a last-case allowance, but will still result in reserved words being escaped. - modified = value; - break; - case camelCase: - // NOTE: Removes hyphens and underscores - modified = camelize(modified, true); - break; - case PascalCase: - // NOTE: Removes hyphens and underscores - String result = camelize(modified); - modified = titleCase(result); - break; - case snake_case: - // NOTE: Removes hyphens - modified = underscore(modified); - break; - case UPPERCASE: - modified = modified.toUpperCase(); - break; - } + modified = modified.toUpperCase(); - if (reservedWords.contains(modified)) { + if (isReservedWord(modified)) { return escapeReservedWord(modified); } return modified; } + @Override + public String toEnumValue(String value, String datatype) { + if (isPrimivite(datatype)) { + return value; + } + return super.toEnumValue(value, datatype); + } + + @Override + public boolean isPrimivite(String datatype) { + return "kotlin.Byte".equalsIgnoreCase(datatype) + || "kotlin.Short".equalsIgnoreCase(datatype) + || "kotlin.Int".equalsIgnoreCase(datatype) + || "kotlin.Long".equalsIgnoreCase(datatype) + || "kotlin.Float".equalsIgnoreCase(datatype) + || "kotlin.Double".equalsIgnoreCase(datatype) + || "kotlin.Boolean".equalsIgnoreCase(datatype); + } + @Override public String toInstantiationType(Schema p) { if (p instanceof ArraySchema) { @@ -498,11 +497,13 @@ public String toModelName(final String name) { String modifiedName = name.replaceAll("\\.", ""); modifiedName = sanitizeKotlinSpecificNames(modifiedName); - if (reservedWords.contains(modifiedName)) { - modifiedName = escapeReservedWord(modifiedName); + modifiedName = titleCase(modifiedName); + + if (modifiedName.equalsIgnoreCase("Companion")) { + modifiedName = "_" + modifiedName; } - return titleCase(modifiedName); + return modifiedName; } @Override @@ -510,6 +511,18 @@ public String toVarName(String name) { return super.toVarName(sanitizeKotlinSpecificNames(name)); } + @Override + public String toEnumName(CodegenProperty property) { + return StringUtils.capitalize(property.name); + } + + @Override + public void addHandlebarHelpers(Handlebars handlebars) { + super.addHandlebarHelpers(handlebars); + handlebars.registerHelpers(StringHelpers.class); + handlebars.registerHelpers(ConditionalHelpers.class); + } + /** * Provides a strongly typed declaration for simple arrays of some type and arrays of arrays of some type. * @@ -578,11 +591,11 @@ protected boolean isReservedWord(String word) { protected boolean needToImport(String type) { // provides extra protection against improperly trying to import language primitives and java types boolean imports = - !type.startsWith("kotlin.") && - !type.startsWith("java.") && - !defaultIncludes.contains(type) && - !languageSpecificPrimitives.contains(type) && - !instantiationLibraryFunction.contains(type); + !type.startsWith("kotlin.") && + !type.startsWith("java.") && + !defaultIncludes.contains(type) && + !languageSpecificPrimitives.contains(type) && + !instantiationLibraryFunction.contains(type); return imports; } diff --git a/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegen.java index cdd7fc572a..61509bdd89 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegen.java @@ -1,5 +1,7 @@ package io.swagger.codegen.v3.generators.kotlin; +import com.github.jknack.handlebars.Handlebars; +import com.github.jknack.handlebars.helper.ConditionalHelpers; import io.swagger.codegen.v3.CliOption; import io.swagger.codegen.v3.CodegenType; import io.swagger.codegen.v3.SupportingFile; @@ -10,11 +12,9 @@ import java.util.HashMap; import java.util.Map; -import org.apache.commons.lang3.StringUtils; - public class KotlinClientCodegen extends AbstractKotlinCodegen { - public static final String DATE_LIBRARY = "dateLibrary"; + public static final String DATE_LIBRARY = "dateLibrary"; private static Logger LOGGER = LoggerFactory.getLogger(KotlinClientCodegen.class); protected String dateLibrary = DateLibrary.JAVA8.value; @@ -80,17 +80,13 @@ public void setDateLibrary(String library) { @Override public void processOpts() { - super.processOpts(); - - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } + super.processOpts(); if (additionalProperties.containsKey(DATE_LIBRARY)) { setDateLibrary(additionalProperties.get(DATE_LIBRARY).toString()); } - if (DateLibrary.THREETENBP.value.equals(dateLibrary)) { + if (DateLibrary.THREETENBP.value.equals(dateLibrary)) { additionalProperties.put(DateLibrary.THREETENBP.value, true); typeMapping.put("date", "LocalDate"); typeMapping.put("DateTime", "LocalDateTime"); @@ -122,5 +118,8 @@ public void processOpts() { supportingFiles.add(new SupportingFile("infrastructure/ResponseExtensions.kt.mustache", infrastructureFolder, "ResponseExtensions.kt")); supportingFiles.add(new SupportingFile("infrastructure/Serializer.kt.mustache", infrastructureFolder, "Serializer.kt")); supportingFiles.add(new SupportingFile("infrastructure/Errors.kt.mustache", infrastructureFolder, "Errors.kt")); + supportingFiles.add(new SupportingFile("infrastructure/LocalDateAdapter.kt.mustache", infrastructureFolder, "LocalDateAdapter.kt")); + supportingFiles.add(new SupportingFile("infrastructure/LocalDateTimeAdapter.kt.mustache", infrastructureFolder, "LocalDateTimeAdapter.kt")); + } -} +} \ No newline at end of file diff --git a/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinServerCodegen.java index 917f6d282f..7d8800b51e 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/kotlin/KotlinServerCodegen.java @@ -18,8 +18,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import com.github.jknack.handlebars.helper.StringHelpers; -import com.github.jknack.handlebars.Handlebars; import org.apache.commons.lang3.StringUtils; import static java.util.Collections.singletonMap; @@ -162,10 +160,6 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - if (!additionalProperties.containsKey(GENERATE_APIS)) { additionalProperties.put(GENERATE_APIS, true); } @@ -232,12 +226,6 @@ public void processOpts() { supportingFiles.add(new SupportingFile("ApiKeyAuth.kt.mustache", infrastructureFolder, "ApiKeyAuth.kt")); } - @Override - public void addHandlebarHelpers(Handlebars handlebars) { - super.addHandlebarHelpers(handlebars); - handlebars.registerHelpers(StringHelpers.class); - } - @Override public String getDefaultTemplateDir() { return "kotlin-server"; diff --git a/src/main/java/io/swagger/codegen/v3/generators/nodejs/NodeJSServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/nodejs/NodeJSServerCodegen.java index 7b68937ae0..24a29d3724 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/nodejs/NodeJSServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/nodejs/NodeJSServerCodegen.java @@ -1,5 +1,6 @@ package io.swagger.codegen.v3.generators.nodejs; +import io.swagger.codegen.v3.*; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; @@ -9,13 +10,7 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import io.swagger.codegen.v3.CliOption; -import io.swagger.codegen.v3.CodegenConstants; -import io.swagger.codegen.v3.CodegenOperation; -import io.swagger.codegen.v3.CodegenParameter; -import io.swagger.codegen.v3.CodegenResponse; -import io.swagger.codegen.v3.CodegenType; -import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.generators.OperationParameters; import io.swagger.codegen.v3.utils.URLPathUtil; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -23,6 +18,7 @@ import io.swagger.v3.oas.models.Paths; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.core.util.Yaml; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,15 +26,8 @@ import java.io.IOException; import java.math.BigDecimal; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.regex.Pattern; public class NodeJSServerCodegen extends DefaultCodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(NodeJSServerCodegen.class); @@ -171,7 +160,7 @@ public String apiFilename(String templateName, String tag) { if ( templateName.equals("service.mustache") ) { String stringToMatch = File.separator + "controllers" + File.separator; String replacement = File.separator + implFolder + File.separator; - result = result.replaceAll(Pattern.quote(stringToMatch), replacement); + result = StringUtils.replace(result, stringToMatch, replacement); } return result; } @@ -296,11 +285,6 @@ private static List> sortOperationsByPath(List codegenContents) { + if (codegenContents.isEmpty()) { + CodegenContent content = new CodegenContent(); + content.getParameters().addAll(codegenOperation.allParams); + codegenContents.add(content); + + codegenOperation.getContents().add(content); + return; + } + for (CodegenContent content : codegenContents) { + addParameters(content, codegenOperation.bodyParams); + addParameters(content, codegenOperation.queryParams); + addParameters(content, codegenOperation.pathParams); + addParameters(content, codegenOperation.headerParams); + addParameters(content, codegenOperation.cookieParams); + } + for (CodegenContent content : codegenContents) { + OperationParameters.addHasMore(content.getParameters()); + } + codegenOperation.getContents().addAll(codegenContents); + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIGenerator.java b/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIGenerator.java index d946ceeae8..c7cd91a760 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIGenerator.java +++ b/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIGenerator.java @@ -1,7 +1,6 @@ package io.swagger.codegen.v3.generators.openapi; import io.swagger.codegen.v3.CliOption; -import io.swagger.codegen.v3.CodegenConstants; import io.swagger.codegen.v3.CodegenType; import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; @@ -20,10 +19,13 @@ public class OpenAPIGenerator extends DefaultCodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIGenerator.class); public static final String OUTPUT_NAME = "outputFile"; + public static final String FLATTEN_SPEC = "flattenSpec"; public static final String OPENAPI_FILENAME_DEFAULT_JSON = "openapi.json"; - protected String outputFile = OPENAPI_FILENAME_DEFAULT_JSON; + private String outputFile = OPENAPI_FILENAME_DEFAULT_JSON; + + protected boolean flattenSpec = true; public OpenAPIGenerator() { super(); @@ -31,10 +33,20 @@ public OpenAPIGenerator() { cliOptions.add(new CliOption(OUTPUT_NAME, "output filename") - .defaultValue(OPENAPI_FILENAME_DEFAULT_JSON)); + .defaultValue(getOutputFile())); + + cliOptions.add(new CliOption(FLATTEN_SPEC, + "flatten the spec by moving all inline complex schema to components, and add a ref in element", + "boolean") + .defaultValue(Boolean.TRUE.toString())); + supportingFiles.add(new SupportingFile("README.md", "", "README.md")); } + protected String getOutputFile() { + return outputFile; + } + @Override public CodegenType getTag() { return CodegenType.DOCUMENTATION; @@ -53,7 +65,12 @@ public String getHelp() { @Override public void preprocessOpenAPI(OpenAPI openAPI) { super.preprocessOpenAPI(openAPI); - String outputString = Json.pretty(openAPI); + final String outputString; + if (flattenSpec) { + outputString = Json.pretty(openAPI); + } else { + outputString = Json.pretty(this.unflattenedOpenAPI); + } try { String outputFile = outputFolder + File.separator + this.outputFile; @@ -68,11 +85,19 @@ public void preprocessOpenAPI(OpenAPI openAPI) { public void processOpts() { super.processOpts(); - embeddedTemplateDir = templateDir = getTemplateDir(); - if (additionalProperties.containsKey(OUTPUT_NAME) && !StringUtils.isBlank((String) additionalProperties.get(OUTPUT_NAME))) { setOutputFile((String) additionalProperties.get(OUTPUT_NAME)); } + + if (additionalProperties + .containsKey(FLATTEN_SPEC) && + ( + !(additionalProperties.get(FLATTEN_SPEC) instanceof String) || + !StringUtils.isBlank((String) additionalProperties.get(FLATTEN_SPEC)) + ) + ) { + this.flattenSpec = Boolean.valueOf(additionalProperties.get(FLATTEN_SPEC).toString()); + } } public void setOutputFile(String outputFile) { @@ -105,4 +130,9 @@ public String escapeUnsafeCharacters(String input) { protected void setTemplateEngine() { templateEngine = new HandlebarTemplateEngine(this); } + + @Override + public boolean needsUnflattenedSpec() { + return true; + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIYamlGenerator.java b/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIYamlGenerator.java index b494242e0e..2287a8c7ae 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIYamlGenerator.java +++ b/src/main/java/io/swagger/codegen/v3/generators/openapi/OpenAPIYamlGenerator.java @@ -1,43 +1,19 @@ package io.swagger.codegen.v3.generators.openapi; -import io.swagger.codegen.v3.CliOption; -import io.swagger.codegen.v3.CodegenType; -import io.swagger.codegen.v3.SupportingFile; -import io.swagger.codegen.v3.generators.DefaultCodegenConfig; import io.swagger.v3.core.util.Yaml; import io.swagger.v3.oas.models.OpenAPI; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -public class OpenAPIYamlGenerator extends DefaultCodegenConfig { +public class OpenAPIYamlGenerator extends OpenAPIGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIYamlGenerator.class); - public static final String OUTPUT_NAME = "outputFile"; + public static final String OPENAPI_FILENAME_DEFAULT_YAML = "openapi.yaml"; - public static final String SWAGGER_FILENAME_DEFAULT_YAML = "openapi.yaml"; - - protected String outputFile = SWAGGER_FILENAME_DEFAULT_YAML; - - - public OpenAPIYamlGenerator() { - super(); - outputFolder = "generated-code/openapi"; - - cliOptions.add(new CliOption(OUTPUT_NAME, - "output filename") - .defaultValue(SWAGGER_FILENAME_DEFAULT_YAML)); - - supportingFiles.add(new SupportingFile("README.md", "", "README.md")); - } - - @Override - public CodegenType getTag() { - return CodegenType.DOCUMENTATION; - } + private String outputFile = OPENAPI_FILENAME_DEFAULT_YAML; @Override public String getName() { @@ -50,19 +26,8 @@ public String getHelp() { } @Override - public void processOpts() { - super.processOpts(); - - embeddedTemplateDir = templateDir = getTemplateDir(); - - if (additionalProperties.containsKey(OUTPUT_NAME) && !StringUtils.isBlank((String) additionalProperties.get(OUTPUT_NAME))) { - setOutputFile((String) additionalProperties.get(OUTPUT_NAME)); - } - } - - @Override - public String getDefaultTemplateDir() { - return "openapi"; + protected String getOutputFile() { + return outputFile; } public void setOutputFile(String outputFile) { @@ -71,26 +36,20 @@ public void setOutputFile(String outputFile) { @Override public void preprocessOpenAPI(OpenAPI openAPI) { - super.preprocessOpenAPI(openAPI); + this.openAPI = openAPI; try { - String valueAsString = Yaml.pretty(openAPI); + final String outputString; + if (flattenSpec) { + outputString = Yaml.pretty(openAPI); + } else { + outputString = Yaml.pretty(this.unflattenedOpenAPI); + } + String outputFile = outputFolder + File.separator + this.outputFile; - FileUtils.writeStringToFile(new File(outputFile), valueAsString); + FileUtils.writeStringToFile(new File(outputFile), outputString); LOGGER.debug("wrote file to " + outputFile); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } - - @Override - public String escapeQuotationMark(String input) { - // just return the original string - return input; - } - - @Override - public String escapeUnsafeCharacters(String input) { - // just return the original string - return input; - } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/php/AbstractPhpCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/php/AbstractPhpCodegen.java index 51dad7e72d..62c8b9f953 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/php/AbstractPhpCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/php/AbstractPhpCodegen.java @@ -251,7 +251,7 @@ public String toSrcPath(String packageName, String basePath) { } @Override - public String escapeReservedWord(String name) { + public String escapeReservedWord(String name) { if(this.reservedWordsMappings().containsKey(name)) { return this.reservedWordsMappings().get(name); } diff --git a/src/main/java/io/swagger/codegen/v3/generators/php/PhpClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/php/PhpClientCodegen.java index 85813aa33b..daec128c11 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/php/PhpClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/php/PhpClientCodegen.java @@ -2,30 +2,40 @@ import io.swagger.codegen.v3.CliOption; import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.CodegenParameter; import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenSecurity; import io.swagger.codegen.v3.CodegenType; import io.swagger.codegen.v3.SupportingFile; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.BooleanSchema; +import io.swagger.v3.oas.models.media.DateSchema; +import io.swagger.v3.oas.models.media.DateTimeSchema; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.NumberSchema; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.parser.util.SchemaTypeUtil; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.HashSet; import java.util.regex.Matcher; -import io.swagger.v3.oas.models.media.*; -import io.swagger.v3.parser.util.SchemaTypeUtil; -import org.apache.commons.lang3.StringUtils; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; public class PhpClientCodegen extends DefaultCodegenConfig { @@ -101,7 +111,6 @@ public PhpClientCodegen() { instantiationTypes.put("array", "array"); instantiationTypes.put("map", "map"); - // provide primitives to mustache template List sortedLanguageSpecificPrimitives= new ArrayList(languageSpecificPrimitives); Collections.sort(sortedLanguageSpecificPrimitives); @@ -128,6 +137,7 @@ public PhpClientCodegen() { typeMapping.put("object", "object"); typeMapping.put("binary", "string"); typeMapping.put("ByteArray", "string"); + typeMapping.put("BigDecimal", "float"); typeMapping.put("UUID", "string"); cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC)); @@ -141,6 +151,7 @@ public PhpClientCodegen() { cliOptions.add(new CliOption(CodegenConstants.GIT_USER_ID, CodegenConstants.GIT_USER_ID_DESC)); cliOptions.add(new CliOption(COMPOSER_PROJECT_NAME, "The project name used in the composer package name. The template uses {{composerVendorName}}/{{composerProjectName}} for the composer package name. e.g. petstore-client. IMPORTANT NOTE (2016/03): composerProjectName will be deprecated and replaced by gitRepoId in the next swagger-codegen release")); cliOptions.add(new CliOption(CodegenConstants.GIT_REPO_ID, CodegenConstants.GIT_REPO_ID_DESC)); + cliOptions.add(new CliOption(CodegenConstants.GIT_REPO_BASE_URL, CodegenConstants.GIT_REPO_BASE_URL_DESC)); cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, "The version to use in the composer package version field. e.g. 1.2.3")); cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "hides the timestamp when files were generated") .defaultValue(Boolean.TRUE.toString())); @@ -239,11 +250,6 @@ public void processOpts() { super.processOpts(); - embeddedTemplateDir = getTemplateDir(); - if (StringUtils.isBlank(templateDir)) { - templateDir = embeddedTemplateDir; - } - if (additionalProperties.containsKey(PACKAGE_PATH)) { this.setPackagePath((String) additionalProperties.get(PACKAGE_PATH)); } else { @@ -274,6 +280,12 @@ public void processOpts() { additionalProperties.put(CodegenConstants.GIT_REPO_ID, gitRepoId); } + if (additionalProperties.containsKey(CodegenConstants.GIT_REPO_BASE_URL)) { + this.setGitRepoBaseURL((String) additionalProperties.get(CodegenConstants.GIT_REPO_BASE_URL)); + } else { + additionalProperties.put(CodegenConstants.GIT_REPO_BASE_URL, gitRepoBaseURL); + } + if (additionalProperties.containsKey(CodegenConstants.ARTIFACT_VERSION)) { this.setArtifactVersion((String) additionalProperties.get(CodegenConstants.ARTIFACT_VERSION)); } else { @@ -283,6 +295,12 @@ public void processOpts() { if (additionalProperties.containsKey(VARIABLE_NAMING_CONVENTION)) { this.setParameterNamingConvention((String) additionalProperties.get(VARIABLE_NAMING_CONVENTION)); } + if (StringUtils.isBlank(composerVendorName) && additionalProperties.get(CodegenConstants.GIT_USER_ID) != null) { + additionalProperties.put(CodegenConstants.GIT_USER_ID, StringUtils.lowerCase(additionalProperties.get(CodegenConstants.GIT_USER_ID).toString())); + } + if (StringUtils.isBlank(composerProjectName) && additionalProperties.get(CodegenConstants.GIT_REPO_ID) != null) { + additionalProperties.put(CodegenConstants.GIT_REPO_ID, StringUtils.lowerCase(additionalProperties.get(CodegenConstants.GIT_REPO_ID).toString())); + } additionalProperties.put("escapedInvokerPackage", invokerPackage.replace("\\", "\\\\")); @@ -446,6 +464,12 @@ public void setComposerProjectName(String composerProjectName) { this.composerProjectName = composerProjectName; } + @Override + protected void processMapSchema(CodegenModel codegenModel, String name, Schema schema) { + super.processMapSchema(codegenModel, name, schema); + addVars(codegenModel, schema.getProperties(), schema.getRequired()); + } + @Override public String toVarName(String name) { // sanitize name @@ -750,4 +774,17 @@ public String escapeUnsafeCharacters(String input) { return input.replace("*/", "*_/").replace("/*", "/_*"); } + @Override + public List fromSecurity(Map securitySchemeMap) { + final List securities = super.fromSecurity(securitySchemeMap); + securities.forEach(codegenSecurity -> { + final Map extensions = codegenSecurity.getVendorExtensions(); + if (extensions != null && extensions.containsKey("x-token-example")) { + additionalProperties.put("x-token-example", extensions.get("x-token-example")); + return; + } + }); + return securities; + } + } diff --git a/src/main/java/io/swagger/codegen/v3/generators/python/PythonClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/python/PythonClientCodegen.java index 13f71d8c32..2eadf6071e 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/python/PythonClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/python/PythonClientCodegen.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; @@ -86,6 +87,7 @@ public PythonClientCodegen() { languageSpecificPrimitives.add("datetime"); languageSpecificPrimitives.add("date"); languageSpecificPrimitives.add("object"); + languageSpecificPrimitives.add("binary_type"); instantiationTypes.put("map", "dict"); @@ -93,6 +95,7 @@ public PythonClientCodegen() { typeMapping.put("integer", "int"); typeMapping.put("float", "float"); typeMapping.put("number", "float"); + typeMapping.put("BigDecimal", "float"); typeMapping.put("long", "int"); typeMapping.put("double", "float"); typeMapping.put("array", "list"); @@ -123,7 +126,7 @@ public PythonClientCodegen() { "assert", "else", "if", "pass", "yield", "break", "except", "import", "print", "class", "exec", "in", "raise", "continue", "finally", "is", "return", "def", "for", "lambda", "try", "self", "nonlocal", "None", "True", "nonlocal", - "float", "int", "str", "date", "datetime")); + "float", "int", "str", "date", "datetime", "False", "await", "async")); regexModifiers = new HashMap(); regexModifiers.put('i', "IGNORECASE"); @@ -159,8 +162,6 @@ public void processOpts() { super.processOpts(); Boolean excludeTests = false; - embeddedTemplateDir = templateDir = getTemplateDir(); - if(additionalProperties.containsKey(CodegenConstants.EXCLUDE_TESTS)) { excludeTests = Boolean.valueOf(additionalProperties.get(CodegenConstants.EXCLUDE_TESTS).toString()); } @@ -173,7 +174,8 @@ public void processOpts() { } if (additionalProperties.containsKey(CodegenConstants.PROJECT_NAME)) { - setProjectName((String) additionalProperties.get(CodegenConstants.PROJECT_NAME)); + String projectName = (String) additionalProperties.get(CodegenConstants.PROJECT_NAME); + setProjectName(projectName.replaceAll("[^a-zA-Z0-9\\s\\-_]","")); } else { // default: set project based on package name @@ -200,16 +202,18 @@ public void processOpts() { setPackageUrl((String) additionalProperties.get(PACKAGE_URL)); } + final String packageFolder = packageName.replace('.', File.separatorChar); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("tox.mustache", "", "tox.ini")); supportingFiles.add(new SupportingFile("test-requirements.mustache", "", "test-requirements.txt")); supportingFiles.add(new SupportingFile("requirements.mustache", "", "requirements.txt")); - supportingFiles.add(new SupportingFile("configuration.mustache", packageName, "configuration.py")); - supportingFiles.add(new SupportingFile("__init__package.mustache", packageName, "__init__.py")); - supportingFiles.add(new SupportingFile("__init__model.mustache", packageName + File.separatorChar + modelPackage, "__init__.py")); - supportingFiles.add(new SupportingFile("__init__api.mustache", packageName + File.separatorChar + apiPackage, "__init__.py")); + supportingFiles.add(new SupportingFile("configuration.mustache", packageFolder, "configuration.py")); + supportingFiles.add(new SupportingFile("__init__package.mustache", packageFolder, "__init__.py")); + supportingFiles.add(new SupportingFile("__init__model.mustache", packageFolder + File.separatorChar + modelPackage, "__init__.py")); + supportingFiles.add(new SupportingFile("__init__api.mustache", packageFolder + File.separatorChar + apiPackage, "__init__.py")); if(Boolean.FALSE.equals(excludeTests)) { supportingFiles.add(new SupportingFile("__init__test.mustache", testFolder, "__init__.py")); @@ -218,16 +222,16 @@ public void processOpts() { supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml")); supportingFiles.add(new SupportingFile("setup.mustache", "", "setup.py")); - supportingFiles.add(new SupportingFile("api_client.mustache", packageName, "api_client.py")); + supportingFiles.add(new SupportingFile("api_client.mustache", packageFolder, "api_client.py")); if ("asyncio".equals(getLibrary())) { - supportingFiles.add(new SupportingFile("asyncio/rest.mustache", packageName, "rest.py")); + supportingFiles.add(new SupportingFile("asyncio/rest.mustache", packageFolder, "rest.py")); additionalProperties.put("asyncio", "true"); } else if ("tornado".equals(getLibrary())) { - supportingFiles.add(new SupportingFile("tornado/rest.mustache", packageName, "rest.py")); + supportingFiles.add(new SupportingFile("tornado/rest.mustache", packageFolder, "rest.py")); additionalProperties.put("tornado", "true"); } else { - supportingFiles.add(new SupportingFile("rest.mustache", packageName, "rest.py")); + supportingFiles.add(new SupportingFile("rest.mustache", packageFolder, "rest.py")); } modelPackage = packageName + "." + modelPackage; @@ -235,6 +239,17 @@ public void processOpts() { } + @Override + public CodegenModel fromModel(String name, Schema schema, Map allDefinitions) { + final CodegenModel codegenModel = super.fromModel(name, schema, allDefinitions); + final List imports = codegenModel.imports.stream() + .filter(model -> model.equals(codegenModel.parent)) + .collect(Collectors.toList()); + codegenModel.imports.clear(); + codegenModel.imports.addAll(imports); + return codegenModel; + } + private static String dropDots(String str) { return str.replaceAll("\\.", "_"); } @@ -291,8 +306,8 @@ public void postProcessPattern(String pattern, Map vendorExtensi //Must follow Perl /pattern/modifiers convention if(pattern.charAt(0) != '/' || i < 2) { - throw new IllegalArgumentException("Pattern must follow the Perl " - + "/pattern/modifiers convention. "+pattern+" is not valid."); + pattern = String.format("/%s/", pattern);; + i = pattern.lastIndexOf('/'); } String regex = pattern.substring(1, i).replace("'", "\\'"); @@ -456,6 +471,10 @@ public String toParamName(String name) { @Override public String toModelName(String name) { + if (name == null) { + // sanitizeName will return "Object" for null, but this is called "object" in python + return "object"; + } name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. // remove dollar sign name = name.replaceAll("$", ""); diff --git a/src/main/java/io/swagger/codegen/v3/generators/python/PythonFlaskConnexionCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/python/PythonFlaskConnexionCodegen.java index db2188a952..f27ade7c06 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/python/PythonFlaskConnexionCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/python/PythonFlaskConnexionCodegen.java @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import io.swagger.v3.core.util.Yaml; import io.swagger.v3.oas.models.OpenAPI; @@ -70,6 +71,7 @@ public PythonFlaskConnexionCodegen() { languageSpecificPrimitives.add("object"); languageSpecificPrimitives.add("byte"); languageSpecificPrimitives.add("bytearray"); + languageSpecificPrimitives.add("binary_type"); typeMapping.clear(); typeMapping.put("integer", "int"); @@ -101,7 +103,7 @@ public PythonFlaskConnexionCodegen() { "assert", "else", "if", "pass", "yield", "break", "except", "import", "print", "class", "exec", "in", "raise", "continue", "finally", "is", "return", "def", "for", "lambda", "try", "self", "None", "True", "False", "nonlocal", - "float", "int", "str", "date", "datetime")); + "float", "int", "str", "date", "datetime", "False", "await", "async")); // set the output folder here outputFolder = "generated-code/connexion"; @@ -157,12 +159,6 @@ public PythonFlaskConnexionCodegen() { @Override public void processOpts() { super.processOpts(); - //apiTemplateFiles.clear(); - /* - * Template Location. This is the location which templates will be read from. The generator - * will use the resource stream to attempt to read the templates. - */ - embeddedTemplateDir = templateDir = getTemplateDir(); if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) { setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME)); @@ -196,6 +192,7 @@ public void processOpts() { supportingFiles.add(new SupportingFile("__main__.mustache", packageName, "__main__.py")); supportingFiles.add(new SupportingFile("encoder.mustache", packageName, "encoder.py")); supportingFiles.add(new SupportingFile("util.mustache", packageName, "util.py")); + supportingFiles.add(new SupportingFile("type_util.mustache", packageName, "type_util.py")); supportingFiles.add(new SupportingFile("__init__.mustache", packageName + File.separatorChar + controllerPackage, "__init__.py")); supportingFiles.add(new SupportingFile("__init__model.mustache", packageName + File.separatorChar + modelPackage, "__init__.py")); supportingFiles.add(new SupportingFile("base_model_.mustache", packageName + File.separatorChar + modelPackage, "base_model_.py")); @@ -327,6 +324,7 @@ public String getSchemaType(Schema p) { @Override public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); final Paths paths = openAPI.getPaths(); addRouterControllerExtensions(paths); final Map securitySchemes = openAPI.getComponents() != null ? openAPI.getComponents().getSecuritySchemes() : null; @@ -344,6 +342,17 @@ private static List> getOperations(Map objs) return result; } + protected void addOperationImports(CodegenOperation codegenOperation, Set operationImports) { + for (String operationImport : operationImports) { + if ("object".equalsIgnoreCase(operationImport)) { + continue; + } + if (needToImport(operationImport)) { + codegenOperation.imports.add(operationImport); + } + } + } + private static List> sortOperationsByPath(List ops) { Multimap opsByPath = ArrayListMultimap.create(); @@ -764,4 +773,41 @@ protected void addSecurityExtensions(Map securitySchemes } } } + + public Map postProcessAllModels(Map processedModels) { + Map allModels = new HashMap<>(); + for (Map.Entry entry : processedModels.entrySet()) { + String modelName = toModelName(entry.getKey()); + Map inner = (Map) entry.getValue(); + List> models = (List>) inner.get("models"); + List> imports = (List>) inner.get("imports"); + for (Map mo : models) { + CodegenModel codegenModel = (CodegenModel) mo.get("model"); + + for (CodegenProperty codegenProperty : codegenModel.vars) { + if (Boolean.parseBoolean(String.valueOf(codegenProperty.vendorExtensions.get("x-is-composed")))) { + Map item = new HashMap<>(); + if (codegenProperty.getIsContainer()) { + item.put("import", toModelImport(codegenProperty.items.datatype)); + } else { + item.put("import", toModelImport(codegenProperty.datatype)); + } + imports.add(item); + } + } + + allModels.put(modelName, codegenModel); + } + } + postProcessAllCodegenModels(allModels); + return processedModels; + } + + @Override + protected void addImport(CodegenModel codegenModel, String type) { + if ("object".equalsIgnoreCase(type)) { + return; + } + super.addImport(codegenModel, type); + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/r/RClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/r/RClientCodegen.java new file mode 100644 index 0000000000..31fc8a2767 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/r/RClientCodegen.java @@ -0,0 +1,459 @@ +package io.swagger.codegen.v3.generators.r; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import io.swagger.models.properties.ArrayProperty; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RClientCodegen extends DefaultCodegenConfig { + static Logger LOGGER = LoggerFactory.getLogger(RClientCodegen.class); + + protected String packageName = "swagger"; + protected String packageVersion = "1.0.0"; + protected String apiDocPath = "docs/"; + protected String modelDocPath = "docs/"; + + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + public String getName() { + return "r"; + } + + public String getHelp() { + return "Generates a R client library (beta)."; + } + + public RClientCodegen() { + super(); + outputFolder = "generated-code/r"; + modelTemplateFiles.put("model.mustache", ".r"); + apiTemplateFiles.put("api.mustache", ".r"); + + modelDocTemplateFiles.put("model_doc.mustache", ".md"); + apiDocTemplateFiles.put("api_doc.mustache", ".md"); + + // default HIDE_GENERATION_TIMESTAMP to true + hideGenerationTimestamp = Boolean.TRUE; + + setReservedWordsLowerCase( + Arrays.asList( + // reserved words: https://stat.ethz.ch/R-manual/R-devel/library/base/html/Reserved.html + "if", "else", "repeat", "while", "function", "for", "in", + "next", "break", "TRUE", "FALSE", "NULL", "Inf", "NaN", + "NA", "NA_integer_", "NA_real_", "NA_complex_", "NA_character_" + ) + ); + + defaultIncludes = new HashSet( + Arrays.asList( + "map", + "array") + ); + + languageSpecificPrimitives = new HashSet( + Arrays.asList( + "Integer", + "Numeric", + "Character") + ); + + instantiationTypes.clear(); + + typeMapping.clear(); + typeMapping.put("integer", "Integer"); + typeMapping.put("long", "Integer"); + typeMapping.put("number", "Numeric"); + typeMapping.put("float", "Numeric"); + typeMapping.put("double", "Numeric"); + typeMapping.put("boolean", "Character"); + typeMapping.put("string", "Character"); + typeMapping.put("UUID", "Character"); + typeMapping.put("date", "Character"); + typeMapping.put("DateTime", "Character"); + typeMapping.put("password", "Character"); + typeMapping.put("file", "TODO_FILE_MAPPING"); + // map binary to string as a workaround + // the correct solution is to use []byte + typeMapping.put("binary", "Character"); + typeMapping.put("ByteArray", "Character"); + typeMapping.put("object", "TODO_OBJECT_MAPPING"); + + cliOptions.clear(); + cliOptions.add(new CliOption(CodegenConstants.PACKAGE_NAME, "R package name (convention: lowercase).") + .defaultValue("swagger")); + cliOptions.add(new CliOption(CodegenConstants.PACKAGE_VERSION, "R package version.") + .defaultValue("1.0.0")); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC) + .defaultValue(Boolean.TRUE.toString())); + + } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_NAME)) { + setPackageName((String) additionalProperties.get(CodegenConstants.PACKAGE_NAME)); + } else { + setPackageName("swagger"); + } + + if (additionalProperties.containsKey(CodegenConstants.PACKAGE_VERSION)) { + setPackageVersion((String) additionalProperties.get(CodegenConstants.PACKAGE_VERSION)); + } else { + setPackageVersion("1.0.0"); + } + + additionalProperties.put(CodegenConstants.PACKAGE_NAME, packageName); + additionalProperties.put(CodegenConstants.PACKAGE_VERSION, packageVersion); + + additionalProperties.put("apiDocPath", apiDocPath); + additionalProperties.put("modelDocPath", modelDocPath); + + apiTestTemplateFiles.clear(); // TODO: add api test template + modelTestTemplateFiles.clear(); // TODO: add model test template + + apiDocTemplateFiles.clear(); // TODO: add api doc template + modelDocTemplateFiles.clear(); // TODO: add model doc template + + modelPackage = packageName; + apiPackage = packageName; + + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); + supportingFiles.add(new SupportingFile("description.mustache", "", "DESCRIPTION")); + supportingFiles.add(new SupportingFile("Rbuildignore.mustache", "", ".Rbuildignore")); + supportingFiles.add(new SupportingFile(".travis.yml", "", ".travis.yml")); + supportingFiles.add(new SupportingFile("response.mustache", "/R", "Response.r")); + supportingFiles.add(new SupportingFile("element.mustache", "/R", "Element.r")); + supportingFiles.add(new SupportingFile("api_client.mustache", "/R", "ApiClient.r")); + supportingFiles.add(new SupportingFile("NAMESPACE.mustache", "", "NAMESPACE")); + } + + @Override + public String escapeReservedWord(String name) + { + // Can't start with an underscore, as our fields need to start with an + // UppercaseLetter so that R treats them as public/visible. + + // Options? + // - MyName + // - AName + // - TheName + // - XName + // - X_Name + // ... or maybe a suffix? + // - Name_ ... think this will work. + if(this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return camelize(name) + '_'; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + "R" + File.separator; + } + + public String modelFileFolder() { + return outputFolder + File.separator + "R" + File.separator; + } + + @Override + public String toVarName(String name) { + // replace - with _ e.g. created-at => created_at + name = sanitizeName(name.replaceAll("-", "_")); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) + return name; + + // convert variable name to snake case + // PetId => pet_id + name = underscore(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name)) + name = escapeReservedWord(name); + + // for reserved word or word starting with number, append _ + if (name.matches("^\\d.*")) + name = "Var" + name; + + return name; + } + + @Override + public String toParamName(String name) { + return toVarName(name); + } + + @Override + public String toModelName(String name) { + return toModelFilename(name); + } + + @Override + public String toModelFilename(String name) { + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + + name = sanitizeName(name); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. return => ModelReturn (after camelize) + } + + // model name starts with number + if (name.matches("^\\d.*")) { + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. 200Response => Model200Response (after camelize) + } + + return camelize(name); + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + // e.g. PetApi.r => pet_api.r + return camelize(name + "_api"); + } + + @Override + public String apiDocFileFolder() { + return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar); + } + + @Override + public String modelDocFileFolder() { + return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar); + } + + @Override + public String toModelDocFilename(String name) { + return toModelName(name); + } + + @Override + public String toApiDocFilename(String name) { + return toApiName(name); + } + + @Override + public String toApiName(String name) { + return camelize(super.toApiName(name)); + } + + @Override + public String getTypeDeclaration(Schema schema) { + if(schema instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema) schema; + Schema inner = arraySchema.getItems(); + return getTypeDeclaration(inner); + } else if (schema instanceof MapSchema) { + MapSchema mp = (MapSchema) schema; + Object innerObject = mp.getAdditionalProperties(); + if (innerObject instanceof Schema) { + return getTypeDeclaration((Schema) innerObject); + } + } + // Not using the supertype invocation, because we want to UpperCamelize + // the type. + String schemaType = getSchemaType(schema); + if (typeMapping.containsKey(schemaType)) { + return typeMapping.get(schemaType); + } + if (typeMapping.containsValue(schemaType)) { + return schemaType; + } + if (languageSpecificPrimitives.contains(schemaType)) { + return schemaType; + } + return toModelName(schemaType); + } + + @Override + public String getSchemaType(Schema schema) { + String swaggerType = super.getSchemaType(schema); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (languageSpecificPrimitives.contains(type)) + return (type); + } else { + type = swaggerType; + } + return type; + } + + @Override + public String toOperationId(String operationId) { + String sanitizedOperationId = sanitizeName(operationId); + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(sanitizedOperationId)) { + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + underscore("call_" + operationId)); + sanitizedOperationId = "call_" + sanitizedOperationId; + } + + return underscore(sanitizedOperationId); + } + + @Override + public Map postProcessModels(Map objs) { + // remove model imports to avoid error + List> imports = (List>) objs.get("imports"); + final String prefix = modelPackage(); + Iterator> iterator = imports.iterator(); + while (iterator.hasNext()) { + String _import = iterator.next().get("import"); + if (_import.startsWith(prefix)) + iterator.remove(); + } + + // recursively add import for mapping one type to multiple imports + List> recursiveImports = (List>) objs.get("imports"); + if (recursiveImports == null) + return objs; + + ListIterator> listIterator = imports.listIterator(); + while (listIterator.hasNext()) { + String _import = listIterator.next().get("import"); + // if the import package happens to be found in the importMapping (key) + // add the corresponding import package to the list + if (importMapping.containsKey(_import)) { + listIterator.add(createMapping("import", importMapping.get(_import))); + } + } + + return postProcessModelsEnum(objs); + } + + @Override + protected boolean needToImport(String type) { + return !defaultIncludes.contains(type) && !languageSpecificPrimitives.contains(type); + } + + @Override + public String getDefaultTemplateDir() { + return "R"; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public void setPackageVersion(String packageVersion) { + this.packageVersion = packageVersion; + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("]]", "] ]"); + } + + public Map createMapping(String key, String value){ + Map customImport = new HashMap(); + customImport.put(key, value); + + return customImport; + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) { + return value; + } else { + return escapeText(value); + } + } + + @Override + public String toEnumDefaultValue(String value, String datatype) { + return datatype + "_" + value; + } + + @Override + public String toEnumVarName(String name, String datatype) { + if (name.length() == 0) { + return "EMPTY"; + } + + // number + if ("int".equals(datatype) || "double".equals(datatype) || "float".equals(datatype)) { + String varName = name; + varName = varName.replaceAll("-", "MINUS_"); + varName = varName.replaceAll("\\+", "PLUS_"); + varName = varName.replaceAll("\\.", "_DOT_"); + return varName; + } + + // for symbol, e.g. $, # + if (getSymbolName(name) != null) { + return getSymbolName(name).toUpperCase(); + } + + // string + String enumName = sanitizeName(underscore(name).toUpperCase()); + enumName = enumName.replaceFirst("^_", ""); + enumName = enumName.replaceFirst("_$", ""); + + if (isReservedWord(enumName) || enumName.matches("\\d.*")) { // reserved word or starts with number + return escapeReservedWord(enumName); + } else { + return enumName; + } + } + + @Override + public String toEnumName(CodegenProperty property) { + String enumName = underscore(toModelName(property.name)).toUpperCase(); + + // remove [] for array or map of enum + enumName = enumName.replace("[]", ""); + + if (enumName.matches("\\d.*")) { // starts with number + return "_" + enumName; + } else { + return enumName; + } + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/ruby/RubyClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/ruby/RubyClientCodegen.java new file mode 100644 index 0000000000..cc8fc4faf2 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/ruby/RubyClientCodegen.java @@ -0,0 +1,747 @@ +package io.swagger.codegen.v3.generators.ruby; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenParameter; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.BooleanSchema; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.NumberSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Arrays; +import java.util.Map; + +public class RubyClientCodegen extends DefaultCodegenConfig { + private static final Logger LOGGER = LoggerFactory.getLogger(RubyClientCodegen.class); + + public static final String GEM_NAME = "gemName"; + public static final String MODULE_NAME = "moduleName"; + public static final String GEM_VERSION = "gemVersion"; + public static final String GEM_LICENSE = "gemLicense"; + public static final String GEM_REQUIRED_RUBY_VERSION = "gemRequiredRubyVersion"; + public static final String GEM_HOMEPAGE = "gemHomepage"; + public static final String GEM_SUMMARY = "gemSummary"; + public static final String GEM_DESCRIPTION = "gemDescription"; + public static final String GEM_AUTHOR = "gemAuthor"; + public static final String GEM_AUTHOR_EMAIL = "gemAuthorEmail"; + + protected String gemName; + protected String moduleName; + protected String gemVersion = "1.0.0"; + protected String specFolder = "spec"; + protected String libFolder = "lib"; + protected String gemLicense = "proprietary"; + protected String gemRequiredRubyVersion = ">= 1.9"; + protected String gemHomepage = "http://swagger.io"; + protected String gemSummary = "A ruby wrapper for the swagger APIs"; + protected String gemDescription = "This gem maps to a swagger API"; + protected String gemAuthor = ""; + protected String gemAuthorEmail = ""; + protected String apiDocPath = "docs/"; + protected String modelDocPath = "docs/"; + + protected static int emptyMethodNameCounter = 0; + + public RubyClientCodegen() { + super(); + + // clear import mapping (from default generator) as ruby does not use it + // at the moment + importMapping.clear(); + + modelPackage = "models"; + apiPackage = "api"; + outputFolder = "generated-code" + File.separator + "ruby"; + + // default HIDE_GENERATION_TIMESTAMP to true + hideGenerationTimestamp = Boolean.TRUE; + + setReservedWordsLowerCase( + Arrays.asList( + // local variable names used in API methods (endpoints) + "local_var_path", "query_params", "header_params", "_header_accept", "_header_accept_result", + "_header_content_type", "form_params", "post_body", "auth_names", + // ruby reserved keywords + "__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__", + "begin", "defined?", "ensure", "module", "redo", "super", "until", "BEGIN", + "break", "do", "false", "next", "rescue", "then", "when", "END", "case", + "else", "for", "nil", "retry", "true", "while", "alias", "class", "elsif", + "if", "not", "return", "undef", "yield") + ); + + typeMapping.clear(); + languageSpecificPrimitives.clear(); + + // primitives in ruby lang + languageSpecificPrimitives.add("int"); + languageSpecificPrimitives.add("array"); + languageSpecificPrimitives.add("map"); + languageSpecificPrimitives.add("string"); + // primitives in the typeMapping + languageSpecificPrimitives.add("String"); + languageSpecificPrimitives.add("Integer"); + languageSpecificPrimitives.add("Float"); + languageSpecificPrimitives.add("Date"); + languageSpecificPrimitives.add("DateTime"); + languageSpecificPrimitives.add("BOOLEAN"); + languageSpecificPrimitives.add("Array"); + languageSpecificPrimitives.add("Hash"); + languageSpecificPrimitives.add("File"); + languageSpecificPrimitives.add("Object"); + + typeMapping.put("string", "String"); + typeMapping.put("char", "String"); + typeMapping.put("int", "Integer"); + typeMapping.put("integer", "Integer"); + typeMapping.put("long", "Integer"); + typeMapping.put("short", "Integer"); + typeMapping.put("float", "Float"); + typeMapping.put("double", "Float"); + typeMapping.put("number", "Float"); + typeMapping.put("date", "Date"); + typeMapping.put("DateTime", "DateTime"); + typeMapping.put("boolean", "BOOLEAN"); + typeMapping.put("array", "Array"); + typeMapping.put("List", "Array"); + typeMapping.put("map", "Hash"); + typeMapping.put("object", "Object"); + typeMapping.put("file", "File"); + typeMapping.put("binary", "String"); + typeMapping.put("ByteArray", "String"); + typeMapping.put("UUID", "String"); + + // remove modelPackage and apiPackage added by default + cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) || + CodegenConstants.API_PACKAGE.equals(opt.getOpt())); + cliOptions.add(new CliOption(GEM_NAME, "gem name (convention: underscore_case).") + .defaultValue("openapi_client")); + cliOptions.add(new CliOption(MODULE_NAME, "top module name (convention: CamelCase, usually corresponding to gem name).") + .defaultValue("OpenAPIClient")); + cliOptions.add(new CliOption(GEM_VERSION, "gem version.") + .defaultValue("1.0.0")); + cliOptions.add(new CliOption(GEM_LICENSE, "gem license. ") + .defaultValue("proprietary")); + cliOptions.add(new CliOption(GEM_REQUIRED_RUBY_VERSION, "gem required Ruby version. ") + .defaultValue(">= 1.9")); + cliOptions.add(new CliOption(GEM_HOMEPAGE, "gem homepage. ") + .defaultValue("http://swagger.io")); + cliOptions.add(new CliOption(GEM_SUMMARY, "gem summary. ") + .defaultValue("A ruby wrapper for the open APIs")); + cliOptions.add(new CliOption(GEM_DESCRIPTION, "gem description. ") + .defaultValue("This gem maps to a open API")); + cliOptions.add(new CliOption(GEM_AUTHOR, "gem author (only one is supported).")); + cliOptions.add(new CliOption(GEM_AUTHOR_EMAIL, "gem author email (only one is supported).")); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC) + .defaultValue(Boolean.TRUE.toString())); + } + + @Override + public void processOpts() { + super.processOpts(); + + if (StringUtils.isBlank(templateDir)) { + embeddedTemplateDir = templateDir = getTemplateDir(); + } + + modelTemplateFiles.put("model.mustache", ".rb"); + apiTemplateFiles.put("api.mustache", ".rb"); + modelDocTemplateFiles.put("model_doc.mustache", ".md"); + apiDocTemplateFiles.put("api_doc.mustache", ".md"); + + modelTestTemplateFiles.put("model_test.mustache", ".rb"); + apiTestTemplateFiles.put("api_test.mustache", ".rb"); + + if (additionalProperties.containsKey(GEM_NAME)) { + setGemName((String) additionalProperties.get(GEM_NAME)); + } + if (additionalProperties.containsKey(MODULE_NAME)) { + setModuleName((String) additionalProperties.get(MODULE_NAME)); + } + + if (gemName == null && moduleName == null) { + setGemName("swagger_client"); + setModuleName(generateModuleName(gemName)); + } else if (gemName == null) { + setGemName(generateGemName(moduleName)); + } else if (moduleName == null) { + setModuleName(generateModuleName(gemName)); + } + + additionalProperties.put(GEM_NAME, gemName); + additionalProperties.put(MODULE_NAME, moduleName); + + if (additionalProperties.containsKey(GEM_VERSION)) { + setGemVersion((String) additionalProperties.get(GEM_VERSION)); + }else { + // not set, pass the default value to template + additionalProperties.put(GEM_VERSION, gemVersion); + } + + if (additionalProperties.containsKey(GEM_LICENSE)) { + setGemLicense((String) additionalProperties.get(GEM_LICENSE)); + } + + if (additionalProperties.containsKey(GEM_REQUIRED_RUBY_VERSION)) { + setGemRequiredRubyVersion((String) additionalProperties.get(GEM_REQUIRED_RUBY_VERSION)); + } + + if (additionalProperties.containsKey(GEM_HOMEPAGE)) { + setGemHomepage((String) additionalProperties.get(GEM_HOMEPAGE)); + } + + if (additionalProperties.containsKey(GEM_SUMMARY)) { + setGemSummary((String) additionalProperties.get(GEM_SUMMARY)); + } + + if (additionalProperties.containsKey(GEM_DESCRIPTION)) { + setGemDescription((String) additionalProperties.get(GEM_DESCRIPTION)); + } + + if (additionalProperties.containsKey(GEM_AUTHOR)) { + setGemAuthor((String) additionalProperties.get(GEM_AUTHOR)); + } + + if (additionalProperties.containsKey(GEM_AUTHOR_EMAIL)) { + setGemAuthorEmail((String) additionalProperties.get(GEM_AUTHOR_EMAIL)); + } + + // make api and model doc path available in mustache template + additionalProperties.put("apiDocPath", apiDocPath); + additionalProperties.put("modelDocPath", modelDocPath); + + // use constant model/api package (folder path) + setModelPackage("models"); + setApiPackage("api"); + + supportingFiles.add(new SupportingFile("gemspec.mustache", "", gemName + ".gemspec")); + supportingFiles.add(new SupportingFile("gem.mustache", libFolder, gemName + ".rb")); + String gemFolder = libFolder + File.separator + gemName; + supportingFiles.add(new SupportingFile("api_client.mustache", gemFolder, "api_client.rb")); + supportingFiles.add(new SupportingFile("api_error.mustache", gemFolder, "api_error.rb")); + supportingFiles.add(new SupportingFile("configuration.mustache", gemFolder, "configuration.rb")); + supportingFiles.add(new SupportingFile("version.mustache", gemFolder, "version.rb")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); + supportingFiles.add(new SupportingFile("Rakefile.mustache", "", "Rakefile")); + supportingFiles.add(new SupportingFile("Gemfile.mustache", "", "Gemfile")); + supportingFiles.add(new SupportingFile("rubocop.mustache", "", ".rubocop.yml")); + + // test files should not be overwritten + writeOptional(outputFolder, new SupportingFile("rspec.mustache", "", ".rspec")); + writeOptional(outputFolder, new SupportingFile("spec_helper.mustache", specFolder, "spec_helper.rb")); + writeOptional(outputFolder, new SupportingFile("configuration_spec.mustache", specFolder, "configuration_spec.rb")); + writeOptional(outputFolder, new SupportingFile("api_client_spec.mustache", specFolder, "api_client_spec.rb")); + // not including base object test as the moment as not all API has model + writeOptional(outputFolder, new SupportingFile("base_object_spec.mustache", specFolder, "base_object_spec.rb")); + } + + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map definitions, OpenAPI openAPI) { + CodegenOperation op = super.fromOperation(path, httpMethod, operation, definitions, openAPI); + // Set vendor-extension to be used in template: + // x-codegen-hasMoreRequired + // x-codegen-hasMoreOptional + // x-codegen-hasRequiredParams + CodegenParameter lastRequired = null; + CodegenParameter lastOptional = null; + for (CodegenParameter p : op.allParams) { + if (p.required) { + lastRequired = p; + } else { + lastOptional = p; + } + } + for (CodegenParameter p : op.allParams) { + if (p == lastRequired) { + p.vendorExtensions.put("x-codegen-hasMoreRequired", false); + } else if (p == lastOptional) { + p.vendorExtensions.put("x-codegen-hasMoreOptional", false); + } else { + p.vendorExtensions.put("x-codegen-hasMoreRequired", true); + p.vendorExtensions.put("x-codegen-hasMoreOptional", true); + } + } + op.vendorExtensions.put("x-codegen-hasRequiredParams", lastRequired != null); + return op; + } + + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public String getName() { + return "ruby"; + } + + @Override + public String getHelp() { + return "Generates a Ruby client library."; + } + + /** + * Generate Ruby module name from the gem name, e.g. use "SwaggerClient" for "swagger_client". + * + * @param gemName Ruby gem name + * @return Ruby module name + */ + private String generateModuleName(String gemName) { + return camelize(gemName.replaceAll("[^\\w]+", "_")); + } + + /** + * Generate Ruby gem name from the module name, e.g. use "swagger_client" for "SwaggerClient". + * + * @param moduleName Ruby module name + * @return Ruby gem name + */ + private String generateGemName(String moduleName) { + return underscore(moduleName.replaceAll("[^\\w]+", "")); + } + + @Override + public String escapeReservedWord(String name) { + if(this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return "_" + name; + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + libFolder + File.separator + gemName + File.separator + apiPackage.replace("/", File.separator); + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + libFolder + File.separator + gemName + File.separator + modelPackage.replace("/", File.separator); + } + + @Override + public String apiTestFileFolder() { + return outputFolder + File.separator + specFolder + File.separator + apiPackage.replace("/", File.separator); + } + + @Override + public String modelTestFileFolder() { + return outputFolder + File.separator + specFolder + File.separator + modelPackage.replace("/", File.separator); + } + + @Override + public String apiDocFileFolder() { + return (outputFolder + "/" + apiDocPath).replace('/', File.separatorChar); + } + + @Override + public String modelDocFileFolder() { + return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar); + } + + @Override + public String getTypeDeclaration(Schema schema) { + if (schema instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema) schema; + Schema inner = arraySchema.getItems(); + return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">"; + } else if (schema instanceof MapSchema) { + MapSchema mapSchema = (MapSchema) schema; + if (mapSchema.getAdditionalProperties() instanceof Schema) { + Schema inner = (Schema) mapSchema.getAdditionalProperties(); + return getSchemaType(schema) + ""; + } + } + return super.getTypeDeclaration(schema); + } + + @Override + public String toDefaultValue(Schema schema) { + if (schema instanceof IntegerSchema) { + IntegerSchema integerSchema = (IntegerSchema) schema; + if (integerSchema.getDefault() != null) { + return integerSchema.getDefault().toString(); + } + } else if (schema instanceof NumberSchema) { + NumberSchema numberSchema = (NumberSchema) schema; + if (numberSchema.getDefault() != null) { + return numberSchema.getDefault().toString(); + } + } else if (schema instanceof BooleanSchema) { + BooleanSchema booleanSchema = (BooleanSchema) schema; + if (booleanSchema.getDefault() != null) { + return booleanSchema.getDefault().toString(); + } + } else if (schema instanceof StringSchema) { + StringSchema stringSchema = (StringSchema) schema; + if (stringSchema.getDefault() != null) { + return "'" + escapeText(stringSchema.getDefault()) + "'"; + } + } + + return null; + } + + @Override + public String getSchemaType(Schema schema) { + String swaggerType = super.getSchemaType(schema); + String type = null; + if (typeMapping.containsKey(swaggerType)) { + type = typeMapping.get(swaggerType); + if (languageSpecificPrimitives.contains(type)) { + return type; + } + } else { + type = swaggerType; + } + if (type == null) { + return null; + } + return toModelName(type); + } + + @Override + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + // if it's all uppper case, convert to lower case + if (name.matches("^[A-Z_]*$")) { + name = name.toLowerCase(); + } + + // camelize (lower first character) the variable name + // petId => pet_id + name = underscore(name); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public String toParamName(String name) { + // should be the same as variable name + return toVarName(name); + } + + @Override + public String toModelName(String name) { + name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + String modelName = camelize("Model" + name); + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + modelName); + return modelName; + } + + // model name starts with number + if (name.matches("^\\d.*")) { + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + camelize("model_" + name)); + name = "model_" + name; // e.g. 200Response => Model200Response (after camelize) + } + + // camelize the model name + // phone_number => PhoneNumber + return camelize(name); + } + + @Override + public String toModelFilename(String name) { + name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + if (!StringUtils.isEmpty(modelNamePrefix)) { + name = modelNamePrefix + "_" + name; + } + + if (!StringUtils.isEmpty(modelNameSuffix)) { + name = name + "_" + modelNameSuffix; + } + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + String filename = underscore("model_" + name); + LOGGER.warn(name + " (reserved word) cannot be used as model filename. Renamed to " + filename); + return filename; + } + + // model name starts with number + if (name.matches("^\\d.*")) { + LOGGER.warn(name + " (model name starts with number) cannot be used as model name. Renamed to " + underscore("model_" + name)); + name = "model_" + name; // e.g. 200Response => model_200_response + } + + // underscore the model file name + // PhoneNumber.rb => phone_number.rb + return underscore(name); + } + + @Override + public String toModelDocFilename(String name) { + return toModelName(name); + } + + @Override + public String toApiFilename(String name) { + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + + // e.g. PhoneNumberApi.rb => phone_number_api.rb + return underscore(name) + "_api"; + } + + @Override + public String toApiDocFilename(String name) { + return toApiName(name); + } + + @Override + public String toApiTestFilename(String name) { + return toApiFilename(name) + "_spec"; + } + + @Override + public String toModelTestFilename(String name) { + return toModelFilename(name) + "_spec"; + } + + @Override + public String toApiName(String name) { + if (name.length() == 0) { + return "DefaultApi"; + } + // e.g. phone_number_api => PhoneNumberApi + return camelize(name) + "Api"; + } + + @Override + public String toEnumValue(String value, String datatype) { + if ("Integer".equals(datatype) || "Float".equals(datatype)) { + return value; + } else { + return "'" + escapeText(value) + "'"; + } + } + + @Override + public String toEnumVarName(String name, String datatype) { + if (name.length() == 0) { + return "EMPTY"; + } + + // number + if ("Integer".equals(datatype) || "Float".equals(datatype)) { + String varName = name; + varName = varName.replaceAll("-", "MINUS_"); + varName = varName.replaceAll("\\+", "PLUS_"); + varName = varName.replaceAll("\\.", "_DOT_"); + return varName; + } + + // string + String enumName = sanitizeName(underscore(name).toUpperCase()); + enumName = enumName.replaceFirst("^_", ""); + enumName = enumName.replaceFirst("_$", ""); + + if (enumName.matches("\\d.*")) { // starts with number + return "N" + enumName; + } else { + return enumName; + } + } + + @Override + public String toEnumName(CodegenProperty property) { + String enumName = underscore(toModelName(property.name)).toUpperCase(); + enumName = enumName.replaceFirst("^_", ""); + enumName = enumName.replaceFirst("_$", ""); + + if (enumName.matches("\\d.*")) { // starts with number + return "N" + enumName; + } else { + return enumName; + } + } + + @Override + public Map postProcessModels(Map objs) { + // process enum in models + return postProcessModelsEnum(objs); + } + + @Override + public String toOperationId(String operationId) { + // rename to empty_method_name_1 (e.g.) if method name is empty + if (StringUtils.isEmpty(operationId)) { + operationId = underscore("empty_method_name_" + emptyMethodNameCounter++); + LOGGER.warn("Empty method name (operationId) found. Renamed to " + operationId); + return operationId; + } + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + String newOperationId = underscore("call_" + operationId); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId); + return newOperationId; + } + + return underscore(sanitizeName(operationId)); + } + + @Override + public String toApiImport(String name) { + return gemName + "/" + apiPackage() + "/" + toApiFilename(name); + } + + @Override + public void setParameterExampleValue(CodegenParameter p) { + String example; + + if (p.defaultValue == null) { + example = p.example; + } else { + example = p.defaultValue; + } + + String type = p.baseType; + if (type == null) { + type = p.dataType; + } + + if ("String".equals(type)) { + if (example == null) { + example = p.paramName + "_example"; + } + example = "'" + escapeText(example) + "'"; + } else if ("Integer".equals(type)) { + if (example == null) { + example = "56"; + } + } else if ("Float".equals(type)) { + if (example == null) { + example = "3.4"; + } + } else if ("BOOLEAN".equals(type)) { + if (example == null) { + example = "true"; + } + } else if ("File".equals(type)) { + if (example == null) { + example = "/path/to/file"; + } + example = "File.new('" + escapeText(example) + "')"; + } else if ("Date".equals(type)) { + if (example == null) { + example = "2013-10-20"; + } + example = "Date.parse('" + escapeText(example) + "')"; + } else if ("DateTime".equals(type)) { + if (example == null) { + example = "2013-10-20T19:20:30+01:00"; + } + example = "DateTime.parse('" + escapeText(example) + "')"; + } else if (!languageSpecificPrimitives.contains(type)) { + // type is a model class, e.g. User + example = moduleName + "::" + type + ".new"; + } + + if (example == null) { + example = "nil"; + } else if (Boolean.TRUE.equals(p.getIsListContainer())) { + example = "[" + example + "]"; + } else if (Boolean.TRUE.equals(p.getIsMapContainer())) { + example = "{'key' => " + example + "}"; + } + + p.example = example; + } + + public void setGemName(String gemName) { + this.gemName = gemName; + } + + public void setModuleName(String moduleName) { + this.moduleName = moduleName; + } + + public void setGemVersion(String gemVersion) { + this.gemVersion = gemVersion; + } + + public void setGemDescription(String gemDescription) { + this.gemDescription = gemDescription; + } + + public void setGemSummary(String gemSummary) { + this.gemSummary = gemSummary; + } + + public void setGemLicense(String gemLicense) { + this.gemLicense = gemLicense; + } + + public void setGemRequiredRubyVersion(String gemRequiredRubyVersion) { + this.gemRequiredRubyVersion = gemRequiredRubyVersion; + } + + public void setGemHomepage(String gemHomepage) { + this.gemHomepage = gemHomepage; + } + + public void setGemAuthor(String gemAuthor) { + this.gemAuthor = gemAuthor; + } + + public void setGemAuthorEmail(String gemAuthorEmail) { + this.gemAuthorEmail = gemAuthorEmail; + } + + @Override + public boolean shouldOverwrite(String filename) { + // skip spec file as the file might have been updated with new test cases + return !(skipOverwrite && new File(filename).exists()); + // + //return super.shouldOverwrite(filename) && !filename.endsWith("_spec.rb"); + } + + @Override + public String getDefaultTemplateDir() { + return "ruby"; + } + + @Override + public String escapeQuotationMark(String input) { + // remove ' to avoid code injection + return input.replace("'", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("=end", "=_end").replace("=begin", "=_begin"); + } + +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/scala/AbstractScalaCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/scala/AbstractScalaCodegen.java index 3c27334324..7823235980 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/scala/AbstractScalaCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/scala/AbstractScalaCodegen.java @@ -254,10 +254,4 @@ protected String stripPackageName(String input) { int lastIndexOfDot = input.lastIndexOf("."); return input.substring(lastIndexOfDot + 1); } - - // todo: remove this once handlebar templates for this generator are implemented - @Override - protected void setTemplateEngine() { - templateEngine = new MustacheTemplateEngine(this); - } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegen.java index 678ea3f912..e37ccf021e 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegen.java @@ -55,12 +55,6 @@ public AkkaHttpServerCodegen() { } - @Override - public void processOpts() { - super.processOpts(); - embeddedTemplateDir = templateDir = getTemplateDir(); - } - @Override public Map postProcessOperations(Map objs) { return setComplexTypes(objs); diff --git a/src/main/java/io/swagger/codegen/v3/generators/scala/ScalaClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/scala/ScalaClientCodegen.java index b7dcd63d97..a151735268 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/scala/ScalaClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/scala/ScalaClientCodegen.java @@ -78,7 +78,8 @@ public ScalaClientCodegen() { gradleWrapperPackage.replace( ".", File.separator ), "gradle-wrapper.jar") ); supportingFiles.add(new SupportingFile("build.sbt.mustache", "", "build.sbt")); - + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + importMapping.remove("List"); importMapping.remove("Set"); importMapping.remove("Map"); @@ -119,8 +120,6 @@ public ScalaClientCodegen() { public void processOpts() { super.processOpts(); - embeddedTemplateDir = templateDir = getTemplateDir(); - if (additionalProperties.containsKey(CodegenConstants.MODEL_PROPERTY_NAMING)) { setModelPropertyNaming((String) additionalProperties.get(CodegenConstants.MODEL_PROPERTY_NAMING)); } diff --git a/src/main/java/io/swagger/codegen/v3/generators/swift/AbstractSwiftCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/swift/AbstractSwiftCodegen.java index 042901d89b..b495d56fff 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/swift/AbstractSwiftCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/swift/AbstractSwiftCodegen.java @@ -51,6 +51,8 @@ public abstract class AbstractSwiftCodegen extends DefaultCodegenConfig { public static final String SWIFT_USE_API_NAMESPACE = "swiftUseApiNamespace"; public static final String DEFAULT_POD_AUTHORS = "Swagger Codegen"; public static final String LENIENT_TYPE_CAST = "lenientTypeCast"; + protected static final String MODEL_CLASSES = "modelClasses"; + protected static final String USE_MODEL_CLASSES = "useModelClasses"; private static final String LIBRARY_PROMISE_KIT = "PromiseKit"; private static final String LIBRARY_RX_SWIFT = "RxSwift"; @@ -143,10 +145,6 @@ protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Sc public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - // Setup project name if (additionalProperties.containsKey(PROJECT_NAME)) { setProjectName((String) additionalProperties.get(PROJECT_NAME)); @@ -196,6 +194,10 @@ public void processOpts() { additionalProperties.put(POD_AUTHORS, DEFAULT_POD_AUTHORS); } + if (additionalProperties.containsKey(MODEL_CLASSES)) { + additionalProperties.put(USE_MODEL_CLASSES, true); + } + setLenientTypeCast(convertPropertyToBooleanAndWriteBack(LENIENT_TYPE_CAST)); supportingFiles.add(new SupportingFile("Podspec.mustache", diff --git a/src/main/java/io/swagger/codegen/v3/generators/swift/Swift5Codegen.java b/src/main/java/io/swagger/codegen/v3/generators/swift/Swift5Codegen.java new file mode 100644 index 0000000000..a7e3118d3a --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/swift/Swift5Codegen.java @@ -0,0 +1,856 @@ +package io.swagger.codegen.v3.generators.swift; + + + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.text.WordUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +public class Swift5Codegen extends DefaultCodegenConfig { + protected static final Logger LOGGER = LoggerFactory.getLogger(Swift5Codegen.class); + + public static final String PROJECT_NAME = "projectName"; + public static final String RESPONSE_AS = "responseAs"; + public static final String UNWRAP_REQUIRED = "unwrapRequired"; + public static final String OBJC_COMPATIBLE = "objcCompatible"; + public static final String POD_SOURCE = "podSource"; + public static final String POD_AUTHORS = "podAuthors"; + public static final String POD_SOCIAL_MEDIA_URL = "podSocialMediaURL"; + public static final String POD_DOCSET_URL = "podDocsetURL"; + public static final String POD_LICENSE = "podLicense"; + public static final String POD_HOMEPAGE = "podHomepage"; + public static final String POD_SUMMARY = "podSummary"; + public static final String POD_DESCRIPTION = "podDescription"; + public static final String POD_SCREENSHOTS = "podScreenshots"; + public static final String POD_DOCUMENTATION_URL = "podDocumentationURL"; + public static final String SWIFT_USE_API_NAMESPACE = "swiftUseApiNamespace"; + public static final String DEFAULT_POD_AUTHORS = "Swagger Codegen"; + public static final String LENIENT_TYPE_CAST = "lenientTypeCast"; + private static final String LIBRARY_PROMISE_KIT = "PromiseKit"; + private static final String LIBRARY_RX_SWIFT = "RxSwift"; + private static final String[] RESPONSE_LIBRARIES = {LIBRARY_PROMISE_KIT, LIBRARY_RX_SWIFT}; + protected String projectName = "SwaggerClient"; + private boolean unwrapRequired; + private boolean objcCompatible = false; + private boolean lenientTypeCast = false; + protected boolean swiftUseApiNamespace; + private String[] responseAs = new String[0]; + protected String sourceFolder = "Classes" + File.separator + "Swaggers"; + + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public String getName() { + return "swift5"; + } + + @Override + public String getHelp() { + return "Generates a swift client library."; + } + + @Override + protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, + Schema swaggerModel) { + + final Object additionalProperties = swaggerModel.getAdditionalProperties(); + + if (additionalProperties != null && additionalProperties instanceof Schema) { + codegenModel.additionalPropertiesType = getSchemaType((Schema) additionalProperties); + } + } + + /** + * Constructor for the swift5 language codegen module. + */ + public Swift5Codegen() { + super(); + outputFolder = "generated-code" + File.separator + "swift"; + modelTemplateFiles.put("model.mustache", ".swift"); + apiTemplateFiles.put("api.mustache", ".swift"); + apiPackage = File.separator + "APIs"; + modelPackage = File.separator + "Models"; + + languageSpecificPrimitives = new HashSet<>( + Arrays.asList( + "Int", + "Int32", + "Int64", + "Float", + "Double", + "Bool", + "Void", + "String", + "Character", + "AnyObject", + "Any") + ); + defaultIncludes = new HashSet<>( + Arrays.asList( + "Data", + "Date", + "URL", // for file + "UUID", + "Array", + "Dictionary", + "Set", + "Any", + "Empty", + "AnyObject", + "Any") + ); + reservedWords = new HashSet<>( + Arrays.asList( + // name used by swift client + "ErrorResponse", "Response", + + // Added for Objective-C compatibility + "id", "description", "NSArray", "NSURL", "CGFloat", "NSSet", "NSString", "NSInteger", "NSUInteger", + "NSError", "NSDictionary", + + // + // Swift keywords. This list is taken from here: + // https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID410 + // + // Keywords used in declarations + "associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import", "init", + "inout", "internal", "let", "open", "operator", "private", "protocol", "public", "static", "struct", + "subscript", "typealias", "var", + // Keywords uses in statements + "break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if", + "in", "repeat", "return", "switch", "where", "while", + // Keywords used in expressions and types + "as", "Any", "catch", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws", "true", "try", + // Keywords used in patterns + "_", + // Keywords that begin with a number sign + "#available", "#colorLiteral", "#column", "#else", "#elseif", "#endif", "#file", "#fileLiteral", "#function", "#if", + "#imageLiteral", "#line", "#selector", "#sourceLocation", + // Keywords reserved in particular contexts + "associativity", "convenience", "dynamic", "didSet", "final", "get", "infix", "indirect", "lazy", "left", + "mutating", "none", "nonmutating", "optional", "override", "postfix", "precedence", "prefix", "Protocol", + "required", "right", "set", "Type", "unowned", "weak", "willSet", + + // + // Swift Standard Library types + // https://developer.apple.com/documentation/swift + // + // Numbers and Basic Values + "Bool", "Int", "Double", "Float", "Range", "ClosedRange", "Error", "Optional", + // Special-Use Numeric Types + "UInt", "UInt8", "UInt16", "UInt32", "UInt64", "Int8", "Int16", "Int32", "Int64", "Float80", "Float32", "Float64", + // Strings and Text + "String", "Character", "Unicode", "StaticString", + // Collections + "Array", "Dictionary", "Set", "OptionSet", "CountableRange", "CountableClosedRange", + + // The following are commonly-used Foundation types + "URL", "Data", "Codable", "Encodable", "Decodable", + + // The following are other words we want to reserve + "Void", "AnyObject", "Class", "dynamicType", "COLUMN", "FILE", "FUNCTION", "LINE" + ) + ); + + typeMapping = new HashMap<>(); + typeMapping.put("array", "Array"); + typeMapping.put("List", "Array"); + typeMapping.put("map", "Dictionary"); + typeMapping.put("date", "Date"); + typeMapping.put("Date", "Date"); + typeMapping.put("DateTime", "Date"); + typeMapping.put("boolean", "Bool"); + typeMapping.put("string", "String"); + typeMapping.put("char", "Character"); + typeMapping.put("short", "Int"); + typeMapping.put("int", "Int"); + typeMapping.put("long", "Int64"); + typeMapping.put("integer", "Int"); + typeMapping.put("Integer", "Int"); + typeMapping.put("float", "Float"); + typeMapping.put("number", "Double"); + typeMapping.put("double", "Double"); + typeMapping.put("object", "Any"); + typeMapping.put("Object", "Any"); + typeMapping.put("file", "URL"); + typeMapping.put("binary", "Data"); + typeMapping.put("ByteArray", "Data"); + typeMapping.put("UUID", "UUID"); + typeMapping.put("URI", "String"); + typeMapping.put("BigDecimal", "Decimal"); + + importMapping = new HashMap<>(); + + cliOptions.add(new CliOption(PROJECT_NAME, "Project name in Xcode")); + cliOptions.add(new CliOption(RESPONSE_AS, + "Optionally use libraries to manage response. Currently " + + StringUtils.join(RESPONSE_LIBRARIES, ", ") + + " are available.")); + cliOptions.add(new CliOption(UNWRAP_REQUIRED, + "Treat 'required' properties in response as non-optional " + + "(which would crash the app if api returns null as opposed " + + "to required option specified in json schema")); + cliOptions.add(new CliOption(OBJC_COMPATIBLE, + "Add additional properties and methods for Objective-C " + + "compatibility (default: false)")); + cliOptions.add(new CliOption(POD_SOURCE, "Source information used for Podspec")); + cliOptions.add(new CliOption(CodegenConstants.POD_VERSION, "Version used for Podspec")); + cliOptions.add(new CliOption(POD_AUTHORS, "Authors used for Podspec")); + cliOptions.add(new CliOption(POD_SOCIAL_MEDIA_URL, "Social Media URL used for Podspec")); + cliOptions.add(new CliOption(POD_DOCSET_URL, "Docset URL used for Podspec")); + cliOptions.add(new CliOption(POD_LICENSE, "License used for Podspec")); + cliOptions.add(new CliOption(POD_HOMEPAGE, "Homepage used for Podspec")); + cliOptions.add(new CliOption(POD_SUMMARY, "Summary used for Podspec")); + cliOptions.add(new CliOption(POD_DESCRIPTION, "Description used for Podspec")); + cliOptions.add(new CliOption(POD_SCREENSHOTS, "Screenshots used for Podspec")); + cliOptions.add(new CliOption(POD_DOCUMENTATION_URL, + "Documentation URL used for Podspec")); + cliOptions.add(new CliOption(SWIFT_USE_API_NAMESPACE, + "Flag to make all the API classes inner-class " + + "of {{projectName}}API")); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, + CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC) + .defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(LENIENT_TYPE_CAST, + "Accept and cast values for simple types (string->bool, " + + "string->int, int->string)") + .defaultValue(Boolean.FALSE.toString())); + } + + @Override + public void processOpts() { + super.processOpts(); + + /* + * Template Location. This is the location which templates will be read from. The generator + * will use the resource stream to attempt to read the templates. + */ + if (StringUtils.isBlank(templateDir)) { + embeddedTemplateDir = templateDir = getTemplateDir(); + } + + // Setup project name + if (additionalProperties.containsKey(PROJECT_NAME)) { + setProjectName((String) additionalProperties.get(PROJECT_NAME)); + } else { + additionalProperties.put(PROJECT_NAME, projectName); + } + sourceFolder = projectName + File.separator + sourceFolder; + + // Setup unwrapRequired option, which makes all the + // properties with "required" non-optional + if (additionalProperties.containsKey(UNWRAP_REQUIRED)) { + setUnwrapRequired(convertPropertyToBooleanAndWriteBack(UNWRAP_REQUIRED)); + } + additionalProperties.put(UNWRAP_REQUIRED, unwrapRequired); + + // Setup objcCompatible option, which adds additional properties + // and methods for Objective-C compatibility + if (additionalProperties.containsKey(OBJC_COMPATIBLE)) { + setObjcCompatible(convertPropertyToBooleanAndWriteBack(OBJC_COMPATIBLE)); + } + additionalProperties.put(OBJC_COMPATIBLE, objcCompatible); + + // Setup unwrapRequired option, which makes all the properties with "required" non-optional + if (additionalProperties.containsKey(RESPONSE_AS)) { + Object responseAsObject = additionalProperties.get(RESPONSE_AS); + if (responseAsObject instanceof String) { + setResponseAs(((String) responseAsObject).split(",")); + } else { + setResponseAs((String[]) responseAsObject); + } + } + additionalProperties.put(RESPONSE_AS, responseAs); + if (ArrayUtils.contains(responseAs, LIBRARY_PROMISE_KIT)) { + additionalProperties.put("usePromiseKit", true); + } + if (ArrayUtils.contains(responseAs, LIBRARY_RX_SWIFT)) { + additionalProperties.put("useRxSwift", true); + } + + // Setup swiftUseApiNamespace option, which makes all the API + // classes inner-class of {{projectName}}API + if (additionalProperties.containsKey(SWIFT_USE_API_NAMESPACE)) { + setSwiftUseApiNamespace(convertPropertyToBooleanAndWriteBack(SWIFT_USE_API_NAMESPACE)); + } + + if (!additionalProperties.containsKey(POD_AUTHORS)) { + additionalProperties.put(POD_AUTHORS, DEFAULT_POD_AUTHORS); + } + + setLenientTypeCast(convertPropertyToBooleanAndWriteBack(LENIENT_TYPE_CAST)); + + supportingFiles.add(new SupportingFile("Podspec.mustache", + "", + projectName + ".podspec")); + supportingFiles.add(new SupportingFile("Cartfile.mustache", + "", + "Cartfile")); + supportingFiles.add(new SupportingFile("APIHelper.mustache", + sourceFolder, + "APIHelper.swift")); + supportingFiles.add(new SupportingFile("AlamofireImplementations.mustache", + sourceFolder, + "AlamofireImplementations.swift")); + supportingFiles.add(new SupportingFile("Configuration.mustache", + sourceFolder, + "Configuration.swift")); + supportingFiles.add(new SupportingFile("Extensions.mustache", + sourceFolder, + "Extensions.swift")); + supportingFiles.add(new SupportingFile("Models.mustache", + sourceFolder, + "Models.swift")); + supportingFiles.add(new SupportingFile("APIs.mustache", + sourceFolder, + "APIs.swift")); + supportingFiles.add(new SupportingFile("CodableHelper.mustache", + sourceFolder, + "CodableHelper.swift")); + supportingFiles.add(new SupportingFile("JSONEncodableEncoding.mustache", + sourceFolder, + "JSONEncodableEncoding.swift")); + supportingFiles.add(new SupportingFile("JSONEncodingHelper.mustache", + sourceFolder, + "JSONEncodingHelper.swift")); + supportingFiles.add(new SupportingFile("JSONValue.mustache", + sourceFolder, + "JSONValue.swift")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", + "", + "git_push.sh")); + supportingFiles.add(new SupportingFile("gitignore.mustache", + "", + ".gitignore")); + + copyFistAllOfProperties = true; + + } + + @Override + protected boolean isReservedWord(String word) { + return word != null && reservedWords.contains(word); //don't lowercase as super does + } + + @Override + public String getDefaultTemplateDir() { + return "swift5"; + } + + @Override + public String escapeReservedWord(String name) { + if (this.reservedWordsMappings().containsKey(name)) { + return this.reservedWordsMappings().get(name); + } + return "_" + name; // add an underscore to the name + } + + @Override + public String modelFileFolder() { + return outputFolder + File.separator + sourceFolder + + modelPackage().replace('.', File.separatorChar); + } + + @Override + public String apiFileFolder() { + return outputFolder + File.separator + sourceFolder + + apiPackage().replace('.', File.separatorChar); + } + + @Override + public String getTypeDeclaration(Schema prop) { + if (prop instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema) prop; + Schema inner = arraySchema.getItems(); + return "[" + getTypeDeclaration(inner) + "]"; + } else if (prop instanceof MapSchema) { + MapSchema mp = (MapSchema) prop; + Object inner = mp.getAdditionalProperties(); + if (inner instanceof Schema) { + return "[String:" + getTypeDeclaration((Schema) inner) + "]"; + } + } + return super.getTypeDeclaration(prop); + } + + @Override + public String getSchemaType(Schema prop) { + String schemaType = super.getSchemaType(prop); + String type; + if (typeMapping.containsKey(schemaType)) { + type = typeMapping.get(schemaType); + if (languageSpecificPrimitives.contains(type) || defaultIncludes.contains(type)) { + return type; + } + } else { + type = schemaType; + } + return toModelName(type); + } + + @Override + public boolean isDataTypeFile(String dataType) { + return dataType != null && dataType.equals("URL"); + } + + @Override + public boolean isDataTypeBinary(final String dataType) { + return dataType != null && dataType.equals("Data"); + } + + /** + * Output the proper model name (capitalized). + * + * @param name the name of the model + * @return capitalized model name + */ + @Override + public String toModelName(String name) { + // FIXME parameter should not be assigned. Also declare it as "final" + name = sanitizeName(name); + + if (!StringUtils.isEmpty(modelNameSuffix)) { // set model suffix + name = name + "_" + modelNameSuffix; + } + + if (!StringUtils.isEmpty(modelNamePrefix)) { // set model prefix + name = modelNamePrefix + "_" + name; + } + + // camelize the model name + // phone_number => PhoneNumber + name = camelize(name); + + // model name cannot use reserved keyword, e.g. return + if (isReservedWord(name)) { + String modelName = "Model" + name; + LOGGER.warn(name + " (reserved word) cannot be used as model name. Renamed to " + + modelName); + return modelName; + } + + // model name starts with number + if (name.matches("^\\d.*")) { + // e.g. 200Response => Model200Response (after camelize) + String modelName = "Model" + name; + LOGGER.warn(name + + " (model name starts with number) cannot be used as model name." + + " Renamed to " + modelName); + return modelName; + } + + return name; + } + + /** + * Return the capitalized file name of the model. + * + * @param name the model name + * @return the file name of the model + */ + @Override + public String toModelFilename(String name) { + // should be the same as the model name + return toModelName(name); + } + + @Override + public String toDefaultValue(Schema prop) { + // nil + return null; + } + + @Override + public String toInstantiationType(Schema prop) { + if (prop instanceof MapSchema) { + MapSchema mapSchema = (MapSchema) prop; + if (mapSchema.getAdditionalProperties() != null && mapSchema.getAdditionalProperties() instanceof Schema) { + return getSchemaType((Schema) mapSchema.getAdditionalProperties()); + } + } else if (prop instanceof ArraySchema) { + ArraySchema ap = (ArraySchema) prop; + String inner = getSchemaType(ap.getItems()); + return "[" + inner + "]"; + } + return null; + } + + @Override + public String toApiName(String name) { + if (name.length() == 0) { + return "DefaultAPI"; + } + return initialCaps(name) + "API"; + } + + @Override + public String toOperationId(String operationId) { + operationId = camelize(sanitizeName(operationId), true); + + // Throw exception if method name is empty. + // This should not happen but keep the check just in case + if (StringUtils.isEmpty(operationId)) { + throw new RuntimeException("Empty method name (operationId) not allowed"); + } + + // method name cannot use reserved keyword, e.g. return + if (isReservedWord(operationId)) { + String newOperationId = camelize(("call_" + operationId), true); + LOGGER.warn(operationId + " (reserved word) cannot be used as method name." + + " Renamed to " + newOperationId); + return newOperationId; + } + + return operationId; + } + + @Override + public String toVarName(String name) { + // sanitize name + name = sanitizeName(name); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + // camelize the variable name + // pet_id => petId + name = camelize(name, true); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public String toParamName(String name) { + // sanitize name + name = sanitizeName(name); + + // replace - with _ e.g. created-at => created_at + name = name.replaceAll("-", "_"); + + // if it's all uppper case, do nothing + if (name.matches("^[A-Z_]*$")) { + return name; + } + + // camelize(lower) the variable name + // pet_id => petId + name = camelize(name, true); + + // for reserved word or word starting with number, append _ + if (isReservedWord(name) || name.matches("^\\d.*")) { + name = escapeReservedWord(name); + } + + return name; + } + + @Override + public CodegenModel fromModel(String name, Schema model, Map allDefinitions) { + CodegenModel codegenModel = super.fromModel(name, model, allDefinitions); + if (codegenModel.description != null) { + codegenModel.imports.add("ApiModel"); + } + if (allDefinitions != null) { + String parentSchema = codegenModel.parentSchema; + + // multilevel inheritance: reconcile properties of all the parents + while (parentSchema != null) { + final Schema parentModel = allDefinitions.get(parentSchema); + final CodegenModel parentCodegenModel = super.fromModel(codegenModel.parent, + parentModel, + allDefinitions); + reconcileProperties(codegenModel, parentCodegenModel); + + // get the next parent + parentSchema = parentCodegenModel.parentSchema; + } + } + + return codegenModel; + } + + protected void updateCodegenModelEnumVars(CodegenModel codegenModel) { + super.updateCodegenModelEnumVars(codegenModel); + for (CodegenProperty var : codegenModel.allVars) { + updateCodegenPropertyEnum(var); + } + } + + @Override + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation, Map definitions, OpenAPI openAPI) { + CodegenOperation codegenOperation = super.fromOperation(path, httpMethod, operation, definitions, openAPI); + + if (codegenOperation.returnType != null && codegenOperation.returnType.equals("Any")) { + codegenOperation.returnType = null; + } + + return codegenOperation; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public void setUnwrapRequired(boolean unwrapRequired) { + this.unwrapRequired = unwrapRequired; + } + + public void setObjcCompatible(boolean objcCompatible) { + this.objcCompatible = objcCompatible; + } + + public void setLenientTypeCast(boolean lenientTypeCast) { + this.lenientTypeCast = lenientTypeCast; + } + + public void setResponseAs(String[] responseAs) { + this.responseAs = responseAs; + } + + public void setSwiftUseApiNamespace(boolean swiftUseApiNamespace) { + this.swiftUseApiNamespace = swiftUseApiNamespace; + } + + @Override + public String toEnumValue(String value, String datatype) { + return String.valueOf(value); + } + + @Override + public String toEnumDefaultValue(String value, String datatype) { + return datatype + "_" + value; + } + + @Override + public String toEnumVarName(String name, String datatype) { + if (name.length() == 0) { + return "empty"; + } + + Pattern startWithNumberPattern = Pattern.compile("^\\d+"); + Matcher startWithNumberMatcher = startWithNumberPattern.matcher(name); + if (startWithNumberMatcher.find()) { + String startingNumbers = startWithNumberMatcher.group(0); + String nameWithoutStartingNumbers = name.substring(startingNumbers.length()); + + return "_" + startingNumbers + camelize(nameWithoutStartingNumbers, true); + } + + // for symbol, e.g. $, # + if (getSymbolName(name) != null) { + return camelize(WordUtils.capitalizeFully(getSymbolName(name).toUpperCase()), true); + } + + // Camelize only when we have a structure defined below + boolean camelized = false; + if (name.matches("[A-Z][a-z0-9]+[a-zA-Z0-9]*")) { + name = camelize(name, true); + camelized = true; + } + + // Reserved Name + String nameLowercase = StringUtils.lowerCase(name); + if (isReservedWord(nameLowercase)) { + return escapeReservedWord(nameLowercase); + } + + // Check for numerical conversions + if ("Int".equals(datatype) || "Int32".equals(datatype) || "Int64".equals(datatype) + || "Float".equals(datatype) || "Double".equals(datatype)) { + String varName = "number" + camelize(name); + varName = varName.replaceAll("-", "minus"); + varName = varName.replaceAll("\\+", "plus"); + varName = varName.replaceAll("\\.", "dot"); + return varName; + } + + // If we have already camelized the word, don't progress + // any further + if (camelized) { + return name; + } + + char[] separators = {'-', '_', ' ', ':', '(', ')'}; + return camelize(WordUtils.capitalizeFully(StringUtils.lowerCase(name), separators) + .replaceAll("[-_ :()]", ""), + true); + } + + @Override + public String toEnumName(CodegenProperty property) { + String enumName = toModelName(property.name); + + // Ensure that the enum type doesn't match a reserved word or + // the variable name doesn't match the generated enum type or the + // Swift compiler will generate an error + if (isReservedWord(property.datatypeWithEnum) + || toVarName(property.name).equals(property.datatypeWithEnum)) { + enumName = property.datatypeWithEnum + "Enum"; + } + + // TODO: toModelName already does something for names starting with number, + // so this code is probably never called + if (enumName.matches("\\d.*")) { // starts with number + return "_" + enumName; + } else { + return enumName; + } + } + + @Override + public Map postProcessModels(Map objs) { + Map postProcessedModelsEnum = postProcessModelsEnum(objs); + + // We iterate through the list of models, and also iterate through each of the + // properties for each model. For each property, if: + // + // CodegenProperty.name != CodegenProperty.baseName + // + // then we set + // + // CodegenProperty.vendorExtensions["x-codegen-escaped-property-name"] = true + // + // Also, if any property in the model has x-codegen-escaped-property-name=true, then we mark: + // + // CodegenModel.vendorExtensions["x-codegen-has-escaped-property-names"] = true + // + List models = (List) postProcessedModelsEnum.get("models"); + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + boolean modelHasPropertyWithEscapedName = false; + for (CodegenProperty prop : cm.allVars) { + if (!prop.name.equals(prop.baseName)) { + prop.vendorExtensions.put("x-codegen-escaped-property-name", true); + modelHasPropertyWithEscapedName = true; + } + } + if (modelHasPropertyWithEscapedName) { + cm.vendorExtensions.put("x-codegen-has-escaped-property-names", true); + } + } + + return postProcessedModelsEnum; + } + + @Override + public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { + super.postProcessModelProperty(model, property); + + // The default template code has the following logic for + // assigning a type as Swift Optional: + // + // {{^unwrapRequired}}?{{/unwrapRequired}} + // {{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}} + // + // which means: + // + // boolean isSwiftOptional = !unwrapRequired || (unwrapRequired && !property.required); + // + // We can drop the check for unwrapRequired in (unwrapRequired && !property.required) + // due to short-circuit evaluation of the || operator. + boolean isSwiftOptional = !unwrapRequired || !property.required; + boolean isSwiftScalarType = getBooleanValue(property, CodegenConstants.IS_INTEGER_EXT_NAME) + || getBooleanValue(property, CodegenConstants.IS_LONG_EXT_NAME) + || getBooleanValue(property, CodegenConstants.IS_FLOAT_EXT_NAME) + || getBooleanValue(property, CodegenConstants.IS_DOUBLE_EXT_NAME) + || getBooleanValue(property, CodegenConstants.IS_BOOLEAN_EXT_NAME); + + if (isSwiftOptional && isSwiftScalarType) { + // Optional scalar types like Int?, Int64?, Float?, Double?, and Bool? + // do not translate to Objective-C. So we want to flag those + // properties in case we want to put special code in the templates + // which provide Objective-C compatibility. + property.vendorExtensions.put("x-swift-optional-scalar", true); + } + } + + @Override + public String escapeQuotationMark(String input) { + // remove " to avoid code injection + return input.replace("\"", ""); + } + + @Override + public String escapeUnsafeCharacters(String input) { + return input.replace("*/", "*_/").replace("/*", "/_*"); + } + + private static void reconcileProperties(CodegenModel codegenModel, + CodegenModel parentCodegenModel) { + // To support inheritance in this generator, we will analyze + // the parent and child models, look for properties that match, and remove + // them from the child models and leave them in the parent. + // Because the child models extend the parents, the properties + // will be available via the parent. + + // Get the properties for the parent and child models + final List parentModelCodegenProperties = parentCodegenModel.vars; + List codegenProperties = codegenModel.vars; + codegenModel.allVars = new ArrayList<>(codegenProperties); + codegenModel.parentVars = parentCodegenModel.allVars; + + // Iterate over all of the parent model properties + boolean removedChildProperty = false; + + for (CodegenProperty parentModelCodegenProperty : parentModelCodegenProperties) { + // Now that we have found a prop in the parent class, + // and search the child class for the same prop. + Iterator iterator = codegenProperties.iterator(); + while (iterator.hasNext()) { + CodegenProperty codegenProperty = iterator.next(); + if (codegenProperty.baseName.equals(parentModelCodegenProperty.baseName)) { + // We found a property in the child class that is + // a duplicate of the one in the parent, so remove it. + iterator.remove(); + removedChildProperty = true; + } + } + } + + if (removedChildProperty) { + // If we removed an entry from this model's vars, we need to ensure hasMore is updated + int count = 0; + int numVars = codegenProperties.size(); + for (CodegenProperty codegenProperty : codegenProperties) { + count += 1; + codegenProperty.getVendorExtensions().put(CodegenConstants.HAS_MORE_EXT_NAME, count < numVars); + } + codegenModel.vars = codegenProperties; + } + } +} + diff --git a/src/main/java/io/swagger/codegen/v3/generators/typescript/AbstractTypeScriptClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/typescript/AbstractTypeScriptClientCodegen.java index 2a62c72b41..0d173042ae 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/typescript/AbstractTypeScriptClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/typescript/AbstractTypeScriptClientCodegen.java @@ -5,11 +5,16 @@ import io.swagger.codegen.v3.CodegenModel; import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.ISchemaHandler; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.util.OpenAPIUtil; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.BooleanSchema; +import io.swagger.v3.oas.models.media.BinarySchema; +import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.DateSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; +import io.swagger.v3.oas.models.media.FileSchema; import io.swagger.v3.oas.models.media.IntegerSchema; import io.swagger.v3.oas.models.media.MapSchema; import io.swagger.v3.oas.models.media.NumberSchema; @@ -27,13 +32,15 @@ import java.util.List; import java.util.Map; import java.util.TreeSet; +import java.util.stream.Collectors; import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.CodegenConstants.IS_OBJECT_EXT_NAME; import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; public abstract class AbstractTypeScriptClientCodegen extends DefaultCodegenConfig { - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTypeScriptClientCodegen.class); + protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractTypeScriptClientCodegen.class); private static final String UNDEFINED_VALUE = "undefined"; @@ -90,6 +97,7 @@ public AbstractTypeScriptClientCodegen() { typeMapping.put("int", "number"); typeMapping.put("float", "number"); typeMapping.put("number", "number"); + typeMapping.put("BigDecimal", "number"); typeMapping.put("long", "number"); typeMapping.put("short", "number"); typeMapping.put("char", "string"); @@ -109,7 +117,6 @@ public AbstractTypeScriptClientCodegen() { cliOptions.add(new CliOption(CodegenConstants.MODEL_PROPERTY_NAMING, CodegenConstants.MODEL_PROPERTY_NAMING_DESC).defaultValue("camelCase")); cliOptions.add(new CliOption(CodegenConstants.SUPPORTS_ES6, CodegenConstants.SUPPORTS_ES6_DESC).defaultValue("false")); - } @Override @@ -222,19 +229,48 @@ public String toModelFilename(String name) { return toModelName(name); } + @Override + public CodegenModel fromModel(String name, Schema schema, Map allDefinitions) { + final CodegenModel codegenModel = super.fromModel(name, schema, allDefinitions); + if (isObjectSchema(schema) || schema instanceof MapSchema) { + codegenModel.getVendorExtensions().put(CodegenConstants.IS_OBJECT_EXT_NAME, Boolean.TRUE); + } + return codegenModel; + } + @Override public String getTypeDeclaration(Schema propertySchema) { - if (propertySchema instanceof ArraySchema) { - Schema inner = ((ArraySchema) propertySchema).getItems(); - return String.format("%s<%s>", getSchemaType(propertySchema), getTypeDeclaration(inner)); - } else if (propertySchema instanceof MapSchema && hasSchemaProperties(propertySchema)) { - Schema inner = (Schema) propertySchema.getAdditionalProperties(); - return String.format("{ [key, string]: %s;}", getTypeDeclaration(inner)); + Schema inner; + if(propertySchema instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema)propertySchema; + inner = arraySchema.getItems(); + return this.getSchemaType(propertySchema) + "<" + this.getTypeDeclaration(inner) + ">"; + } else if(propertySchema instanceof MapSchema && hasSchemaProperties(propertySchema)) { + inner = (Schema) propertySchema.getAdditionalProperties(); + return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }"; } else if (propertySchema instanceof MapSchema && hasTrueAdditionalProperties(propertySchema)) { - Schema inner = new ObjectSchema(); - return String.format("{ [key, string]: %s;}", getTypeDeclaration(inner)); + inner = new ObjectSchema(); + return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }"; + } else if(propertySchema instanceof FileSchema || propertySchema instanceof BinarySchema) { + return "Blob"; + } else if(propertySchema instanceof ObjectSchema) { + return "any"; + } else { + return super.getTypeDeclaration(propertySchema); + } + } + + @Override + public void addImport(CodegenModel codegenModel, String type) { + if (type == null) { + return; + } + String[] names = type.split("( [|&] )|[<>]"); + for (String name : names) { + if (needToImport(name)) { + codegenModel.imports.add(name); + } } - return super.getTypeDeclaration(propertySchema); } @Override @@ -269,18 +305,47 @@ public String toDefaultValue(Schema propertySchema) { } @Override - public String getSchemaType(Schema schema) { + public String getSchemaType(Schema schema) { String swaggerType = super.getSchemaType(schema); + if (swaggerType == null) { + // default to object, see #10496 + swaggerType = "object"; + } + if (schema instanceof ComposedSchema) { + ComposedSchema composedSchema = (ComposedSchema)schema; + if (composedSchema.getAllOf() != null && !composedSchema.getAllOf().isEmpty()) { + return String.join(" & ", getTypesFromInterfaces(composedSchema.getAllOf())); + } else if (composedSchema.getOneOf() != null && !composedSchema.getOneOf().isEmpty()) { + return String.join(" | ", getTypesFromInterfaces(composedSchema.getOneOf())); + } else if (composedSchema.getAnyOf() != null && !composedSchema.getAnyOf().isEmpty()) { + return String.join(" | ", getTypesFromInterfaces(composedSchema.getAnyOf())); + } else { + return "object"; + } + } String type = null; if (typeMapping.containsKey(swaggerType)) { type = typeMapping.get(swaggerType); if (languageSpecificPrimitives.contains(type)) return type; - } else + } else { type = swaggerType; + } return toModelName(type); } + private List getTypesFromInterfaces(List interfaces) { + return interfaces.stream().map(schema -> { + String schemaType = getSchemaType(schema); + if (schema instanceof ArraySchema) { + ArraySchema ap = (ArraySchema) schema; + Schema inner = ap.getItems(); + schemaType = schemaType + "<" + getSchemaType(inner) + ">"; + } + return schemaType; + }).distinct().collect(Collectors.toList()); + } + @Override public String toOperationId(String operationId) { // throw exception if method name is empty @@ -402,7 +467,7 @@ public Map postProcessModels(Map objs) { var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + "." + var.enumName); } } - } + } return objs; } @@ -425,4 +490,9 @@ public String escapeQuotationMark(String input) { public String escapeUnsafeCharacters(String input) { return input.replace("*/", "*_/").replace("/*", "/_*"); } + + @Override + public ISchemaHandler getSchemaHandler() { + return new TypeScriptSchemaHandler(this); + } } diff --git a/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAngularClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAngularClientCodegen.java index 5a7823e1df..d41e86ae26 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAngularClientCodegen.java +++ b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAngularClientCodegen.java @@ -15,6 +15,7 @@ import io.swagger.codegen.v3.CodegenParameter; import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.utils.ModelUtils; import io.swagger.codegen.v3.utils.SemVer; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.BinarySchema; @@ -27,6 +28,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCodegen { private static Logger LOGGER = LoggerFactory.getLogger(TypeScriptAngularClientCodegen.class); @@ -39,10 +43,15 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode public static final String SNAPSHOT = "snapshot"; public static final String WITH_INTERFACES = "withInterfaces"; public static final String NG_VERSION = "ngVersion"; + public static final String NG_PACKAGR = "useNgPackagr"; + public static final String PROVIDED_IN_ROOT ="providedInRoot"; + public static final String KEBAB_FILE_NAME ="kebab-file-name"; + public static final String USE_OVERRIDE ="useOverride"; protected String npmName = null; protected String npmVersion = "1.0.0"; protected String npmRepository = null; + protected boolean kebabFileNaming; public TypeScriptAngularClientCodegen() { super(); @@ -54,6 +63,8 @@ public TypeScriptAngularClientCodegen() { this.cliOptions.add(new CliOption(SNAPSHOT, "When setting this property to true the version will be suffixed with -SNAPSHOT.yyyyMMddHHmm", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); this.cliOptions.add(new CliOption(WITH_INTERFACES, "Setting this property to true will generate interfaces next to the default class implementations.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); this.cliOptions.add(new CliOption(NG_VERSION, "The version of Angular. Default is '4.3'")); + this.cliOptions.add(new CliOption(PROVIDED_IN_ROOT, "Use this property to provide Injectables in root (it is only valid in angular version greater or equal to 6.0.0).", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); + this.cliOptions.add(new CliOption(USE_OVERRIDE, "Use this property to place `override` keyword in encoder methods.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); } @Override @@ -80,10 +91,6 @@ public String getHelp() { public void processOpts() { super.processOpts(); - if (StringUtils.isBlank(templateDir)) { - embeddedTemplateDir = templateDir = getTemplateDir(); - } - modelTemplateFiles.put("model.mustache", ".ts"); apiTemplateFiles.put("api.service.mustache", ".ts"); @@ -102,10 +109,77 @@ public void processOpts() { supportingFiles.add(new SupportingFile("variables.mustache", getIndexDirectory(), "variables.ts")); supportingFiles.add(new SupportingFile("encoder.mustache", getIndexDirectory(), "encoder.ts")); supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore")); + supportingFiles.add(new SupportingFile("npmignore", "", ".npmignore")); supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + SemVer ngVersion = determineNgVersion(); + + additionalProperties.put(NG_VERSION, ngVersion); + + // for Angular 2 AOT support we will use good-old ngc, + // Angular Package format wasn't invented at this time and building was much more easier + if (!ngVersion.atLeast("4.0.0")) { + LOGGER.warn("Please update your legacy Angular " + ngVersion + " project to benefit from 'Angular Package Format' support."); + additionalProperties.put(NG_PACKAGR, false); + } else { + additionalProperties.put(NG_PACKAGR, true); + } + + // Set the rxJS version compatible to the Angular version + if (ngVersion.atLeast("8.0.0")) { + additionalProperties.put("rxjsVersion", "6.5.0"); + additionalProperties.put("useRxJS6", true); + } else if (ngVersion.atLeast("7.0.0")) { + additionalProperties.put("rxjsVersion", "6.3.0"); + additionalProperties.put("useRxJS6", true); + } else if (ngVersion.atLeast("6.0.0")) { + additionalProperties.put("rxjsVersion", "6.1.0"); + additionalProperties.put("useRxJS6", true); + } else { + // Angular prior to v6 + additionalProperties.put("rxjsVersion", "5.4.0"); + } + if (!ngVersion.atLeast("4.3.0")) { + supportingFiles.add(new SupportingFile("rxjs-operators.mustache", getIndexDirectory(), "rxjs-operators.ts")); + } + + // Version after Angular 10 require ModuleWithProviders to be generic. Compatible from version 7. + if (ngVersion.atLeast("7.0.0")) { + additionalProperties.put("genericModuleWithProviders", true); + } + + // for Angular 2 AOT support we will use good-old ngc, + // Angular Package format wasn't invented at this time and building was much more easier + if (!ngVersion.atLeast("4.0.0")) { + LOGGER.warn("Please update your legacy Angular " + ngVersion + " project to benefit from 'Angular Package Format' support."); + additionalProperties.put("useNgPackagr", false); + } else { + additionalProperties.put("useNgPackagr", true); + supportingFiles.add(new SupportingFile("ng-package.mustache", getIndexDirectory(), "ng-package.json")); + } + + // Libraries generated with v1.x of ng-packagr will ship with AoT metadata in v3, which is intended for Angular v4. + // Libraries generated with v2.x of ng-packagr will ship with AoT metadata in v4, which is intended for Angular v5 (and Angular v6). + additionalProperties.put("useOldNgPackagr", !ngVersion.atLeast("5.0.0")); + + // set http client usage + if (ngVersion.atLeast("8.0.0")) { + additionalProperties.put("useHttpClient", true); + } else if (ngVersion.atLeast("4.3.0")) { + additionalProperties.put("useHttpClient", true); + } else { + additionalProperties.put("useHttpClient", false); + } + + if (additionalProperties.containsKey(PROVIDED_IN_ROOT) && !ngVersion.atLeast("6.0.0")) { + additionalProperties.put(PROVIDED_IN_ROOT,false); + } + + additionalProperties.put("injectionToken", ngVersion.atLeast("4.0.0") ? "InjectionToken" : "OpaqueToken"); + additionalProperties.put("injectionTokenTyped", ngVersion.atLeast("4.0.0")); + if (additionalProperties.containsKey(NPM_NAME)) { - addNpmPackageGeneration(); + addNpmPackageGeneration(ngVersion); } if (additionalProperties.containsKey(WITH_INTERFACES)) { @@ -115,25 +189,28 @@ public void processOpts() { } } - // determine NG version + if (additionalProperties.containsKey(USE_OVERRIDE)) { + final boolean useOverride = Boolean.parseBoolean(String.valueOf(additionalProperties.get(USE_OVERRIDE))); + additionalProperties.put(USE_OVERRIDE, useOverride); + } + + kebabFileNaming = Boolean.parseBoolean(String.valueOf(additionalProperties.get(KEBAB_FILE_NAME))); + + } + + private SemVer determineNgVersion() { SemVer ngVersion; if (additionalProperties.containsKey(NG_VERSION)) { ngVersion = new SemVer(additionalProperties.get(NG_VERSION).toString()); } else { - ngVersion = new SemVer("6.0.0"); + ngVersion = new SemVer("8.0.0"); LOGGER.info("generating code for Angular {} ...", ngVersion); LOGGER.info(" (you can select the angular version by setting the additionalProperty ngVersion)"); } - additionalProperties.put(NG_VERSION, ngVersion); - additionalProperties.put("injectionToken", ngVersion.atLeast("4.0.0") ? "InjectionToken" : "OpaqueToken"); - additionalProperties.put("injectionTokenTyped", ngVersion.atLeast("4.0.0")); - additionalProperties.put("useHttpClient", ngVersion.atLeast("4.3.0")); - if (!ngVersion.atLeast("4.3.0")) { - supportingFiles.add(new SupportingFile("rxjs-operators.mustache", getIndexDirectory(), "rxjs-operators.ts")); - } + return ngVersion; } - private void addNpmPackageGeneration() { + private void addNpmPackageGeneration(SemVer ngVersion) { if (additionalProperties.containsKey(NPM_NAME)) { this.setNpmName(additionalProperties.get(NPM_NAME).toString()); } @@ -142,8 +219,7 @@ private void addNpmPackageGeneration() { this.setNpmVersion(additionalProperties.get(NPM_VERSION).toString()); } - if (additionalProperties.containsKey(SNAPSHOT) - && Boolean.valueOf(additionalProperties.get(SNAPSHOT).toString())) { + if (additionalProperties.containsKey(SNAPSHOT) && Boolean.parseBoolean(additionalProperties.get(SNAPSHOT).toString())) { this.setNpmVersion(npmVersion + "-SNAPSHOT." + SNAPSHOT_SUFFIX_FORMAT.format(new Date())); } additionalProperties.put(NPM_VERSION, npmVersion); @@ -152,11 +228,79 @@ private void addNpmPackageGeneration() { this.setNpmRepository(additionalProperties.get(NPM_REPOSITORY).toString()); } + additionalProperties.put("useHttpClientPackage", false); + if (ngVersion.atLeast("15.0.0")) { + additionalProperties.put("tsVersion", ">=4.8.2 <4.10.0"); + additionalProperties.put("rxjsVersion", "7.5.5"); + additionalProperties.put("ngPackagrVersion", "15.0.2"); + additionalProperties.put("zonejsVersion", "0.11.5"); + } else if (ngVersion.atLeast("14.0.0")) { + additionalProperties.put("tsVersion", ">=4.6.0 <=4.8.0"); + additionalProperties.put("rxjsVersion", "7.5.5"); + additionalProperties.put("ngPackagrVersion", "14.0.2"); + additionalProperties.put("zonejsVersion", "0.11.5"); + } else if (ngVersion.atLeast("13.0.0")) { + additionalProperties.put("tsVersion", ">=4.4.2 <4.5.0"); + additionalProperties.put("rxjsVersion", "7.4.0"); + additionalProperties.put("ngPackagrVersion", "13.0.3"); + additionalProperties.put("zonejsVersion", "0.11.4"); + } else if (ngVersion.atLeast("12.0.0")) { + additionalProperties.put("tsVersion", ">=4.3.0 <4.4.0"); + additionalProperties.put("rxjsVersion", "7.4.0"); + additionalProperties.put("ngPackagrVersion", "12.2.1"); + additionalProperties.put("zonejsVersion", "0.11.4"); + } else if (ngVersion.atLeast("11.0.0")) { + additionalProperties.put("tsVersion", ">=4.0.0 <4.1.0"); + additionalProperties.put("rxjsVersion", "6.6.0"); + additionalProperties.put("ngPackagrVersion", "11.0.2"); + additionalProperties.put("zonejsVersion", "0.11.3"); + } else if (ngVersion.atLeast("10.0.0")) { + additionalProperties.put("tsVersion", ">=3.9.2 <4.0.0"); + additionalProperties.put("rxjsVersion", "6.6.0"); + additionalProperties.put("ngPackagrVersion", "10.0.3"); + additionalProperties.put("zonejsVersion", "0.10.2"); + } else if (ngVersion.atLeast("9.0.0")) { + additionalProperties.put("tsVersion", ">=3.6.0 <3.8.0"); + additionalProperties.put("rxjsVersion", "6.5.3"); + additionalProperties.put("ngPackagrVersion", "9.0.1"); + additionalProperties.put("zonejsVersion", "0.10.2"); + } else if (ngVersion.atLeast("8.0.0")) { + additionalProperties.put("tsVersion", ">=3.4.0 <3.6.0"); + additionalProperties.put("rxjsVersion", "6.5.0"); + additionalProperties.put("ngPackagrVersion", "5.4.0"); + additionalProperties.put("zonejsVersion", "0.9.1"); + } else if (ngVersion.atLeast("7.0.0")) { + additionalProperties.put("tsVersion", ">=3.1.1 <3.2.0"); + additionalProperties.put("rxjsVersion", "6.3.0"); + additionalProperties.put("ngPackagrVersion", "5.1.0"); + additionalProperties.put("zonejsVersion", "0.8.26"); + + additionalProperties.put("useHttpClientPackage", true); + } else if (ngVersion.atLeast("6.0.0")) { + additionalProperties.put("tsVersion", ">=2.7.2 and <2.10.0"); + additionalProperties.put("rxjsVersion", "6.1.0"); + additionalProperties.put("ngPackagrVersion", "3.0.6"); + additionalProperties.put("zonejsVersion", "0.8.26"); + + additionalProperties.put("useHttpClientPackage", true); + } else { + additionalProperties.put("tsVersion", ">=2.1.5 and <2.8"); + additionalProperties.put("rxjsVersion", "6.1.0"); + additionalProperties.put("ngPackagrVersion", "3.0.6"); + additionalProperties.put("zonejsVersion", "0.8.26"); + + additionalProperties.put("useHttpClientPackage", true); + } + //Files for building our lib supportingFiles.add(new SupportingFile("README.mustache", getIndexDirectory(), "README.md")); supportingFiles.add(new SupportingFile("package.mustache", getIndexDirectory(), "package.json")); supportingFiles.add(new SupportingFile("typings.mustache", getIndexDirectory(), "typings.json")); supportingFiles.add(new SupportingFile("tsconfig.mustache", getIndexDirectory(), "tsconfig.json")); + if (additionalProperties.containsKey(NG_PACKAGR) + && Boolean.valueOf(additionalProperties.get(NG_PACKAGR).toString())) { + supportingFiles.add(new SupportingFile("ng-package.mustache", getIndexDirectory(), "ng-package.json")); + } } private String getIndexDirectory() { @@ -231,6 +375,24 @@ private boolean isLanguageGenericType(String type) { return false; } + protected void addOperationImports(CodegenOperation codegenOperation, Set operationImports) { + for (String operationImport : operationImports) { + if (operationImport.contains("|")) { + String[] importNames = operationImport.split("\\|"); + for (String importName : importNames) { + importName = importName.trim(); + if (needToImport(importName)) { + codegenOperation.imports.add(importName); + } + } + } else { + if (needToImport(operationImport)) { + codegenOperation.imports.add(operationImport); + } + } + } + } + @Override public void postProcessParameter(CodegenParameter parameter) { super.postProcessParameter(parameter); @@ -341,6 +503,21 @@ public Map postProcessModels(Map objs) { return result; } + @Override + public Map postProcessAllModels(Map processedModels) { + for (Map.Entry entry : processedModels.entrySet()) { + final Map inner = (Map) entry.getValue(); + final List> models = (List>) inner.get("models"); + for (Map mo : models) { + final CodegenModel codegenModel = (CodegenModel) mo.get("model"); + if (codegenModel.getIsAlias() && codegenModel.imports != null && !codegenModel.imports.isEmpty()) { + mo.put("tsImports", toTsImports(codegenModel, codegenModel.imports)); + } + } + } + return processedModels; + } + private List> toTsImports(CodegenModel cm, Set imports) { List> tsImports = new ArrayList<>(); for (String im : imports) { @@ -367,6 +544,9 @@ public String toApiFilename(String name) { if (name.length() == 0) { return "default.service"; } + if (kebabFileNaming) { + return dashize(name); + } return camelize(name, true) + ".service"; } @@ -377,6 +557,9 @@ public String toApiImport(String name) { @Override public String toModelFilename(String name) { + if (kebabFileNaming) { + return dashize(name); + } return camelize(toModelName(name), true); } diff --git a/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAxiosClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAxiosClientCodegen.java new file mode 100644 index 0000000000..cf2f5fa4a6 --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptAxiosClientCodegen.java @@ -0,0 +1,298 @@ +package io.swagger.codegen.v3.generators.typescript; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenOperation; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.SupportingFile; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeSet; + +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +public class TypeScriptAxiosClientCodegen extends AbstractTypeScriptClientCodegen { + + public static final String NPM_NAME = "npmName"; + public static final String NPM_VERSION = "npmVersion"; + public static final String NPM_REPOSITORY = "npmRepository"; + public static final String DEFAULT_API_PACKAGE = "apis"; + public static final String DEFAULT_MODEL_PACKAGE = "models"; + + protected String npmRepository = null; + protected String npmName = null; + protected String npmVersion = "1.0.0"; + + + private String tsModelPackage = ""; + + public TypeScriptAxiosClientCodegen() { + super(); + importMapping.clear(); + outputFolder = "generated-code/typescript-axios"; + LOGGER.info("Template folder: " + this.templateDir()); + LOGGER.info("Template engine: " + this.getTemplateEngine()); + reservedWords.add("query"); + + // Custom CLI options + this.cliOptions.add(new CliOption(NPM_NAME, "The name under which you want to publish generated npm package")); + this.cliOptions.add(new CliOption(NPM_VERSION, "The version of your npm package. Defaults to 1.0.0")); + this.cliOptions.add(new CliOption(NPM_REPOSITORY, + "Use this property to set an url your private npm registry in the package.json")); + } + + @Override + public String getName() { + return "typescript-axios"; + } + + @Override + public String getHelp() { + return "Generates a TypeScript Axios client library."; + } + + /** + * Creates a relative path to a file or folder. The resulting path is + * relative to the root directory of the final client library. + * + * @param path The path to the file or folder. + * @return A path to the file or folder which is relative to the client + * library root directory. + */ + private static String getRelativeToRoot(String path) { + StringBuilder sb = new StringBuilder(); + int slashCount = path.split("/").length; + if (slashCount == 0) { + sb.append("./"); + } else { + for (int i = 0; i < slashCount; ++i) { + sb.append("../"); + } + } + return sb.toString(); + } + + @Override + public void processOpts() { + super.processOpts(); + if (StringUtils.isBlank(modelPackage)) { + modelPackage = DEFAULT_MODEL_PACKAGE; + } + if (StringUtils.isBlank(apiPackage)) { + apiPackage = DEFAULT_API_PACKAGE; + } + tsModelPackage = modelPackage.replaceAll("\\.", "/"); + String tsApiPackage = apiPackage.replaceAll("\\.", "/"); + + String modelRelativeToRoot = getRelativeToRoot(tsModelPackage); + String apiRelativeToRoot = getRelativeToRoot(tsApiPackage); + + additionalProperties.put("tsModelPackage", tsModelPackage); + additionalProperties.put("tsApiPackage", tsApiPackage); + additionalProperties.put("apiRelativeToRoot", apiRelativeToRoot); + additionalProperties.put("modelRelativeToRoot", modelRelativeToRoot); + + supportingFiles.add(new SupportingFile("index.mustache", "", "index.ts")); + supportingFiles.add(new SupportingFile("baseApi.mustache", "", "base.ts")); + supportingFiles.add(new SupportingFile("api.mustache", "", "api.ts")); + supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.ts")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore")); + supportingFiles.add(new SupportingFile("npmignore", "", ".npmignore")); + + modelTemplateFiles.put("model.mustache", ".ts"); + apiTemplateFiles.put("apiInner.mustache", ".ts"); + supportingFiles.add(new SupportingFile("modelIndex.mustache", tsModelPackage, "index.ts")); + + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json")); + + addNpmPackageGeneration(); + } + + @Override + public Map postProcessOperations(Map operations) { + boolean hasImports = operations.get("hasImport") != null && Boolean.parseBoolean(operations.get("hasImport").toString()); + if (hasImports) { + List> imports = (List>) operations.get("imports"); + + for (Map importMap : imports) { + final String importValue = importMap.get("import"); + if (StringUtils.isNotBlank(importValue) && importValue.contains(".")) { + int index = importValue.indexOf("."); + importMap.put("import", importValue.substring(index + 1)); + } + } + } + return operations; + } + + @Override + public Map postProcessOperationsWithModels(Map objs, List allModels) { + objs = super.postProcessOperationsWithModels(objs, allModels); + Map vals = (Map) objs.getOrDefault("operations", new HashMap<>()); + List operations = (List) vals.getOrDefault("operation", new ArrayList<>()); + /* + Filter all the operations that are multipart/form-data operations and set the vendor extension flag + 'multipartFormData' for the template to work with. + */ + operations.stream() + .filter(op -> getBooleanValue(op, CodegenConstants.HAS_CONSUMES_EXT_NAME)) + .filter(op -> op.consumes.stream().anyMatch(opc -> opc.values().stream().anyMatch("multipart/form-data"::equals))) + .forEach(op -> op.vendorExtensions.putIfAbsent("multipartFormData", true)); + return objs; + } + + @Override + public Map postProcessAllModels(Map objs) { + Map result = super.postProcessAllModels(objs); + for (Map.Entry entry : result.entrySet()) { + Map inner = (Map) entry.getValue(); + List> models = (List>) inner.get("models"); + for (Map model : models) { + CodegenModel codegenModel = (CodegenModel) model.get("model"); + //todo: model.put("hasAllOf", codegenModel.allOf.size() > 0); + //todo: model.put("hasOneOf", codegenModel.oneOf.size() > 0); + } + } + return result; + } + + + @Override + public Map postProcessModels(Map objs) { + List models = (List) postProcessModelsEnum(objs).get("models"); + + for (Object _mo : models) { + Map mo = (Map) _mo; + CodegenModel cm = (CodegenModel) mo.get("model"); + + // Deduce the model file name in kebab case + cm.classFilename = cm.classname.replaceAll("([a-z0-9])([A-Z])", "$1-$2").toLowerCase(Locale.ROOT); + + //processed enum names + cm.imports = new TreeSet(cm.imports); + // name enum with model name, e.g. StatusEnum => PetStatusEnum + for (CodegenProperty var : cm.vars) { + if (getBooleanValue(var, CodegenConstants.IS_ENUM_EXT_NAME)) { + var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + var.enumName); + var.enumName = var.enumName.replace(var.enumName, cm.classname + var.enumName); + } + } + if (cm.parent != null) { + for (CodegenProperty var : cm.allVars) { + if (getBooleanValue(var, CodegenConstants.IS_ENUM_EXT_NAME)) { + var.datatypeWithEnum = var.datatypeWithEnum.replace(var.enumName, cm.classname + var.enumName); + var.enumName = var.enumName.replace(var.enumName, cm.classname + var.enumName); + } + } + } + } + + // Apply the model file name to the imports as well + for (Map m : (List>) objs.get("imports")) { + String javaImport = m.get("import").substring(modelPackage.length() + 1); + String tsImport = tsModelPackage + "/" + javaImport; + m.put("tsImport", tsImport); + m.put("class", javaImport); + m.put("filename", javaImport.replaceAll("([a-z0-9])([A-Z])", "$1-$2").toLowerCase(Locale.ROOT)); + } + return objs; + } + + /** + * Extracts npm package fields from `additionalProperties`. These fields + * are provided as custom CLI options. + */ + private void addNpmPackageGeneration() { + // Name of the NPM package + if (additionalProperties.containsKey(NPM_NAME)) { + this.setNpmName(additionalProperties.get(NPM_NAME).toString()); + } + + // NPM package version (SemVer) + if (additionalProperties.containsKey(NPM_VERSION)) { + this.setNpmVersion(additionalProperties.get(NPM_VERSION).toString()); + } + /* Package version has default value. Make internal version and + * additionalProperties version consistent. + */ + additionalProperties.put(NPM_VERSION, npmVersion); + + // NPM registry the package is pushed to + if (additionalProperties.containsKey(NPM_REPOSITORY)) { + this.setNpmRepository(additionalProperties.get(NPM_REPOSITORY).toString()); + } + } + + /** + * Overriding toRegularExpression() to avoid escapeText() being called, + * as it would return a broken regular expression if any escaped character / metacharacter were present. + */ + @Override + public String toRegularExpression(String pattern) { + return addRegularExpressionDelimiter(pattern); + } + + @Override + public String toModelFilename(String name) { + return super.toModelFilename(name).replaceAll("([a-z0-9])([A-Z])", "$1-$2").toLowerCase(Locale.ROOT); + } + + @Override + public String toApiFilename(String name) { + return super.toApiFilename(name).replaceAll("([a-z0-9])([A-Z])", "$1-$2").toLowerCase(Locale.ROOT); + } + + @Override + public String getDefaultTemplateDir() { + return "typescript-axios"; + } + + /** + * Gets the name of the generated NPM package. + * + * @return The NPM package name. + */ + public String getNpmName() { + return this.npmName; + } + + public void setNpmName(String npmName) { + this.npmName = npmName; + } + + /** + * Gets the generated NPM package SemVer string. + * + * @return The package version. + */ + public String getNpmVersion() { + return this.npmVersion; + } + + public void setNpmVersion(String npmVersion) { + this.npmVersion = npmVersion; + } + + /** + * Gets the name of the NPM registry the package is published to. + * + * @return The NPM registry name. + */ + public String getNpmRepository() { + return this.npmRepository; + } + + public void setNpmRepository(String npmRepository) { + this.npmRepository = npmRepository; + } + +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptFetchClientCodegen.java b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptFetchClientCodegen.java new file mode 100644 index 0000000000..2168b5059c --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptFetchClientCodegen.java @@ -0,0 +1,230 @@ +package io.swagger.codegen.v3.generators.typescript; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.Set; + +import io.swagger.codegen.v3.CliOption; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenParameter; +import io.swagger.codegen.v3.SupportingFile; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.BinarySchema; +import io.swagger.v3.oas.models.media.FileSchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.parser.util.SchemaTypeUtil; + +import org.apache.commons.lang3.StringUtils; + +public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodegen { + private static final SimpleDateFormat SNAPSHOT_SUFFIX_FORMAT = new SimpleDateFormat("yyyyMMddHHmm"); + + public static final String NPM_NAME = "npmName"; + public static final String NPM_VERSION = "npmVersion"; + public static final String NPM_REPOSITORY = "npmRepository"; + public static final String SNAPSHOT = "snapshot"; + public static final String WITH_INTERFACES = "withInterfaces"; + + protected String npmName = null; + protected String npmVersion = "1.0.0"; + protected String npmRepository = null; + + public TypeScriptFetchClientCodegen() { + super(); + this.outputFolder = "generated-code" + File.separator + "typescript-fetch"; + + this.cliOptions.add(new CliOption(NPM_NAME, "The name under which you want to publish generated npm package")); + this.cliOptions.add(new CliOption(NPM_VERSION, "The version of your npm package")); + this.cliOptions.add(new CliOption(NPM_REPOSITORY, + "Use this property to set an url your private npmRepo in the package.json")); + this.cliOptions.add(new CliOption(SNAPSHOT, + "When setting this property to true the version will be suffixed with -SNAPSHOT.yyyyMMddHHmm", + SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); + this.cliOptions.add(new CliOption(WITH_INTERFACES, + "Setting this property to true will generate interfaces next to the default class implementations.", + SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); + } + + @Override + protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) { + if (schema instanceof MapSchema && hasSchemaProperties(schema)) { + codegenModel.additionalPropertiesType = getTypeDeclaration((Schema) schema.getAdditionalProperties()); + addImport(codegenModel, codegenModel.additionalPropertiesType); + } else if (schema instanceof MapSchema && hasTrueAdditionalProperties(schema)) { + codegenModel.additionalPropertiesType = getTypeDeclaration(new ObjectSchema()); + } + } + + @Override + public String getName() { + return "typescript-fetch"; + } + + @Override + public String getHelp() { + return "Generates a TypeScript client library using Fetch API (beta)."; + } + + @Override + public void processOpts() { + super.processOpts(); + + supportingFiles.add(new SupportingFile("index.mustache", "", "index.ts")); + supportingFiles.add(new SupportingFile("api.mustache", "", "api.ts")); + supportingFiles.add(new SupportingFile("api_test.mustache", "", "api_test.spec.ts")); + supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.ts")); + supportingFiles.add(new SupportingFile("custom.d.mustache", "", "custom.d.ts")); + supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); + supportingFiles.add(new SupportingFile("gitignore", "", ".gitignore")); + + if (additionalProperties.containsKey(NPM_NAME)) { + addNpmPackageGeneration(); + } + } + + @Override + public String getDefaultTemplateDir() { + return "typescript-fetch"; + } + + @Override + public String getTypeDeclaration(Schema propertySchema) { + Schema inner; + if (propertySchema instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema) propertySchema; + inner = arraySchema.getItems(); + return this.getSchemaType(propertySchema) + "<" + this.getTypeDeclaration(inner) + ">"; + } else if (propertySchema instanceof MapSchema && hasSchemaProperties(propertySchema)) { + inner = (Schema) propertySchema.getAdditionalProperties(); + return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }"; + } else if (propertySchema instanceof MapSchema && hasTrueAdditionalProperties(propertySchema)) { + inner = new ObjectSchema(); + return "{ [key: string]: " + this.getTypeDeclaration(inner) + "; }"; + } else if (propertySchema instanceof FileSchema || propertySchema instanceof BinarySchema) { + return "Blob"; + } else if (propertySchema instanceof ObjectSchema) { + return "any"; + } else { + return super.getTypeDeclaration(propertySchema); + } + } + + @Override + public CodegenParameter fromParameter(Parameter parameter, Set imports) { + final CodegenParameter codegenParameter = super.fromParameter(parameter, imports); + if (parameter.getSchema() != null && isObjectSchema(parameter.getSchema())) { + //fixme: codegenParameter.getVendorExtensions().put(CodegenConstants.IS_OBJECT_EXT_NAME, Boolean.TRUE); + codegenParameter.getVendorExtensions().put("x-is-object", Boolean.TRUE); + } + return codegenParameter; + } + + @Override + public CodegenParameter fromRequestBody(RequestBody body, String name, Schema schema, Map schemas, Set imports) { + final CodegenParameter codegenParameter = super.fromRequestBody(body, name, schema, schemas, imports); + if (schema == null) { + schema = getSchemaFromBody(body); + } + if (schema != null && isObjectSchema(schema)) { + //fixme: codegenParameter.getVendorExtensions().put(CodegenConstants.IS_OBJECT_EXT_NAME, Boolean.TRUE); + codegenParameter.getVendorExtensions().put("x-is-object", Boolean.TRUE); + } + return codegenParameter; + } + + @Override + public String getSchemaType(Schema schema) { + String swaggerType = super.getSchemaType(schema); + if (isLanguagePrimitive(swaggerType) || isLanguageGenericType(swaggerType)) { + return swaggerType; + } + applyLocalTypeMapping(swaggerType); + return swaggerType; + } + + private String applyLocalTypeMapping(String type) { + if (typeMapping.containsKey(type)) { + type = typeMapping.get(type); + } + return type; + } + + private boolean isLanguagePrimitive(String type) { + return languageSpecificPrimitives.contains(type); + } + + private boolean isLanguageGenericType(String type) { + for (String genericType : languageGenericTypes) { + if (type.startsWith(genericType + "<")) { + return true; + } + } + return false; + } + + @Override + public void postProcessParameter(CodegenParameter parameter) { + super.postProcessParameter(parameter); + + String type = applyLocalTypeMapping(parameter.dataType); + parameter.dataType = type; + parameter.getVendorExtensions().put(CodegenConstants.IS_PRIMITIVE_TYPE_EXT_NAME, isLanguagePrimitive(type)); + } + + private void addNpmPackageGeneration() { + if (additionalProperties.containsKey(NPM_NAME)) { + this.setNpmName(additionalProperties.get(NPM_NAME).toString()); + } + + if (additionalProperties.containsKey(NPM_VERSION)) { + this.setNpmVersion(additionalProperties.get(NPM_VERSION).toString()); + } + + if (additionalProperties.containsKey(SNAPSHOT) + && Boolean.valueOf(additionalProperties.get(SNAPSHOT).toString())) { + this.setNpmVersion(npmVersion + "-SNAPSHOT." + SNAPSHOT_SUFFIX_FORMAT.format(new Date())); + } + additionalProperties.put(NPM_VERSION, npmVersion); + + if (additionalProperties.containsKey(NPM_REPOSITORY)) { + this.setNpmRepository(additionalProperties.get(NPM_REPOSITORY).toString()); + } + + // Files for building our lib + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + supportingFiles.add(new SupportingFile("package.mustache", "", "package.json")); + supportingFiles.add(new SupportingFile("tsconfig.mustache", "", "tsconfig.json")); + } + + public String getNpmName() { + return npmName; + } + + public void setNpmName(String npmName) { + this.npmName = npmName; + } + + public String getNpmVersion() { + return npmVersion; + } + + public void setNpmVersion(String npmVersion) { + this.npmVersion = npmVersion; + } + + public String getNpmRepository() { + return npmRepository; + } + + public void setNpmRepository(String npmRepository) { + this.npmRepository = npmRepository; + } + +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptSchemaHandler.java b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptSchemaHandler.java new file mode 100644 index 0000000000..94cba0928d --- /dev/null +++ b/src/main/java/io/swagger/codegen/v3/generators/typescript/TypeScriptSchemaHandler.java @@ -0,0 +1,35 @@ +package io.swagger.codegen.v3.generators.typescript; + +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.SchemaHandler; +import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Schema; + +import java.util.Map; + +public class TypeScriptSchemaHandler extends SchemaHandler { + + private AbstractTypeScriptClientCodegen codegenConfig; + + public TypeScriptSchemaHandler(DefaultCodegenConfig codegenConfig) { + super(codegenConfig); + this.codegenConfig = (AbstractTypeScriptClientCodegen) codegenConfig; + } + + public void processComposedSchemas(CodegenModel codegenModel, Schema schema, Map allModels) { + if (!(schema instanceof ComposedSchema)) { + return; + } + final ComposedSchema composedSchema = (ComposedSchema) schema; + final boolean isAlias = composedSchema.getOneOf() != null && !composedSchema.getOneOf().isEmpty() + || composedSchema.getAnyOf() != null && !composedSchema.getAnyOf().isEmpty(); + + if (isAlias) { + codegenModel.getVendorExtensions().put(CodegenConstants.IS_ALIAS_EXT_NAME, Boolean.TRUE); + codegenModel.dataType = this.codegenConfig.getSchemaType(schema); + this.codegenConfig.addImport(codegenModel, codegenModel.dataType); + } + } +} diff --git a/src/main/java/io/swagger/codegen/v3/generators/util/OpenAPIUtil.java b/src/main/java/io/swagger/codegen/v3/generators/util/OpenAPIUtil.java index 2b34279d21..da3c7f2dff 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/util/OpenAPIUtil.java +++ b/src/main/java/io/swagger/codegen/v3/generators/util/OpenAPIUtil.java @@ -4,7 +4,9 @@ import io.swagger.codegen.v3.CodegenProperty; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.Schema; +import org.apache.commons.lang3.StringUtils; +import java.util.List; import java.util.Map; import static io.swagger.codegen.v3.CodegenConstants.HAS_VALIDATION_EXT_NAME; @@ -20,7 +22,9 @@ public static void addPropertiesFromRef(OpenAPI openAPI, Schema refSchema, Codeg if (schema == null) { return; } - codegenProperty.pattern = schema.getPattern(); + if (StringUtils.isBlank(codegenProperty.pattern)) { + codegenProperty.pattern = schema.getPattern(); + } codegenProperty.minLength = schema.getMinLength(); codegenProperty.maxLength = schema.getMaxLength(); if (codegenProperty.pattern != null || codegenProperty.minLength != null || codegenProperty.maxLength != null) { @@ -34,4 +38,53 @@ public static String getSimpleRef(String ref) { } return ref; } + + public static Schema getSchemaFromName(String name, OpenAPI openAPI) { + if (openAPI == null) { + return null; + } + if (openAPI.getComponents() == null) { + return null; + } + final Map mapSchema = openAPI.getComponents().getSchemas(); + if (mapSchema == null || mapSchema.isEmpty()) { + return null; + } + return mapSchema.get(name); + } + + public static Schema getRefSchemaIfExists(Schema schema, OpenAPI openAPI) { + if (schema == null) { + return null; + } + if (StringUtils.isBlank(schema.get$ref()) || openAPI == null || openAPI.getComponents() == null) { + return schema; + } + final String name = getSimpleRef(schema.get$ref()); + return getSchemaFromName(name, openAPI); + } + + public static Schema getSchemaFromRefSchema(Schema refSchema, OpenAPI openAPI) { + if (StringUtils.isBlank(refSchema.get$ref())) { + return null; + } + final String name = getSimpleRef(refSchema.get$ref()); + return getSchemaFromName(name, openAPI); + } + + public static Schema getPropertyFromAllOfSchema(String propertyName, List schemas, OpenAPI openAPI) { + for (Schema schema : schemas) { + if (StringUtils.isNotBlank(schema.get$ref())) { + schema = getSchemaFromRefSchema(schema, openAPI); + } + final Map schemaProperties = schema.getProperties(); + if (schemaProperties == null) { + continue; + } + if (schemaProperties.containsKey(propertyName)) { + return schemaProperties.get(propertyName); + } + } + return null; + } } diff --git a/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig b/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig index ead2418945..2adb275cf1 100644 --- a/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig +++ b/src/main/resources/META-INF/services/io.swagger.codegen.v3.CodegenConfig @@ -1,6 +1,9 @@ +io.swagger.codegen.v3.generators.dart.DartClientCodegen io.swagger.codegen.v3.generators.dotnet.AspNetCoreServerCodegen io.swagger.codegen.v3.generators.dotnet.CSharpClientCodegen io.swagger.codegen.v3.generators.dotnet.CsharpDotNet2ClientCodegen +io.swagger.codegen.v3.generators.go.GoClientCodegen +io.swagger.codegen.v3.generators.go.GoServerCodegen io.swagger.codegen.v3.generators.html.StaticDocCodegen io.swagger.codegen.v3.generators.html.StaticHtmlCodegen io.swagger.codegen.v3.generators.html.StaticHtml2Codegen @@ -14,6 +17,8 @@ io.swagger.codegen.v3.generators.java.JavaJerseyServerCodegen io.swagger.codegen.v3.generators.java.JavaJerseyDIServerCodegen io.swagger.codegen.v3.generators.java.JavaResteasyEapServerCodegen io.swagger.codegen.v3.generators.java.JavaResteasyServerCodegen +io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen +io.swagger.codegen.v3.generators.java.MicronautCodegen io.swagger.codegen.v3.generators.java.SpringCodegen io.swagger.codegen.v3.generators.nodejs.NodeJSServerCodegen io.swagger.codegen.v3.generators.openapi.OpenAPIGenerator @@ -23,8 +28,14 @@ io.swagger.codegen.v3.generators.kotlin.KotlinServerCodegen io.swagger.codegen.v3.generators.php.PhpClientCodegen io.swagger.codegen.v3.generators.python.PythonClientCodegen io.swagger.codegen.v3.generators.python.PythonFlaskConnexionCodegen +io.swagger.codegen.v3.generators.r.RClientCodegen +io.swagger.codegen.v3.generators.ruby.RubyClientCodegen io.swagger.codegen.v3.generators.scala.ScalaClientCodegen io.swagger.codegen.v3.generators.scala.AkkaHttpServerCodegen io.swagger.codegen.v3.generators.swift.Swift3Codegen io.swagger.codegen.v3.generators.swift.Swift4Codegen +io.swagger.codegen.v3.generators.swift.Swift5Codegen io.swagger.codegen.v3.generators.typescript.TypeScriptAngularClientCodegen +io.swagger.codegen.v3.generators.typescript.TypeScriptAxiosClientCodegen +io.swagger.codegen.v3.generators.typescript.TypeScriptFetchClientCodegen +io.swagger.codegen.v3.generators.javascript.JavaScriptClientCodegen diff --git a/src/main/resources/arguments/aspnetcore.yaml b/src/main/resources/arguments/aspnetcore.yaml new file mode 100644 index 0000000000..f239a9524c --- /dev/null +++ b/src/main/resources/arguments/aspnetcore.yaml @@ -0,0 +1,10 @@ +arguments: + - option: "--aspnet-core-version" + description: "aspnetcore version to use, current options are: 2.0, 2.1, 2.2 and 3.0 (default)" + type: "string" + - option: "--interface-only" + description: "creates interfaces controller only" + type: "boolean" + - option: "--interface-controller" + description: "creates interfaces and default implementation for controllers" + type: "boolean" diff --git a/src/main/resources/arguments/inflector.yaml b/src/main/resources/arguments/inflector.yaml index e0b4321709..f3ad5daf80 100644 --- a/src/main/resources/arguments/inflector.yaml +++ b/src/main/resources/arguments/inflector.yaml @@ -13,4 +13,4 @@ arguments: type: "boolean" - option: "--use-oas2" description: "use OpenAPI v2.0 (Swagger 1.5.x) annotations (by default, OpenAPI v3.0 is used)." - type: "boolean" \ No newline at end of file + type: "boolean" diff --git a/src/main/resources/arguments/java.yaml b/src/main/resources/arguments/java.yaml index 9ef0bd1472..2531bd0b12 100644 --- a/src/main/resources/arguments/java.yaml +++ b/src/main/resources/arguments/java.yaml @@ -4,4 +4,4 @@ arguments: type: "string" - option: "--use-oas2" description: "use OpenAPI v2.0 (Swagger 1.5.x) annotations (by default, OpenAPI v3.0 is used)." - type: "boolean" \ No newline at end of file + type: "boolean" diff --git a/src/main/resources/arguments/server.yaml b/src/main/resources/arguments/server.yaml new file mode 100644 index 0000000000..b4ebb72748 --- /dev/null +++ b/src/main/resources/arguments/server.yaml @@ -0,0 +1,4 @@ +arguments: + - option: "--use-oas2" + description: "use OpenAPI v2.0 (Swagger 1.5.x) annotations (by default, OpenAPI v3.0 is used)." + type: "boolean" diff --git a/src/main/resources/arguments/spring.yaml b/src/main/resources/arguments/spring.yaml new file mode 100644 index 0000000000..b4ebb72748 --- /dev/null +++ b/src/main/resources/arguments/spring.yaml @@ -0,0 +1,4 @@ +arguments: + - option: "--use-oas2" + description: "use OpenAPI v2.0 (Swagger 1.5.x) annotations (by default, OpenAPI v3.0 is used)." + type: "boolean" diff --git a/src/main/resources/handlebars/.DS_Store b/src/main/resources/handlebars/.DS_Store new file mode 100644 index 0000000000..f4fa4efcdc Binary files /dev/null and b/src/main/resources/handlebars/.DS_Store differ diff --git a/src/main/resources/handlebars/Java/ApiClient.mustache b/src/main/resources/handlebars/Java/ApiClient.mustache index a30bdb1dfa..8002803fb2 100644 --- a/src/main/resources/handlebars/Java/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/ApiClient.mustache @@ -29,8 +29,14 @@ import com.sun.jersey.api.client.WebResource.Builder; import com.sun.jersey.multipart.FormDataMultiPart; import com.sun.jersey.multipart.file.FileDataBodyPart; +{{#jakarta}} +import jakarta.ws.rs.core.Response.Status.Family; +import jakarta.ws.rs.core.MediaType; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response.Status.Family; import javax.ws.rs.core.MediaType; +{{/jakarta}} import java.util.Collection; import java.util.Collections; diff --git a/src/main/resources/handlebars/Java/BeanValidationException.mustache b/src/main/resources/handlebars/Java/BeanValidationException.mustache index ab8ef30b69..9bb486a758 100644 --- a/src/main/resources/handlebars/Java/BeanValidationException.mustache +++ b/src/main/resources/handlebars/Java/BeanValidationException.mustache @@ -1,9 +1,14 @@ package {{invokerPackage}}; import java.util.Set; - +{{#jakarta}} +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ValidationException; +{{/jakarta}} +{{^jakarta}} import javax.validation.ConstraintViolation; import javax.validation.ValidationException; +{{/jakarta}} public class BeanValidationException extends ValidationException { /** diff --git a/src/main/resources/handlebars/Java/README.mustache b/src/main/resources/handlebars/Java/README.mustache index cc5c3afefd..8c49cd3ac2 100644 --- a/src/main/resources/handlebars/Java/README.mustache +++ b/src/main/resources/handlebars/Java/README.mustache @@ -151,8 +151,8 @@ Class | Method | HTTP request | Description - **Flow**: {{flow}} - **Authorization URL**: {{authorizationUrl}} - **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} +{{#each scopes}} - {{@key}}: {{this}} +{{/each}} {{/isOAuth}} {{/authMethods}} diff --git a/src/main/resources/handlebars/Java/api.mustache b/src/main/resources/handlebars/Java/api.mustache index d208b6856f..c89b71d372 100644 --- a/src/main/resources/handlebars/Java/api.mustache +++ b/src/main/resources/handlebars/Java/api.mustache @@ -63,7 +63,7 @@ public class {{classname}} { @Deprecated {{/isDeprecated}} public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}}) throws ApiException { - Object {{localVariablePrefix}}localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + Object {{localVariablePrefix}}localVarPostBody = {{^isForm}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/isForm}}{{#isForm}}null{{/isForm}}; {{#parameters}}{{#required}} // verify the required parameter '{{paramName}}' is set if ({{paramName}} == null) { @@ -87,10 +87,11 @@ public class {{classname}} { {{#headerParams}}if ({{paramName}} != null) {{localVariablePrefix}}localVarHeaderParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); {{/headerParams}} - + {{#isForm}} {{#formParams}}if ({{paramName}} != null) {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}}); {{/formParams}} + {{/isForm}} final String[] {{localVariablePrefix}}localVarAccepts = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} diff --git a/src/main/resources/handlebars/Java/api_doc.mustache b/src/main/resources/handlebars/Java/api_doc.mustache index c60dc02efe..bb10129cbe 100644 --- a/src/main/resources/handlebars/Java/api_doc.mustache +++ b/src/main/resources/handlebars/Java/api_doc.mustache @@ -63,7 +63,7 @@ try { {{^parameters}}This endpoint does not need any parameter.{{/parameters}}{{#parameters}}{{#@last}} Name | Type | Description | Notes ------------- | ------------- | ------------- | -------------{{/@last}}{{/parameters}} -{{#parameters}} **{{paramName}}** | {{#is this 'primitive-type'}}**{{dataType}}**{{/is}}{{#isNot this 'primitive-type'}}{{#is this 'file'}}**{{dataType}}**{{/is}}{{#isNot this 'file'}}[**{{dataType}}**]({{baseType}}.md){{/isNot}}{{/isNot}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^@last}}, {{/@last}}{{/values}}]{{/allowableValues}} +{{#parameters}} **{{paramName}}** | {{#is this 'primitive-type'}}**{{dataType}}**{{/is}}{{#isNot this 'primitive-type'}}{{#isBinary}}**{{dataType}}**{{/isBinary}}{{^isBinary}}[**{{dataType}}**]({{baseType}}.md){{/isBinary}}{{/isNot}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^@last}}, {{/@last}}{{/values}}]{{/allowableValues}} {{/parameters}} ### Return type diff --git a/src/main/resources/handlebars/Java/api_test.mustache b/src/main/resources/handlebars/Java/api_test.mustache index c9a25efeef..8c13fe4577 100644 --- a/src/main/resources/handlebars/Java/api_test.mustache +++ b/src/main/resources/handlebars/Java/api_test.mustache @@ -2,12 +2,19 @@ package {{package}}; -import {{invokerPackage}}.ApiException; {{#imports}}import {{import}}; {{/imports}} import org.junit.Test; import org.junit.Ignore; +{{#wiremock}} +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.net.HttpURLConnection; +import org.junit.AfterClass; +import org.junit.BeforeClass; +{{/wiremock}} + {{^fullJavaUtil}} import java.util.ArrayList; import java.util.HashMap; @@ -15,6 +22,10 @@ import java.util.List; import java.util.Map; {{/fullJavaUtil}} +{{#wiremock}} +import static com.github.tomakehurst.wiremock.client.WireMock.*; +{{/wiremock}} + /** * API tests for {{classname}} */ @@ -22,6 +33,32 @@ import java.util.Map; public class {{classname}}Test { private final {{classname}} api = new {{classname}}(); + {{#wiremock}} + private static WireMockServer wireMockServer; + + public {{classname}}Test() { + api.getApiClient().setBasePath("http://localhost:" + wireMockServer.port()); + } + + @BeforeClass + public static void setUp() { + wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort()); + wireMockServer.start(); + configureFor(wireMockServer.port()); + {{#operations}} + {{#operation}} + stubFor({{toLowerCase httpMethod}}(urlPathMatching("{{{path}}}")) + .willReturn(aResponse() + .withStatus(HttpURLConnection.HTTP_OK))); + {{/operation}} + {{/operations}} + } + + @AfterClass + public static void tearDown() { + wireMockServer.stop(); + } + {{/wiremock}} {{#operations}} {{#operation}} @@ -32,11 +69,11 @@ public class {{classname}}Test { * * {{notes}} * - * @throws ApiException + * @throws Exception * if the Api call fails */ @Test - public void {{operationId}}Test() throws ApiException { + public void {{operationId}}Test() throws Exception { {{#parameters}} {{{dataType}}} {{paramName}} = null; {{/parameters}} diff --git a/src/main/resources/handlebars/Java/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/build.gradle.java11.mustache new file mode 100644 index 0000000000..3b86cfec6f --- /dev/null +++ b/src/main/resources/handlebars/Java/build.gradle.java11.mustache @@ -0,0 +1,76 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + swagger_annotations_version = "{{#useOas2}}1.5.24{{/useOas2}}{{^useOas2}}2.0.0{{/useOas2}}" + jackson_version = "{{^threetenbp}}2.11.4{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" + jersey_version = "{{#jakarta}}3.1.0{{/jakarta}}{{^jakarta}}1.19.4{{/jakarta}}" + jodatime_version = "2.10.5" + junit_version = "4.13.1" +} + +dependencies { + {{#useOas2}} + implementation "io.swagger:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + implementation "com.sun.jersey:jersey-client:$jersey_version" + implementation "com.sun.jersey.contribs:jersey-multipart:$jersey_version" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jackson_version" + {{#joda}} + implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" + {{/joda}} + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version"} + {{#threetenbp}} + implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version" + {{/threetenbp}} + implementation 'com.sun.xml.ws:jaxws-rt:{{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}}' + testImplementation "junit:junit:$junit_version" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/build.gradle.mustache b/src/main/resources/handlebars/Java/build.gradle.mustache index 6b9599c31c..21e0692da5 100644 --- a/src/main/resources/handlebars/Java/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } @@ -112,8 +117,8 @@ ext { {{^useOas2}} swagger_annotations_version = "2.0.0" {{/useOas2}} - jackson_version = "{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" - jersey_version = "1.19.4" + jackson_version = "2.10.1" + jersey_version = "{{#jakarta}}3.1.0{{/jakarta}}{{^jakarta}}1.19.4{{/jakarta}}" jodatime_version = "2.9.9" junit_version = "4.12" } @@ -132,13 +137,13 @@ dependencies { compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jackson_version" {{#joda}} - compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version", + compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" {{/joda}} {{#java8}} - compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version", + compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" {{/java8}} {{#threetenbp}} - compile "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version", + compile "com.github.joschi.jackson:jackson-datatype-threetenbp:2.6.4" {{/threetenbp}} {{^java8}} compile "com.brsanthu:migbase64:2.2" diff --git a/src/main/resources/handlebars/Java/generatedAnnotation.mustache b/src/main/resources/handlebars/Java/generatedAnnotation.mustache index a47b6faa85..c6c0883bcb 100644 --- a/src/main/resources/handlebars/Java/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/Java/generatedAnnotation.mustache @@ -1 +1 @@ -{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/Java/gradle-wrapper.jar b/src/main/resources/handlebars/Java/gradle-wrapper.jar new file mode 100644 index 0000000000..2c6137b878 Binary files /dev/null and b/src/main/resources/handlebars/Java/gradle-wrapper.jar differ diff --git a/src/main/resources/handlebars/Java/interface.mustache b/src/main/resources/handlebars/Java/interface.mustache index becc0c5549..0d08bbe545 100644 --- a/src/main/resources/handlebars/Java/interface.mustache +++ b/src/main/resources/handlebars/Java/interface.mustache @@ -1,6 +1,26 @@ +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +{{/jackson}} /** * {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} */ +{{#jackson}} +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type") +@JsonSubTypes({ + {{#subTypes}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{classname}}"){{^@last}},{{/@last}} + {{/subTypes}} +}) +{{/jackson}} public interface {{{classname}}} { +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} } diff --git a/src/main/resources/handlebars/Java/libraries/feign/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/feign/ApiClient.mustache index 973aa9b76b..48d038345a 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/ApiClient.mustache @@ -53,7 +53,7 @@ public class ApiClient { this(); for(String authName : authNames) { {{#hasAuthMethods}} - RequestInterceptor auth; + RequestInterceptor auth = null; {{#authMethods}}if ("{{name}}".equals(authName)) { {{#is this 'basic'}} auth = new HttpBasicAuth(); @@ -62,7 +62,7 @@ public class ApiClient { auth = new ApiKeyAuth({{#is this 'key-in-header'}}"header"{{/is}}{{#isNot this 'key-in-header'}}"query"{{/isNot}}, "{{keyParamName}}"); {{/is}} {{#is this 'oauth'}} - auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{scope}}{{#hasMore}}, {{/hasMore}}{{/scopes}}"); + auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#each scopes}}{{@key}}{{^@last}}, {{/@last}}{{/each}}"); {{/is}} } else {{/authMethods}}{ throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); diff --git a/src/main/resources/handlebars/Java/libraries/feign/api.mustache b/src/main/resources/handlebars/Java/libraries/feign/api.mustache index ccefd3fcb3..4b7bd85243 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/api.mustache @@ -40,10 +40,10 @@ public interface {{classname}} extends ApiClient.Api { @RequestLine("{{httpMethod}} {{{path}}}{{#hasQueryParams}}?{{/hasQueryParams}}{{#queryParams}}{{baseName}}={{braces "left"}}{{paramName}}{{braces "right"}}{{#has this 'more'}}&{{/has}}{{/queryParams}}") @Headers({ {{#vendorExtensions.x-contentType}} - "Content-Type: {{vendorExtensions.x-contentType}}", + "Content-Type: {{{vendorExtensions.x-contentType}}}", {{/vendorExtensions.x-contentType}} {{#vendorExtensions.x-accepts}} - "Accept: {{vendorExtensions.x-accepts}}", + "Accept: {{{vendorExtensions.x-accepts}}}", {{/vendorExtensions.x-accepts}} {{^vendorExtensions.x-accepts}} "Accept: */*", @@ -85,13 +85,13 @@ public interface {{classname}} extends ApiClient.Api { @RequestLine("{{httpMethod}} {{{path}}}?{{#queryParams}}{{baseName}}={{braces "left"}}{{paramName}}{{braces "right"}}{{#has this 'more'}}&{{/has}}{{/queryParams}}") @Headers({ {{#vendorExtensions.x-contentType}} - "Content-Type: {{vendorExtensions.x-contentType}}", + "Content-Type: {{{vendorExtensions.x-contentType}}}", {{/vendorExtensions.x-contentType}} {{^vendorExtensions.x-contentType}} "Content-Type: */*", {{/vendorExtensions.x-contentType}} {{#vendorExtensions.x-accepts}} - "Accept: {{vendorExtensions.x-accepts}}", + "Accept: {{{vendorExtensions.x-accepts}}}", {{/vendorExtensions.x-accepts}} {{#headerParams}} "{{baseName}}: {{braces "left"}}{{paramName}}{{braces "right"}}"{{#has this 'more'}},{{/has}} diff --git a/src/main/resources/handlebars/Java/libraries/feign/api_test.mustache b/src/main/resources/handlebars/Java/libraries/feign/api_test.mustache index aed61d9d25..6317437e47 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/api_test.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/api_test.mustache @@ -6,6 +6,13 @@ import {{invokerPackage}}.ApiClient; import org.junit.Before; import org.junit.Test; +{{#wiremock}} +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.net.HttpURLConnection; +import org.junit.AfterClass; +{{/wiremock}} + {{^fullJavaUtil}} import java.util.ArrayList; import java.util.HashMap; @@ -13,6 +20,10 @@ import java.util.List; import java.util.Map; {{/fullJavaUtil}} +{{#wiremock}} +import static com.github.tomakehurst.wiremock.client.WireMock.*; +{{/wiremock}} + /** * API tests for {{classname}} */ @@ -20,10 +31,33 @@ public class {{classname}}Test { private {{classname}} api; + {{#wiremock}} + private static WireMockServer wireMockServer; + + @Before + public void setup() { + wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort()); + wireMockServer.start(); + configureFor(wireMockServer.port()); + api = new ApiClient().setBasePath("http://localhost:" + wireMockServer.port()).buildClient({{classname}}.class); + {{#operations}}{{#operation}} + stubFor({{toLowerCase httpMethod}}(urlPathMatching("{{{path}}}")) + .willReturn(aResponse() + .withStatus(HttpURLConnection.HTTP_OK))); + {{/operation}}{{/operations}} + } + + @AfterClass + public static void tearDown() { + wireMockServer.stop(); + } + {{/wiremock}} + {{^wiremock}} @Before public void setup() { api = new ApiClient().buildClient({{classname}}.class); } + {{/wiremock}} {{#operations}}{{#operation}}{{#contents}}{{#@first}} /** @@ -57,7 +91,7 @@ public class {{classname}}Test { {{{dataType}}} {{paramName}} = null; {{/isNot}} {{/parameters}} - {{classname}}.{{operationIdCamelCase}}QueryParams queryParams = new {{classname}}.{{operationIdCamelCase}}QueryParams() + {{classname}}.{{operationIdCamelCase}}QueryParams queryParams = new {{classname}}.{{operationIdCamelCase}}QueryParams(){{^queryParams}};{{/queryParams}} {{#queryParams}} .{{paramName}}(null){{#hasNot this 'more'}};{{/hasNot}} {{/queryParams}} diff --git a/src/main/resources/handlebars/Java/libraries/feign/auth/OAuth.mustache b/src/main/resources/handlebars/Java/libraries/feign/auth/OAuth.mustache index 5b64a9146d..ede95edce7 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/auth/OAuth.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/auth/OAuth.mustache @@ -1,8 +1,13 @@ package {{invokerPackage}}.auth; import java.io.IOException; + import java.util.ArrayList; import java.util.Collection; +{{^java8}} +import java.util.HashMap; +import java.util.List; +{{/java8}} import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; @@ -82,19 +87,19 @@ public class OAuth implements RequestInterceptor { } // If first time, get the token if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) { - updateAccessToken(); + updateAccessToken(template); } if (getAccessToken() != null) { template.header("Authorization", "Bearer " + getAccessToken()); } } - public synchronized void updateAccessToken() { + public synchronized void updateAccessToken(RequestTemplate template) { OAuthJSONAccessTokenResponse accessTokenResponse; try { accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage()); } catch (Exception e) { - throw new RetryableException(e.getMessage(), e,null); + throw new RetryableException(400, e.getMessage(), template.request().httpMethod(), e, null, template.request()); } if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) { setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn()); @@ -183,7 +188,7 @@ public class OAuth implements RequestInterceptor { if(contentTypeHeader != null) { contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";"); } - + {{#java8}} return OAuthClientResponseFactory.createCustomResponse( body, contentType, @@ -194,6 +199,22 @@ public class OAuth implements RequestInterceptor { )), responseClass ); + {{/java8}} + {{^java8}} + Map> responseHeaders = new HashMap<>(); + for (String key : headers.keySet()) { + List values = new ArrayList(); + values.addAll(headers.values()); + responseHeaders.put(key, values); + } + return OAuthClientResponseFactory.createCustomResponse( + body, + contentType, + feignResponse.status(), + responseHeaders, + responseClass + ); + {{/java8}} } public void shutdown() { diff --git a/src/main/resources/handlebars/Java/libraries/feign/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/feign/build.gradle.java11.mustache new file mode 100644 index 0000000000..4807c37713 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/feign/build.gradle.java11.mustache @@ -0,0 +1,90 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + swagger_annotations_version = "{{#useOas2}}1.5.24{{/useOas2}}{{^useOas2}}2.0.0{{/useOas2}}" + jackson_version = "2.11.4" + {{#threetenbp}} + threepane_version = "2.6.4" + {{/threetenbp}} + feign_version = "11.6" + feign_form_version = "3.8.0" + junit_version = "4.13.1" + oltu_version = "1.0.2" +} + +dependencies { + {{#useOas2}} + implementation "io.swagger:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + implementation "io.github.openfeign:feign-core:$feign_version" + implementation "io.github.openfeign:feign-jackson:$feign_version" + implementation "io.github.openfeign:feign-slf4j:$feign_version" + implementation "io.github.openfeign.form:feign-form:$feign_form_version" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + {{#joda}} + implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" + {{/joda}} + {{#java8}} + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" + {{/java8}} + {{#threetenbp}} + implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$threepane_version" + {{/threetenbp}} + implementation("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version") { + exclude group: 'org.json', module: 'json' + } + implementation "org.json:json:20180130" + implementation "com.brsanthu:migbase64:2.2" + implementation "com.sun.xml.ws:jaxws-rt:{{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}}" + testImplementation "junit:junit:$junit_version" + testImplementation "com.squareup.okhttp3:mockwebserver:3.6.0" + testImplementation "org.assertj:assertj-core:1.7.1" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/feign/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/feign/build.gradle.mustache index d6830f17a6..217f4e2ff0 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } @@ -106,12 +111,12 @@ ext { {{^useOas2}} swagger_annotations_version = "2.0.0" {{/useOas2}} - jackson_version = "2.8.7" + jackson_version = "2.10.1" {{#threetenbp}} threepane_version = "2.6.4" {{/threetenbp}} - feign_version = "9.4.0" - feign_form_version = "2.1.0" + feign_version = "11.6" + feign_form_version = "3.8.0" junit_version = "4.12" oltu_version = "1.0.2" } @@ -123,9 +128,9 @@ dependencies { {{^useOas2}} compile "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" {{/useOas2}} - compile "com.netflix.feign:feign-core:$feign_version" - compile "com.netflix.feign:feign-jackson:$feign_version" - compile "com.netflix.feign:feign-slf4j:$feign_version" + compile "io.github.openfeign:feign-core:$feign_version" + compile "io.github.openfeign:feign-jackson:$feign_version" + compile "io.github.openfeign:feign-slf4j:$feign_version" compile "io.github.openfeign.form:feign-form:$feign_form_version" compile "com.fasterxml.jackson.core:jackson-core:$jackson_version" compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" @@ -139,7 +144,10 @@ dependencies { {{#threetenbp}} compile "com.github.joschi.jackson:jackson-datatype-threetenbp:$threepane_version" {{/threetenbp}} - compile "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" + compile ("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version") { + exclude group: "org.json", module: "json" + } + compile "org.json:json:20180130" compile "com.brsanthu:migbase64:2.2" testCompile "junit:junit:$junit_version" } diff --git a/src/main/resources/handlebars/Java/libraries/feign/build.sbt.mustache b/src/main/resources/handlebars/Java/libraries/feign/build.sbt.mustache index 09456375c1..7230311c3d 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/build.sbt.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/build.sbt.mustache @@ -19,10 +19,10 @@ lazy val root = (project in file(".")). "com.netflix.feign" % "feign-jackson" % "9.4.0" % "compile", "com.netflix.feign" % "feign-slf4j" % "9.4.0" % "compile", "io.github.openfeign.form" % "feign-form" % "2.1.0" % "compile", - "com.fasterxml.jackson.core" % "jackson-core" % "2.8.7" % "compile", - "com.fasterxml.jackson.core" % "jackson-annotations" % "2.8.7" % "compile", - "com.fasterxml.jackson.core" % "jackson-databind" % "2.8.7" % "compile", - "com.fasterxml.jackson.datatype" % "jackson-datatype-{{^java8}}joda{{/java8}}{{#java8}}jsr310{{/java8}}" % "2.8.7" % "compile", + "com.fasterxml.jackson.core" % "jackson-core" % "2.10.1" % "compile", + "com.fasterxml.jackson.core" % "jackson-annotations" % "2.10.1" % "compile", + "com.fasterxml.jackson.core" % "jackson-databind" % "2.10.1" % "compile", + "com.fasterxml.jackson.datatype" % "jackson-datatype-{{^java8}}joda{{/java8}}{{#java8}}jsr310{{/java8}}" % "2.10.1" % "compile", "org.apache.oltu.oauth2" % "org.apache.oltu.oauth2.client" % "1.0.2" % "compile", "com.brsanthu" % "migbase64" % "2.2" % "compile", "junit" % "junit" % "4.12" % "test", diff --git a/src/main/resources/handlebars/Java/libraries/feign/pom.mustache b/src/main/resources/handlebars/Java/libraries/feign/pom.mustache index 20b7da5ab9..fb7f3e4c0d 100644 --- a/src/main/resources/handlebars/Java/libraries/feign/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/feign/pom.mustache @@ -117,7 +117,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -165,6 +165,22 @@ + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + {{/java11}} @@ -277,9 +293,17 @@ 1.7.1 test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} {{#useOas2}} @@ -288,13 +312,13 @@ {{^useOas2}} 2.0.0 {{/useOas2}} - 9.4.0 - 2.1.0 - 2.8.9 + 11.6 + 3.8.0 + 2.10.1 {{#threetenbp}} 2.6.4 {{/threetenbp}} - 4.12 + 4.13.1 1.0.0 1.0.2 diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/ApiClient.mustache index 8f43c9b7bd..46a113c45d 100644 --- a/src/main/resources/handlebars/Java/libraries/jersey2/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/jersey2/ApiClient.mustache @@ -1,5 +1,18 @@ package {{invokerPackage}}; +{{#jakarta}} +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.Invocation; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Form; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; @@ -10,6 +23,7 @@ import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +{{/jakarta}} import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientProperties; @@ -28,6 +42,7 @@ import java.io.InputStream; {{^supportJava6}} import java.nio.file.Files; +import java.nio.file.Paths; import java.nio.file.StandardCopyOption; {{/supportJava6}} {{#supportJava6}} @@ -651,9 +666,9 @@ public class ApiClient { } if (tempFolderPath == null) - return File.createTempFile(prefix, suffix); + return Files.createTempFile(prefix, suffix).toFile(); else - return File.createTempFile(prefix, suffix, new File(tempFolderPath)); + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); } /** @@ -689,7 +704,7 @@ public class ApiClient { } Invocation.Builder invocationBuilder = target.request(); - + if (accept != null) { invocationBuilder = invocationBuilder.accept(accept); } diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/JSON.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/JSON.mustache index 911391a6ba..e094645607 100644 --- a/src/main/resources/handlebars/Java/libraries/jersey2/JSON.mustache +++ b/src/main/resources/handlebars/Java/libraries/jersey2/JSON.mustache @@ -17,7 +17,12 @@ import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; import java.text.DateFormat; +{{#jakarta}} +import jakarta.ws.rs.ext.ContextResolver; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ContextResolver; +{{/jakarta}} {{>generatedAnnotation}} public class JSON implements ContextResolver { diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/api.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/api.mustache index 3f21d85245..6e0dda863e 100644 --- a/src/main/resources/handlebars/Java/libraries/jersey2/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/jersey2/api.mustache @@ -5,7 +5,12 @@ import {{invokerPackage}}.ApiClient; import {{invokerPackage}}.Configuration; import {{invokerPackage}}.Pair; +{{#jakarta}} +import jakarta.ws.rs.core.GenericType; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.GenericType; +{{/jakarta}} {{#imports}}import {{import}}; {{/imports}} @@ -62,7 +67,7 @@ public class {{classname}} { @Deprecated {{/isDeprecated}} public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}}) throws ApiException { - Object {{localVariablePrefix}}localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + Object {{localVariablePrefix}}localVarPostBody = {{^isForm}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/isForm}}{{#isForm}}null{{/isForm}}; {{#parameters}} {{#required}} // verify the required parameter '{{paramName}}' is set @@ -88,11 +93,12 @@ public class {{classname}} { if ({{paramName}} != null) {{localVariablePrefix}}localVarHeaderParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); {{/headerParams}} - + {{#isForm}} {{#formParams}} if ({{paramName}} != null) {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}}); {{/formParams}} + {{/isForm}} final String[] {{localVariablePrefix}}localVarAccepts = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.java11.mustache new file mode 100644 index 0000000000..a4ccb154df --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.java11.mustache @@ -0,0 +1,78 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + swagger_annotations_version = "{{#useOas2}}1.5.24{{/useOas2}}{{^useOas2}}2.0.0{{/useOas2}}" + jackson_version = "2.6.4" + jersey_version = "{{#jakarta}}3.1.0{{/jakarta}}{{^jakarta}}2.29.1{{/jakarta}}" + junit_version = "4.13.1" +} + +dependencies { + {{#useOas2}} + implementation "io.swagger:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + implementation "org.glassfish.jersey.core:jersey-client:$jersey_version" + implementation "org.glassfish.jersey.media:jersey-media-multipart:$jersey_version" + implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + {{#withXml}} + implementation "org.glassfish.jersey.media:jersey-media-jaxb:$jersey_version" + {{/withXml}} + {{#joda}} + implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" + {{/joda}} + implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" + {{#threetenbp}} + implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version" + {{/threetenbp}} + implementation "com.brsanthu:migbase64:2.2" + testImplementation "junit:junit:$junit_version" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.mustache index 975022af9a..74875be6a7 100644 --- a/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/jersey2/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } @@ -111,8 +116,8 @@ ext { {{^useOas2}} swagger_annotations_version = "2.0.0" {{/useOas2}} - jackson_version = "2.8.9" - jersey_version = "2.25.1" + jackson_version = "2.10.1" + jersey_version = "{{#jakarta}}3.1.0{{/jakarta}}{{^jakarta}}2.26{{/jakarta}}" {{#supportJava6}} commons_io_version=2.5 commons_lang3_version=3.6 @@ -134,17 +139,17 @@ dependencies { compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" {{#joda}} - compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version", + compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" {{/joda}} {{#java8}} - compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version", + compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" {{/java8}} {{#supportJava6}} compile "commons-io:commons-io:$commons_io_version" compile "org.apache.commons:commons-lang3:$commons_lang3_version" {{/supportJava6}} {{#threetenbp}} - compile "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version", + compile "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version" {{/threetenbp}} {{^java8}} compile "com.brsanthu:migbase64:2.2" diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/build.sbt.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/build.sbt.mustache index 78be95d554..5c9a87d31a 100644 --- a/src/main/resources/handlebars/Java/libraries/jersey2/build.sbt.mustache +++ b/src/main/resources/handlebars/Java/libraries/jersey2/build.sbt.mustache @@ -15,17 +15,18 @@ lazy val root = (project in file(".")). {{^useOas2}} "io.swagger.core.v3" % "swagger-annotations" % "2.0.0", {{/useOas2}} - "org.glassfish.jersey.core" % "jersey-client" % "2.25.1", - "org.glassfish.jersey.media" % "jersey-media-multipart" % "2.25.1", - "org.glassfish.jersey.media" % "jersey-media-json-jackson" % "2.25.1", - "com.fasterxml.jackson.core" % "jackson-core" % "{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", - "com.fasterxml.jackson.core" % "jackson-annotations" % "{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", - "com.fasterxml.jackson.core" % "jackson-databind" % "{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", + "org.glassfish.jersey.core" % "jersey-client" % "2.29.1", + "org.glassfish.jersey.media" % "jersey-media-multipart" % "2.29.1", + "org.glassfish.jersey.media" % "jersey-media-json-jackson" % "2.29.1", + "org.glassfish.jersey.inject" % "jersey-hk2" % "2.29.1", + "com.fasterxml.jackson.core" % "jackson-core" % "{{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", + "com.fasterxml.jackson.core" % "jackson-annotations" % "{{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", + "com.fasterxml.jackson.core" % "jackson-databind" % "{{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", {{#joda}} - "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.8.9" % "compile", + "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.10.1" % "compile", {{/joda}} {{#java8}} - "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.8.9" % "compile", + "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.10.1" % "compile", {{/java8}} {{#threetenbp}} "com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.6.4" % "compile", diff --git a/src/main/resources/handlebars/Java/libraries/jersey2/pom.mustache b/src/main/resources/handlebars/Java/libraries/jersey2/pom.mustache index bf7e42e728..718c42962d 100644 --- a/src/main/resources/handlebars/Java/libraries/jersey2/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/jersey2/pom.mustache @@ -132,7 +132,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -214,6 +214,11 @@ jersey-media-json-jackson ${jersey-version} + + org.glassfish.jersey.inject + jersey-hk2 + 2.29.1 + @@ -284,12 +289,22 @@ {{/supportJava6}} {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} @@ -298,6 +313,14 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} {{#useOas2}} @@ -307,15 +330,15 @@ 2.0.0 {{/useOas2}} {{^supportJava6}} - 2.25.1 + 2.29.1 {{/supportJava6}} {{#supportJava6}} 2.6 2.5 3.6 {{/supportJava6}} - {{^threetenbp}}2.7.5{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}} + {{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}} 1.0.0 - 4.12 + 4.13.1 diff --git a/src/main/resources/handlebars/Java/libraries/jersey3/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/jersey3/ApiClient.mustache new file mode 100644 index 0000000000..8ff2f3ad82 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey3/ApiClient.mustache @@ -0,0 +1,806 @@ +package {{invokerPackage}}; + +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.Invocation; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Form; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.client.HttpUrlConnectorProvider; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.media.multipart.FormDataBodyPart; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.glassfish.jersey.media.multipart.MultiPart; +import org.glassfish.jersey.media.multipart.MultiPartFeature; + +import java.io.IOException; +import java.io.InputStream; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Map.Entry; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Date; +import java.util.TimeZone; + +import java.net.URLEncoder; + +import java.io.File; +import java.io.UnsupportedEncodingException; + +import java.text.DateFormat; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import {{invokerPackage}}.auth.Authentication; +import {{invokerPackage}}.auth.HttpBasicAuth; +import {{invokerPackage}}.auth.ApiKeyAuth; +import {{invokerPackage}}.auth.OAuth; + +{{>generatedAnnotation}} +public class ApiClient { + protected Map defaultHeaderMap = new HashMap<>(); + protected String basePath = "{{{basePath}}}"; + protected boolean debugging = false; + protected int connectionTimeout = 0; + private int readTimeout = 0; + + protected Client httpClient; + protected JSON json; + protected String tempFolderPath = null; + + protected Map authentications; + + protected int statusCode; + protected Map> responseHeaders; + + protected DateFormat dateFormat; + + public ApiClient() { + json = new JSON(); + httpClient = buildHttpClient(debugging); + + this.dateFormat = new RFC3339DateFormat(); + + // Set default User-Agent. + setUserAgent("{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{artifactVersion}}}/java{{/httpUserAgent}}"); + + // Setup authentications (key: authentication name, value: authentication). + authentications = new HashMap<>();{{#authMethods}}{{#is this 'basic'}} + authentications.put("{{name}}", new HttpBasicAuth());{{/is}}{{#is this 'api-key'}} + authentications.put("{{name}}", new ApiKeyAuth({{#is this 'key-in-header'}}"header"{{/is}}{{#isNot this 'key-in-header'}}"query"{{/isNot}}, "{{keyParamName}}"));{{/is}}{{#is this 'oauth'}} + authentications.put("{{name}}", new OAuth());{{/is}}{{#is this 'bearer'}} + authentications.put("{{name}}", new OAuth());{{/is}}{{/authMethods}} + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + /** + * Gets the JSON instance to do JSON serialization and deserialization. + * @return JSON + */ + public JSON getJSON() { + return json; + } + + public Client getHttpClient() { + return httpClient; + } + + public ApiClient setHttpClient(Client httpClient) { + this.httpClient = httpClient; + return this; + } + + public String getBasePath() { + return basePath; + } + + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + /** + * Gets the status code of the previous request + * @return Status code + */ + public int getStatusCode() { + return statusCode; + } + + /** + * Gets the response headers of the previous request + * @return Response headers + */ + public Map> getResponseHeaders() { + return responseHeaders; + } + + /** + * Get authentications (key: authentication name, value: authentication). + * @return Map of authentication object + */ + public Map getAuthentications() { + return authentications; + } + + /** + * Get authentication for the given name. + * + * @param authName The authentication name + * @return The authentication, null if not found + */ + public Authentication getAuthentication(String authName) { + return authentications.get(authName); + } + + /** + * Helper method to set username for the first HTTP basic authentication. + * @param username Username + */ + public void setUsername(String username) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setUsername(username); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set password for the first HTTP basic authentication. + * @param password Password + */ + public void setPassword(String password) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setPassword(password); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set API key value for the first API key authentication. + * @param apiKey API key + */ + public void setApiKey(String apiKey) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKey(apiKey); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set API key prefix for the first API key authentication. + * @param apiKeyPrefix API key prefix + */ + public void setApiKeyPrefix(String apiKeyPrefix) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set access token for the first OAuth2 authentication. + * @param accessToken Access token + */ + public void setAccessToken(String accessToken) { + for (Authentication auth : authentications.values()) { + if (auth instanceof OAuth) { + ((OAuth) auth).setAccessToken(accessToken); + return; + } + } + throw new RuntimeException("No OAuth2 authentication configured!"); + } + + /** + * Set the User-Agent header's value (by adding to the default header map). + * @param userAgent Http user agent + * @return API client + */ + public ApiClient setUserAgent(String userAgent) { + addDefaultHeader("User-Agent", userAgent); + return this; + } + + /** + * Add a default header. + * + * @param key The header's key + * @param value The header's value + * @return API client + */ + public ApiClient addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + return this; + } + + /** + * Check that whether debugging is enabled for this API client. + * @return True if debugging is switched on + */ + public boolean isDebugging() { + return debugging; + } + + /** + * Enable/disable debugging for this API client. + * + * @param debugging To enable (true) or disable (false) debugging + * @return API client + */ + public ApiClient setDebugging(boolean debugging) { + this.debugging = debugging; + // Rebuild HTTP Client according to the new "debugging" value. + this.httpClient = buildHttpClient(debugging); + return this; + } + + /** + * The path of temporary folder used to store downloaded files from endpoints + * with file response. The default value is null, i.e. using + * the system's default tempopary folder. + * + * @return Temp folder path + */ + public String getTempFolderPath() { + return tempFolderPath; + } + + /** + * Set temp folder path + * @param tempFolderPath Temp folder path + * @return API client + */ + public ApiClient setTempFolderPath(String tempFolderPath) { + this.tempFolderPath = tempFolderPath; + return this; + } + + /** + * Connect timeout (in milliseconds). + * @return Connection timeout + */ + public int getConnectTimeout() { + return connectionTimeout; + } + + /** + * Set the connect timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link Integer#MAX_VALUE}. + * @param connectionTimeout Connection timeout in milliseconds + * @return API client + */ + public ApiClient setConnectTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + httpClient.property(ClientProperties.CONNECT_TIMEOUT, connectionTimeout); + return this; + } + + /** + * read timeout (in milliseconds). + * @return Read timeout + */ + public int getReadTimeout() { + return readTimeout; + } + + /** + * Set the read timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link Integer#MAX_VALUE}. + * @param readTimeout Read timeout in milliseconds + * @return API client + */ + public ApiClient setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + httpClient.property(ClientProperties.READ_TIMEOUT, readTimeout); + return this; + } + + /** + * Get the date format used to parse/format date parameters. + * @return Date format + */ + public DateFormat getDateFormat() { + return dateFormat; + } + + /** + * Set the date format used to parse/format date parameters. + * @param dateFormat Date format + * @return API client + */ + public ApiClient setDateFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + // also set the date format for model (de)serialization with Date properties + this.json.setDateFormat((DateFormat) dateFormat.clone()); + return this; + } + + /** + * Parse the given string into Date object. + * @param str String + * @return Date + */ + public Date parseDate(String str) { + try { + return dateFormat.parse(str); + } catch (java.text.ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * Format the given Date object into string. + * @param date Date + * @return Date in string format + */ + public String formatDate(Date date) { + return dateFormat.format(date); + } + + /** + * Format the given parameter object into string. + * @param param Object + * @return Object in string format + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date) { + return formatDate((Date) param); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for(Object o : (Collection)param) { + if(b.length() > 0) { + b.append(','); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /* + * Format to {@code Pair} objects. + * @param collectionFormat Collection format + * @param name Name + * @param value Value + * @return List of pairs + */ + public List parameterToPairs(String collectionFormat, String name, Object value){ + List params = new ArrayList<>(); + + // preconditions + if (name == null || name.isEmpty() || value == null) { + return params; + } + + Collection valueCollection; + if (value instanceof Collection) { + valueCollection = (Collection) value; + } else { + params.add(new Pair(name, parameterToString(value))); + return params; + } + + if (valueCollection.isEmpty()){ + return params; + } + + // get the collection format (default: csv) + String format = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat); + + // create the params based on the collection format + if ("multi".equals(format)) { + for (Object item : valueCollection) { + params.add(new Pair(name, parameterToString(item))); + } + return params; + } + + String delimiter = ","; + + if ("csv".equals(format)) { + delimiter = ","; + } else if ("ssv".equals(format)) { + delimiter = " "; + } else if ("tsv".equals(format)) { + delimiter = "\t"; + } else if ("pipes".equals(format)) { + delimiter = "|"; + } + + StringBuilder sb = new StringBuilder() ; + for (Object item : valueCollection) { + sb.append(delimiter); + sb.append(parameterToString(item)); + } + params.add(new Pair(name, sb.substring(1))); + return params; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * "* / *" is also default to JSON + * @param mime MIME + * @return True if the MIME type is JSON + */ + public boolean isJsonMime(String mime) { + String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; + return mime != null && (mime.matches(jsonMime) || mime.equals("*/*")); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } + return contentTypes[0]; + } + + /** + * Escape the given string to be used as URL query value. + * @param str String + * @return Escaped string + */ + public String escapeString(String str) { + try { + return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + return str; + } + } + + /** + * Serialize the given Java object into string entity according the given + * Content-Type (only JSON is supported for now). + * @param obj Object + * @param formParams Form parameters + * @param contentType Context type + * @return Entity + * @throws ApiException API exception + */ + public Entity serialize(Object obj, Map formParams, String contentType) throws ApiException { + Entity entity; + if (contentType.startsWith("multipart/form-data")) { + MultiPart multiPart = new MultiPart(); + for (Entry param: formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()) + .fileName(file.getName()).size(file.length()).build(); + multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + } else { + FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()).build(); + multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(param.getValue()))); + } + } + entity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE); + } else if (contentType.startsWith("application/x-www-form-urlencoded")) { + Form form = new Form(); + for (Entry param: formParams.entrySet()) { + form.param(param.getKey(), parameterToString(param.getValue())); + } + entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); + } else { + // We let jersey handle the serialization + entity = Entity.entity(obj, contentType); + } + return entity; + } + + /** + * Deserialize response body to Java object according to the Content-Type. + * @param Type + * @param response Response + * @param returnType Return type + * @return Deserialize object + * @throws ApiException API exception + */ + @SuppressWarnings("unchecked") + public T deserialize(Response response, GenericType returnType) throws ApiException { + if (response == null || returnType == null) { + return null; + } + + if ("byte[]".equals(returnType.toString())) { + // Handle binary response (byte array). + return (T) response.readEntity(byte[].class); + } else if (returnType.getRawType() == File.class) { + // Handle file downloading. + T file = (T) downloadFileFromResponse(response); + return file; + } + String contentType = null; + List contentTypes = response.getHeaders().get("Content-Type"); + if (contentTypes != null && !contentTypes.isEmpty()) { + contentType = String.valueOf(contentTypes.get(0)); + } + if (contentType == null) { + throw new ApiException(500, "missing Content-Type in response"); + } + return response.readEntity(returnType); + } + + /** + * Download file from the given response. + * @param response Response + * @return File + * @throws ApiException If fail to read file content from response and write to disk + */ + public File downloadFileFromResponse(Response response) throws ApiException { + try { + File file = prepareDownloadFile(response); + Files.copy(response.readEntity(InputStream.class), file.toPath(), StandardCopyOption.REPLACE_EXISTING); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + public File prepareDownloadFile(Response response) throws IOException { + String filename = null; + String contentDisposition = (String) response.getHeaders().getFirst("Content-Disposition"); + if (contentDisposition != null && !"".equals(contentDisposition)) { + // Get filename from the Content-Disposition header. + Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + Matcher matcher = pattern.matcher(contentDisposition); + if (matcher.find()) { + filename = matcher.group(1); + } + } + String prefix; + String suffix = null; + if (filename == null) { + prefix = "download-"; + suffix = ""; + } else { + int pos = filename.lastIndexOf('.'); + if (pos == -1) { + prefix = filename + "-"; + } else { + prefix = filename.substring(0, pos) + "-"; + suffix = filename.substring(pos); + } + // File.createTempFile requires the prefix to be at least three characters long + if (prefix.length() < 3) { + prefix = "download-"; + } + } + if (tempFolderPath == null) { + return Files.createTempFile(prefix, suffix).toFile(); + } else { + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); + } + } + + /** + * Invoke API by sending HTTP request with the given options. + * + * @param Type + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "POST", "PUT", "HEAD" and "DELETE" + * @param queryParams The query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param formParams The form parameters + * @param accept The request's Accept header + * @param contentType The request's Content-Type header + * @param authNames The authentications to apply + * @param returnType The return type into which to deserialize the response + * @return The response body in type of string + * @throws ApiException API exception + */ + public T invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType) throws ApiException { + updateParamsForAuth(authNames, queryParams, headerParams); + + // Not using `.target(this.basePath).path(path)` below, + // to support (constant) query string in `path`, e.g. "/posts?draft=1" + WebTarget target = httpClient.target(this.basePath + path); + + if (queryParams != null) { + for (Pair queryParam : queryParams) { + if (queryParam.getValue() != null) { + target = target.queryParam(queryParam.getName(), queryParam.getValue()); + } + } + } + Invocation.Builder invocationBuilder = target.request(); + if (accept != null) { + invocationBuilder = invocationBuilder.accept(accept); + } + for (Entry entry : headerParams.entrySet()) { + String value = entry.getValue(); + if (value != null) { + invocationBuilder = invocationBuilder.header(entry.getKey(), value); + } + } + for (Entry entry : defaultHeaderMap.entrySet()) { + String key = entry.getKey(); + if (!headerParams.containsKey(key)) { + String value = entry.getValue(); + if (value != null) { + invocationBuilder = invocationBuilder.header(key, value); + } + } + } + Entity entity = serialize(body, formParams, contentType); + + Response response = null; + try { + if ("GET".equals(method)) { + response = invocationBuilder.get(); + } else if ("POST".equals(method)) { + response = invocationBuilder.post(entity); + } else if ("PUT".equals(method)) { + response = invocationBuilder.put(entity); + } else if ("DELETE".equals(method)) { + response = invocationBuilder.delete(); + } else if ("PATCH".equals(method)) { + response = invocationBuilder.method("PATCH", entity); + } else if ("HEAD".equals(method)) { + response = invocationBuilder.head(); + } else { + throw new ApiException(500, "unknown method type " + method); + } + + statusCode = response.getStatusInfo().getStatusCode(); + responseHeaders = buildResponseHeaders(response); + + if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) { + return null; + } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) { + if (returnType == null) { + return null; + } else { + return deserialize(response, returnType); + } + } else { + String message = "error"; + String respBody = null; + if (response.hasEntity()) { + try { + respBody = String.valueOf(response.readEntity(String.class)); + message = respBody; + } catch (RuntimeException e) { + // e.printStackTrace(); + } + } + throw new ApiException( + response.getStatus(), + message, + buildResponseHeaders(response), + respBody); + } + } finally { + try { + response.close(); + } catch (Exception e) { + // it's not critical, since the response object is local in method invokeAPI; that's fine, just continue + } + } + } + + /** + * Build the Client used to make HTTP requests. + * @param debugging Debug setting + * @return Client + */ + protected Client buildHttpClient(boolean debugging) { + final ClientConfig clientConfig = new ClientConfig(); + clientConfig.register(MultiPartFeature.class); + clientConfig.register(json); + clientConfig.register(JacksonFeature.class); + clientConfig.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true); + if (debugging) { + clientConfig.register(new LoggingFeature(java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), java.util.logging.Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 1024*50 /* Log payloads up to 50K */)); + clientConfig.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY, LoggingFeature.Verbosity.PAYLOAD_ANY); + // Set logger to ALL + java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME).setLevel(java.util.logging.Level.ALL); + } + performAdditionalClientConfiguration(clientConfig); + return ClientBuilder.newClient(clientConfig); + } + + protected void performAdditionalClientConfiguration(ClientConfig clientConfig) { + // No-op extension point + } + + protected Map> buildResponseHeaders(Response response) { + Map> responseHeaders = new HashMap<>(); + for (Entry> entry: response.getHeaders().entrySet()) { + List values = entry.getValue(); + List headers = new ArrayList<>(); + for (Object o : values) { + headers.add(String.valueOf(o)); + } + responseHeaders.put(entry.getKey(), headers); + } + return responseHeaders; + } + + /** + * Update query and header parameters based on authentication settings. + * + * @param authNames The authentications to apply + */ + protected void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams) { + for (String authName : authNames) { + Authentication auth = authentications.get(authName); + if (auth == null) { + throw new RuntimeException("Authentication undefined: " + authName); + } + auth.applyToParams(queryParams, headerParams); + } + } +} diff --git a/src/main/resources/handlebars/Java/libraries/jersey3/JSON.mustache b/src/main/resources/handlebars/Java/libraries/jersey3/JSON.mustache new file mode 100644 index 0000000000..928832f182 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey3/JSON.mustache @@ -0,0 +1,38 @@ +package {{invokerPackage}}; + +import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.text.DateFormat; + +import jakarta.ws.rs.ext.ContextResolver; + +{{>generatedAnnotation}} +public class JSON implements ContextResolver { + private ObjectMapper mapper; + + public JSON() { + mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false); + mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); + mapper.setDateFormat(new RFC3339DateFormat()); + mapper.registerModule(new JavaTimeModule()); + } + + /** + * Set the date format for JSON (de)serialization with Date properties. + * @param dateFormat Date format + */ + public void setDateFormat(DateFormat dateFormat) { + mapper.setDateFormat(dateFormat); + } + + @Override + public ObjectMapper getContext(Class type) { + return mapper; + } +} diff --git a/src/main/resources/handlebars/Java/libraries/jersey3/api.mustache b/src/main/resources/handlebars/Java/libraries/jersey3/api.mustache new file mode 100644 index 0000000000..9024d15a92 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey3/api.mustache @@ -0,0 +1,118 @@ +package {{package}};//jersey3 + +import {{invokerPackage}}.ApiException; +import {{invokerPackage}}.ApiClient; +import {{invokerPackage}}.Configuration; +import {{invokerPackage}}.Pair; + +import jakarta.ws.rs.core.GenericType; + +{{#imports}}import {{import}}; +{{/imports}} + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +{{>generatedAnnotation}} +{{#operations}} +public class {{classname}} { + private ApiClient {{localVariablePrefix}}apiClient; + + public {{classname}}() { + this(Configuration.getDefaultApiClient()); + } + + public {{classname}}(ApiClient apiClient) { + this.{{localVariablePrefix}}apiClient = apiClient; + } + + public ApiClient getApiClient() { + return {{localVariablePrefix}}apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.{{localVariablePrefix}}apiClient = apiClient; + } + + {{#operation}} + {{#contents}} + /** + * {{summary}} + * {{notes}} + {{#parameters}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} + {{/parameters}} + {{#returnType}} + * @return {{returnType}} + {{/returnType}} + * @throws ApiException if fails to make API call + {{#isDeprecated}} + * @deprecated + {{/isDeprecated}} + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + {{#isDeprecated}} + @Deprecated + {{/isDeprecated}} + public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}}) throws ApiException { + Object {{localVariablePrefix}}localVarPostBody = {{^isForm}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/isForm}}{{#isForm}}null{{/isForm}}; + {{#parameters}} + {{#required}} + // verify the required parameter '{{paramName}}' is set + if ({{paramName}} == null) { + throw new ApiException(400, "Missing the required parameter '{{paramName}}' when calling {{operationId}}"); + } + {{/required}} + {{/parameters}} + // create path and map variables + String {{localVariablePrefix}}localVarPath = "{{{path}}}"{{#pathParams}} + .replaceAll("\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}}; + + // query params + {{javaUtilPrefix}}List {{localVariablePrefix}}localVarQueryParams = new {{javaUtilPrefix}}ArrayList(); + {{javaUtilPrefix}}Map {{localVariablePrefix}}localVarHeaderParams = new {{javaUtilPrefix}}HashMap(); + {{javaUtilPrefix}}Map {{localVariablePrefix}}localVarFormParams = new {{javaUtilPrefix}}HashMap(); + + {{#queryParams}} + {{localVariablePrefix}}localVarQueryParams.addAll({{localVariablePrefix}}apiClient.parameterToPairs("{{#collectionFormat}}{{{collectionFormat}}}{{/collectionFormat}}", "{{baseName}}", {{paramName}})); + {{/queryParams}} + + {{#headerParams}} + if ({{paramName}} != null) { + {{localVariablePrefix}}localVarHeaderParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); + } + {{/headerParams}} + {{#isForm}} + {{#formParams}} + if ({{paramName}} != null) + {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}}); + {{/formParams}} + {{/isForm}} + + final String[] {{localVariablePrefix}}localVarAccepts = { + {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} + }; + final String {{localVariablePrefix}}localVarAccept = {{localVariablePrefix}}apiClient.selectHeaderAccept({{localVariablePrefix}}localVarAccepts); + final String[] {{localVariablePrefix}}localVarContentTypes = { + {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} + }; + final String {{localVariablePrefix}}localVarContentType = {{localVariablePrefix}}apiClient.selectHeaderContentType({{localVariablePrefix}}localVarContentTypes); + + String[] {{localVariablePrefix}}localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{#has this 'more'}}, {{/has}}{{/authMethods}} }; + + {{#returnType}} + GenericType<{{{returnType}}}> {{localVariablePrefix}}localVarReturnType = new GenericType<{{{returnType}}}>() {}; + return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccept, {{localVariablePrefix}}localVarContentType, {{localVariablePrefix}}localVarAuthNames, {{localVariablePrefix}}localVarReturnType); + {{/returnType}}{{^returnType}} + {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccept, {{localVariablePrefix}}localVarContentType, {{localVariablePrefix}}localVarAuthNames, null); + {{/returnType}} + } + {{/contents}} + {{/operation}} +} +{{/operations}} diff --git a/src/main/resources/handlebars/Java/libraries/jersey3/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/jersey3/build.gradle.mustache new file mode 100644 index 0000000000..88426fa8d3 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey3/build.gradle.mustache @@ -0,0 +1,66 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + swagger_annotations_version = "2.2.8" + jackson_version = "2.14.2" + jersey_version = "3.1.1" + junit_version = "4.13.2" +} + +dependencies { + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + implementation "org.glassfish.jersey.core:jersey-client:$jersey_version" + implementation "org.glassfish.jersey.media:jersey-media-multipart:$jersey_version" + implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + {{#withXml}} + implementation "org.glassfish.jersey.media:jersey-media-jaxb:$jersey_version" + {{/withXml}} + implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version" + testImplementation "junit:junit:$junit_version" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 1.8 +java.targetCompatibility = 1.8 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/jersey3/build.sbt.mustache b/src/main/resources/handlebars/Java/libraries/jersey3/build.sbt.mustache new file mode 100644 index 0000000000..5c9a87d31a --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey3/build.sbt.mustache @@ -0,0 +1,44 @@ +lazy val root = (project in file(".")). + settings( + organization := "{{groupId}}", + name := "{{artifactId}}", + version := "{{artifactVersion}}", + scalaVersion := "2.11.4", + scalacOptions ++= Seq("-feature"), + javacOptions in compile ++= Seq("-Xlint:deprecation"), + publishArtifact in (Compile, packageDoc) := false, + resolvers += Resolver.mavenLocal, + libraryDependencies ++= Seq( + {{#useOas2}} + "io.swagger" % "swagger-annotations" % "1.5.15", + {{/useOas2}} + {{^useOas2}} + "io.swagger.core.v3" % "swagger-annotations" % "2.0.0", + {{/useOas2}} + "org.glassfish.jersey.core" % "jersey-client" % "2.29.1", + "org.glassfish.jersey.media" % "jersey-media-multipart" % "2.29.1", + "org.glassfish.jersey.media" % "jersey-media-json-jackson" % "2.29.1", + "org.glassfish.jersey.inject" % "jersey-hk2" % "2.29.1", + "com.fasterxml.jackson.core" % "jackson-core" % "{{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", + "com.fasterxml.jackson.core" % "jackson-annotations" % "{{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", + "com.fasterxml.jackson.core" % "jackson-databind" % "{{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" % "compile", + {{#joda}} + "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.10.1" % "compile", + {{/joda}} + {{#java8}} + "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.10.1" % "compile", + {{/java8}} + {{#threetenbp}} + "com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.6.4" % "compile", + {{/threetenbp}} + {{^java8}} + "com.brsanthu" % "migbase64" % "2.2", + {{/java8}} + {{#supportJava6}} + "org.apache.commons" % "commons-lang3" % "3.6", + "commons-io" % "commons-io" % "2.5", + {{/supportJava6}} + "junit" % "junit" % "4.12" % "test", + "com.novocode" % "junit-interface" % "0.10" % "test" + ) + ) diff --git a/src/main/resources/handlebars/Java/libraries/jersey3/pom.mustache b/src/main/resources/handlebars/Java/libraries/jersey3/pom.mustache new file mode 100644 index 0000000000..ecfc95ae6a --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/jersey3/pom.mustache @@ -0,0 +1,269 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + {{artifactUrl}} + {{artifactDescription}} + + {{scmConnection}} + {{scmDeveloperConnection}} + {{scmUrl}} + + + 2.2.0 + + + + + {{licenseName}} + {{licenseUrl}} + repo + + + + + + {{developerName}} + {{developerEmail}} + {{developerOrganization}} + {{developerOrganizationUrl}} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add_sources + generate-sources + + add-source + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + + + + + sign-artifacts + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + + + + io.swagger.core.v3 + swagger-annotations + ${swagger-core-version} + + + + + org.glassfish.jersey.core + jersey-client + ${jersey-version} + + + org.glassfish.jersey.media + jersey-media-multipart + ${jersey-version} + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey-version} + + + org.glassfish.jersey.inject + jersey-hk2 + 2.29.1 + + + + + com.fasterxml.jackson.core + jackson-core + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-version} + + {{#withXml}} + + + org.glassfish.jersey.media + jersey-media-jaxb + ${jersey-version} + + {{/withXml}} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-version} + + {{#useBeanValidation}} + + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/useBeanValidation}} + + + junit + junit + ${junit-version} + test + + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} + + + 2.2.8 + 3.0.10 + 2.14.2 + 1.0.0 + 4.13.2 + + diff --git a/src/main/resources/handlebars/Java/libraries/okhttp-gson/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/okhttp-gson/ApiClient.mustache index 881db0fc1d..30bcae2c12 100644 --- a/src/main/resources/handlebars/Java/libraries/okhttp-gson/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp-gson/ApiClient.mustache @@ -24,6 +24,8 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.lang.reflect.Type; import java.net.URLConnection; import java.net.URLEncoder; @@ -829,9 +831,9 @@ public class ApiClient { } if (tempFolderPath == null) - return File.createTempFile(prefix, suffix); + return Files.createTempFile(prefix, suffix).toFile(); else - return File.createTempFile(prefix, suffix, new File(tempFolderPath)); + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); } /** @@ -981,7 +983,7 @@ public class ApiClient { * @param formParams The form parameters * @param authNames The authentications to apply * @param progressRequestListener Progress request listener - * @return The HTTP request + * @return The HTTP request * @throws ApiException If fail to serialize the request body object */ public Request buildRequest(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { diff --git a/src/main/resources/handlebars/Java/libraries/okhttp-gson/JSON.mustache b/src/main/resources/handlebars/Java/libraries/okhttp-gson/JSON.mustache index 3dcef4e9c7..02b2fa04ed 100644 --- a/src/main/resources/handlebars/Java/libraries/okhttp-gson/JSON.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp-gson/JSON.mustache @@ -5,7 +5,9 @@ package {{invokerPackage}}; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import io.gsonfire.GsonFireBuilder; +import io.gsonfire.PostProcessor; import io.gsonfire.TypeSelector; import com.google.gson.JsonParseException; import com.google.gson.TypeAdapter; @@ -59,6 +61,7 @@ public class JSON { public static GsonBuilder createGson() { GsonFireBuilder fireBuilder = new GsonFireBuilder() {{#parent}} + {{#discriminator}} .registerTypeSelector({{classname}}.class, new TypeSelector<{{classname}}>() { @Override public Class getClassForElement(JsonElement readElement) { @@ -78,6 +81,35 @@ public class JSON { getDiscriminatorValue(readElement, "{{discriminator.propertyName}}")); } }) + .registerPostProcessor({{classname}}.class, new PostProcessor<{{classname}}>() { + @Override + public void postDeserialize({{classname}} result, JsonElement src, Gson gson) { + + } + + @Override + public void postSerialize(JsonElement result, {{classname}} src, Gson gson) { + Map, String> discriminatorValueByClass = new HashMap<>(); + {{#if discriminator.mapping}} + {{#each discriminator.mapping}} + discriminatorValueByClass.put({{this}}.class, "{{@key}}"); + {{/each}} + {{else}} + {{#children}} + discriminatorValueByClass.put({{classname}}.class, "{{name}}"); + {{/children}} + discriminatorValueByClass.put({{classname}}.class, "{{classname}}"); + {{/if}} + if(result instanceof JsonObject) + { + if(!((JsonObject) result).has("{{discriminator.propertyName}}")) + { + ((JsonObject) result).addProperty("{{discriminator.propertyName}}", discriminatorValueByClass.get(src.getClass())); + } + } + } + }) + {{/discriminator}} {{/parent}} ; return fireBuilder.createGsonBuilder(); diff --git a/src/main/resources/handlebars/Java/libraries/okhttp-gson/api.mustache b/src/main/resources/handlebars/Java/libraries/okhttp-gson/api.mustache index eb25fa7d62..b1033181f5 100644 --- a/src/main/resources/handlebars/Java/libraries/okhttp-gson/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp-gson/api.mustache @@ -19,13 +19,26 @@ import com.google.gson.reflect.TypeToken; import java.io.IOException; {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{#performBeanValidation}} +{{#jakarta}} +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; +import jakarta.validation.executable.ExecutableValidator; +{{/jakarta}} +{{^jakarta}} import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.ValidatorFactory; import javax.validation.executable.ExecutableValidator; +{{/jakarta}} import java.util.Set; import java.lang.reflect.Method; import java.lang.reflect.Type; @@ -248,4 +261,4 @@ public class {{classname}} { {{/contents}} {{/operation}} } -{{/operations}} \ No newline at end of file +{{/operations}} diff --git a/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.java11.mustache new file mode 100644 index 0000000000..8208643f6a --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.java11.mustache @@ -0,0 +1,65 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +dependencies { + {{#useOas2}} + implementation 'io.swagger:swagger-annotations:1.5.24' + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:2.0.0" + {{/useOas2}} + implementation 'com.squareup.okhttp:okhttp:2.7.5' + implementation 'com.squareup.okhttp:logging-interceptor:2.7.5' + implementation 'com.google.code.gson:gson:2.8.1' + implementation 'io.gsonfire:gson-fire:1.8.0' + {{#joda}} + implementation 'joda-time:joda-time:2.9.9' + {{/joda}} + {{#threetenbp}} + implementation 'org.threeten:threetenbp:1.3.5' + {{/threetenbp}} + implementation 'com.sun.xml.ws:jaxws-rt:{{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}}' + testImplementation 'junit:junit:4.13.1' + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.mustache index 2bb4b26834..0fe9528bcb 100644 --- a/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp-gson/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } diff --git a/src/main/resources/handlebars/Java/libraries/okhttp-gson/pom.mustache b/src/main/resources/handlebars/Java/libraries/okhttp-gson/pom.mustache index ee00eae37c..40141310da 100644 --- a/src/main/resources/handlebars/Java/libraries/okhttp-gson/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp-gson/pom.mustache @@ -118,7 +118,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -166,6 +166,22 @@ + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + {{/java11}} @@ -183,6 +199,13 @@ ${swagger-core-version} {{/useOas2}} + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + 2.10.1 + + {{/notNullJacksonAnnotation}} com.squareup.okhttp okhttp @@ -231,25 +254,44 @@ {{/supportJava6}} {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} - javax.validation - validation-api - 1.1.0.Final - provided + javax.validation + validation-api + 1.1.0.Final + provided + {{/jakarta}} {{/useBeanValidation}} {{#performBeanValidation}} org.hibernate hibernate-validator - 5.4.1.Final + {{#jakarta}}8.0.0.Final{{/jakarta}}{{^jakarta}}5.4.1.Final{{/jakarta}} + {{#jakarta}} + + jakarta.el + jakarta.el-api + 5.0.1 + + {{/jakarta}} + {{^jakarta}} javax.el el-api 2.2 + {{/jakarta}} {{/performBeanValidation}} {{#parcelableModel}} @@ -267,9 +309,17 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} {{#useOas2}} @@ -292,7 +342,7 @@ 1.3.5 {{/threetenbp}} 1.0.0 - 4.12 + 4.13.1 UTF-8 diff --git a/src/main/resources/mustache/Java/libraries/okhttp-gson/ApiCallback.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiCallback.mustache similarity index 100% rename from src/main/resources/mustache/Java/libraries/okhttp-gson/ApiCallback.mustache rename to src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiCallback.mustache diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiClient.mustache new file mode 100644 index 0000000000..7b42211558 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiClient.mustache @@ -0,0 +1,1029 @@ +{{>licenseInfo}} + +package {{invokerPackage}}; + +import okhttp3.*; +import okhttp3.internal.http.HttpMethod; +import okhttp3.logging.HttpLoggingInterceptor; +import okhttp3.logging.HttpLoggingInterceptor.Level; +import okio.BufferedSink; +import okio.Okio; +{{#joda}} +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormatter; +{{/joda}} +{{#threetenbp}} +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; +{{/threetenbp}} + +import javax.net.ssl.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.lang.reflect.Type; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +{{#java8}} +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +{{/java8}} +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import {{invokerPackage}}.auth.Authentication; +import {{invokerPackage}}.auth.HttpBasicAuth; +import {{invokerPackage}}.auth.ApiKeyAuth; +import {{invokerPackage}}.auth.OAuth; + +public class ApiClient { + + private String basePath = "{{{basePath}}}"; + private boolean debugging = false; + private Map defaultHeaderMap = new HashMap(); + private String tempFolderPath = null; + + private Map authentications; + + private DateFormat dateFormat; + private DateFormat datetimeFormat; + private boolean lenientDatetimeFormat; + private int dateLength; + + private OkHttpClient httpClient; + private JSON json; + + private HttpLoggingInterceptor loggingInterceptor; + + /* + * Constructor for ApiClient + */ + public ApiClient() { + httpClient = new OkHttpClient(); + + {{#useGzipFeature}} + // Enable gzip request compression + httpClient.interceptors().add(new GzipRequestInterceptor()); + {{/useGzipFeature}} + + json = new JSON(); + + // Set default User-Agent. + setUserAgent("{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{artifactVersion}}}/java{{/httpUserAgent}}"); + + // Setup authentications (key: authentication name, value: authentication). + authentications = new HashMap();{{#authMethods}}{{#isBasic}} + authentications.put("{{name}}", new HttpBasicAuth());{{/isBasic}}{{#isApiKey}} + authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}} + authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{#isBearer}} + authentications.put("{{name}}", new OAuth());{{/isBearer}}{{/authMethods}} + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + /** + * Get base path + * + * @return Baes path + */ + public String getBasePath() { + return basePath; + } + + /** + * Set base path + * + * @param basePath Base path of the URL (e.g {{{basePath}}} + * @return An instance of OkHttpClient + */ + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + /** + * Get HTTP client + * Use to update with modification for e.g. setHttpClient(getHttpClient.newBuilder().readTimeout(5, TimeUnit.SECONDS).build()) + * @return An instance of OkHttpClient + */ + public OkHttpClient getHttpClient() { + return httpClient; + } + + /** + * Set HTTP client + * Update with a modified instance using for e.g. setHttpClient(getHttpClient.newBuilder().readTimeout(5, TimeUnit.SECONDS).build()) + * @param httpClient An instance of OkHttpClient + * @return Api Client + */ + public ApiClient setHttpClient(OkHttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Get JSON + * + * @return JSON object + */ + public JSON getJSON() { + return json; + } + + /** + * Set JSON + * + * @param json JSON object + * @return Api client + */ + public ApiClient setJSON(JSON json) { + this.json = json; + return this; + } + + public DateFormat getDateFormat() { + return dateFormat; + } + + public ApiClient setDateFormat(DateFormat dateFormat) { + this.json.setDateFormat(dateFormat); + return this; + } + + public ApiClient setSqlDateFormat(DateFormat dateFormat) { + this.json.setSqlDateFormat(dateFormat); + return this; + } + + {{#joda}} + public ApiClient setDateTimeFormat(DateTimeFormatter dateFormat) { + this.json.setDateTimeFormat(dateFormat); + return this; + } + + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + this.json.setLocalDateFormat(dateFormat); + return this; + } + + {{/joda}} + {{#jsr310}} + public ApiClient setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + this.json.setOffsetDateTimeFormat(dateFormat); + return this; + } + + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + this.json.setLocalDateFormat(dateFormat); + return this; + } + + {{/jsr310}} + public ApiClient setLenientOnJson(boolean lenientOnJson) { + this.json.setLenientOnJson(lenientOnJson); + return this; + } + + /** + * Get authentications (key: authentication name, value: authentication). + * + * @return Map of authentication objects + */ + public Map getAuthentications() { + return authentications; + } + + /** + * Get authentication for the given name. + * + * @param authName The authentication name + * @return The authentication, null if not found + */ + public Authentication getAuthentication(String authName) { + return authentications.get(authName); + } + + /** + * Helper method to set username for the first HTTP basic authentication. + * + * @param username Username + */ + public void setUsername(String username) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setUsername(username); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set password for the first HTTP basic authentication. + * + * @param password Password + */ + public void setPassword(String password) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setPassword(password); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set API key value for the first API key authentication. + * + * @param apiKey API key + */ + public void setApiKey(String apiKey) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKey(apiKey); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set API key prefix for the first API key authentication. + * + * @param apiKeyPrefix API key prefix + */ + public void setApiKeyPrefix(String apiKeyPrefix) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set access token for the first OAuth2 authentication. + * + * @param accessToken Access token + */ + public void setAccessToken(String accessToken) { + for (Authentication auth : authentications.values()) { + if (auth instanceof OAuth) { + ((OAuth) auth).setAccessToken(accessToken); + return; + } + } + throw new RuntimeException("No OAuth2 authentication configured!"); + } + + /** + * Set the User-Agent header's value (by adding to the default header map). + * + * @param userAgent HTTP request's user agent + * @return ApiClient + */ + public ApiClient setUserAgent(String userAgent) { + addDefaultHeader("User-Agent", userAgent); + return this; + } + + /** + * Add a default header. + * + * @param key The header's key + * @param value The header's value + * @return ApiClient + */ + public ApiClient addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + return this; + } + + /** + * Check that whether debugging is enabled for this API client. + * + * @return True if debugging is enabled, false otherwise. + */ + public boolean isDebugging() { + return debugging; + } + + /** + * Enable/disable debugging for this API client. + * + * @param debugging To enable (true) or disable (false) debugging + * @return ApiClient + */ + public ApiClient setDebugging(boolean debugging) { + if (debugging != this.debugging) { + if (debugging) { + loggingInterceptor = new HttpLoggingInterceptor(); + loggingInterceptor.setLevel(Level.BODY); + httpClient.interceptors().add(loggingInterceptor); + } else { + httpClient.interceptors().remove(loggingInterceptor); + loggingInterceptor = null; + } + } + this.debugging = debugging; + return this; + } + + /** + * The path of temporary folder used to store downloaded files from endpoints + * with file response. The default value is null, i.e. using + * the system's default tempopary folder. + * + * @see createTempFile + * @return Temporary folder path + */ + public String getTempFolderPath() { + return tempFolderPath; + } + + /** + * Set the temporary folder path (for downloading files) + * + * @param tempFolderPath Temporary folder path + * @return ApiClient + */ + public ApiClient setTempFolderPath(String tempFolderPath) { + this.tempFolderPath = tempFolderPath; + return this; + } + + /** + * Format the given parameter object into string. + * + * @param param Parameter + * @return String representation of the parameter + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date {{#joda}}|| param instanceof DateTime || param instanceof LocalDate{{/joda}}{{#jsr310}}|| param instanceof OffsetDateTime || param instanceof LocalDate{{/jsr310}}) { + //Serialize to json string and remove the " enclosing characters + String jsonStr = json.serialize(param); + return jsonStr.substring(1, jsonStr.length() - 1); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for (Object o : (Collection)param) { + if (b.length() > 0) { + b.append(","); + } + b.append(String.valueOf(o)); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Formats the specified query parameter to a list containing a single {@code Pair} object. + * + * Note that {@code value} must not be a collection. + * + * @param name The name of the parameter. + * @param value The value of the parameter. + * @return A list containing a single {@code Pair} object. + */ + public List parameterToPair(String name, Object value) { + List params = new ArrayList<>(); + + // preconditions + if (name == null || name.isEmpty() || value == null || value instanceof Collection) return params; + + params.add(new Pair(name, parameterToString(value))); + return params; + } + + /** + * Formats the specified collection query parameters to a list of {@code Pair} objects. + * + * Note that the values of each of the returned Pair objects are percent-encoded. + * + * @param collectionFormat The collection format of the parameter. + * @param name The name of the parameter. + * @param value The value of the parameter. + * @return A list of {@code Pair} objects. + */ + public List parameterToPairs(String collectionFormat, String name, Collection value) { + List params = new ArrayList<>(); + + // preconditions + if (name == null || name.isEmpty() || value == null || value.isEmpty()) { + return params; + } + + // create the params based on the collection format + if ("multi".equals(collectionFormat)) { + for (Object item : value) { + params.add(new Pair(name, escapeString(parameterToString(item)))); + } + return params; + } + + // collectionFormat is assumed to be "csv" by default + String delimiter = ","; + + // escape all delimiters except commas, which are URI reserved + // characters + if ("ssv".equals(collectionFormat)) { + delimiter = escapeString(" "); + } else if ("tsv".equals(collectionFormat)) { + delimiter = escapeString("\t"); + } else if ("pipes".equals(collectionFormat)) { + delimiter = escapeString("|"); + } + + StringBuilder sb = new StringBuilder() ; + for (Object item : value) { + sb.append(delimiter); + sb.append(escapeString(parameterToString(item))); + } + + params.add(new Pair(name, sb.substring(delimiter.length()))); + + return params; + } + + /** + * Sanitize filename by removing path. + * e.g. ../../sun.gif becomes sun.gif + * + * @param filename The filename to be sanitized + * @return The sanitized filename + */ + public String sanitizeFilename(String filename) { + return filename.replaceAll(".*[/\\\\]", ""); + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * "* / *" is also default to JSON + * @param mime MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public boolean isJsonMime(String mime) { + String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; + return mime != null && (mime.matches(jsonMime) || mime.equals("*/*")); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * or matches "any", JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0 || contentTypes[0].equals("*/*")) { + return "application/json"; + } + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } + return contentTypes[0]; + } + + /** + * Escape the given string to be used as URL query value. + * + * @param str String to be escaped + * @return Escaped string + */ + public String escapeString(String str) { + try { + return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + return str; + } + } + + /** + * Deserialize response body to Java object, according to the return type and + * the Content-Type response header. + * + * @param Type + * @param response HTTP response + * @param returnType The type of the Java object + * @return The deserialized Java object + * @throws ApiException If fail to deserialize response body, i.e. cannot read response body + * or the Content-Type of the response is not supported. + */ + @SuppressWarnings("unchecked") + private T deserialize(Response response, Type returnType) throws ApiException { + if (response == null || returnType == null) { + return null; + } + + if ("byte[]".equals(returnType.toString())) { + // Handle binary response (byte array). + try { + return (T) response.body().bytes(); + } catch (IOException e) { + throw new ApiException(e); + } + } else if (returnType.equals(File.class)) { + // Handle file downloading. + return (T) downloadFileFromResponse(response); + } + + String respBody; + try { + if (response.body() != null) + respBody = response.body().string(); + else + respBody = null; + } catch (IOException e) { + throw new ApiException(e); + } + + if (respBody == null || "".equals(respBody)) { + return null; + } + + String contentType = response.headers().get("Content-Type"); + if (contentType == null) { + // ensuring a default content type + contentType = "application/json"; + } + if (isJsonMime(contentType)) { + return json.deserialize(respBody, returnType); + } else if (returnType.equals(String.class)) { + // Expecting string, return the raw response body. + return (T) respBody; + } else { + throw new ApiException( + "Content type \"" + contentType + "\" is not supported for type: " + returnType, + response.code(), + response.headers().toMultimap(), + respBody); + } + } + + /** + * Serialize the given Java object into request body according to the object's + * class and the request Content-Type. + * + * @param obj The Java object + * @param contentType The request Content-Type + * @return The serialized request body + * @throws ApiException If fail to serialize the given object + */ + private RequestBody serialize(Object obj, String contentType) throws ApiException { + if (obj instanceof byte[]) { + // Binary (byte array) body parameter support. + return RequestBody.create((byte[]) obj, MediaType.parse(contentType)); + } else if (obj instanceof File) { + // File body parameter support. + return RequestBody.create((File) obj, MediaType.parse(contentType)); + } else if (isJsonMime(contentType)) { + String content; + if (obj != null) { + content = json.serialize(obj); + } else { + content = null; + } + return RequestBody.create(content, MediaType.parse(contentType)); + } else { + throw new ApiException("Content type \"" + contentType + "\" is not supported"); + } + } + + /** + * Download file from the given response. + * + * @param response An instance of the Response object + * @throws ApiException If fail to read file content from response and write to disk + * @return Downloaded file + */ + public File downloadFileFromResponse(Response response) throws ApiException { + try { + File file = prepareDownloadFile(response); + BufferedSink sink = Okio.buffer(Okio.sink(file)); + sink.writeAll(response.body().source()); + sink.close(); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * Prepare file for download + * + * @param response An instance of the Response object + * @throws IOException If fail to prepare file for download + * @return Prepared file for the download + */ + public File prepareDownloadFile(Response response) throws IOException { + String filename = null; + String contentDisposition = response.header("Content-Disposition"); + if (contentDisposition != null && !"".equals(contentDisposition)) { + // Get filename from the Content-Disposition header. + Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + Matcher matcher = pattern.matcher(contentDisposition); + if (matcher.find()) { + filename = sanitizeFilename(matcher.group(1)); + } + } + + String prefix = null; + String suffix = null; + if (filename == null) { + prefix = "download-"; + suffix = ""; + } else { + int pos = filename.lastIndexOf("."); + if (pos == -1) { + prefix = filename + "-"; + } else { + prefix = filename.substring(0, pos) + "-"; + suffix = filename.substring(pos); + } + // File.createTempFile requires the prefix to be at least three characters long + if (prefix.length() < 3) + prefix = "download-"; + } + + if (tempFolderPath == null) + return Files.createTempFile(prefix, suffix).toFile(); + else + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); + } + + /** + * {@link #execute(Call, Type)} + * + * @param Type + * @param call An instance of the Call object + * @throws ApiException If fail to execute the call + * @return ApiResponse<T> + */ + public ApiResponse execute(Call call) throws ApiException { + return execute(call, null); + } + + /** + * Execute HTTP call and deserialize the HTTP response body into the given return type. + * + * @param returnType The return type used to deserialize HTTP response body + * @param The return type corresponding to (same with) returnType + * @param call Call + * @return ApiResponse object containing response status, headers and + * data, which is a Java object deserialized from response body and would be null + * when returnType is null. + * @throws ApiException If fail to execute the call + */ + public ApiResponse execute(Call call, Type returnType) throws ApiException { + try { + Response response = call.execute(); + T data = handleResponse(response, returnType); + return new ApiResponse(response.code(), response.headers().toMultimap(), data); + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * {@link #executeAsync(Call, Type, ApiCallback)} + * + * @param Type + * @param call An instance of the Call object + * @param callback ApiCallback<T> + */ + public void executeAsync(Call call, ApiCallback callback) { + executeAsync(call, null, callback); + } + + /** + * Execute HTTP call asynchronously. + * + * @see #execute(Call, Type) + * @param Type + * @param call The callback to be executed when the API call finishes + * @param returnType Return type + * @param callback ApiCallback + */ + @SuppressWarnings("unchecked") + public void executeAsync(Call call, final Type returnType, final ApiCallback callback) { + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + callback.onFailure(new ApiException(e), 0, null); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + T result; + try { + result = (T) handleResponse(response, returnType); + } catch (ApiException e) { + callback.onFailure(e, response.code(), response.headers().toMultimap()); + return; + } + callback.onSuccess(result, response.code(), response.headers().toMultimap()); + } + }); + } + + /** + * Handle the given response, return the deserialized object when the response is successful. + * + * @param Type + * @param response Response + * @param returnType Return type + * @throws ApiException If the response has a unsuccessful status code or + * fail to deserialize the response body + * @return Type + */ + private T handleResponse(Response response, Type returnType) throws ApiException { + if (response.isSuccessful()) { + if (returnType == null || response.code() == 204) { + // returning null if the returnType is not defined, + // or the status code is 204 (No Content) + if (response.body() != null) { + response.body().close(); + } + return null; + } else { + return deserialize(response, returnType); + } + } else { + String respBody = null; + if (response.body() != null) { + try { + respBody = response.body().string(); + } catch (IOException e) { + throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); + } + } + throw new ApiException(response.message(), response.code(), response.headers().toMultimap(), respBody); + } + } + + /** + * Build HTTP call with the given options. + * + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param formParams The form parameters + * @param authNames The authentications to apply + * @param progressRequestListener Progress request listener + * @return The HTTP call + * @throws ApiException If fail to serialize the request body object + */ + public Call buildCall(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Request request = buildRequest(path, method, queryParams, collectionQueryParams, body, headerParams, formParams, authNames, progressRequestListener); + + return httpClient.newCall(request); + } + + /** + * Build an HTTP request with the given options. + * + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param formParams The form parameters + * @param authNames The authentications to apply + * @param progressRequestListener Progress request listener + * @return The HTTP request + * @throws ApiException If fail to serialize the request body object + */ + public Request buildRequest(String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map formParams, String[] authNames, ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + updateParamsForAuth(authNames, queryParams, headerParams); + + final String url = buildUrl(path, queryParams, collectionQueryParams); + final Request.Builder reqBuilder = new Request.Builder().url(url); + processHeaderParams(headerParams, reqBuilder); + + String contentType = (String) headerParams.get("Content-Type"); + // ensuring a default content type + if (contentType == null) { + contentType = "application/json"; + } + + RequestBody reqBody; + if (!HttpMethod.permitsRequestBody(method)) { + reqBody = null; + } else if ("application/x-www-form-urlencoded".equals(contentType)) { + reqBody = buildRequestBodyFormEncoding(formParams); + } else if ("multipart/form-data".equals(contentType)) { + reqBody = buildRequestBodyMultipart(formParams); + } else if (body == null) { + if ("DELETE".equals(method)) { + // allow calling DELETE without sending a request body + reqBody = null; + } else { + // use an empty request body (for POST, PUT and PATCH) + reqBody = RequestBody.create("", MediaType.parse(contentType)); + } + } else { + reqBody = serialize(body, contentType); + } + + Request request = null; + + if(progressRequestListener != null && reqBody != null) { + ProgressRequestBody progressRequestBody = new ProgressRequestBody(reqBody, progressRequestListener); + request = reqBuilder.method(method, progressRequestBody).build(); + } else { + request = reqBuilder.method(method, reqBody).build(); + } + + return request; + } + + /** + * Build full URL by concatenating base path, the given sub path and query parameters. + * + * @param path The sub path + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @return The full URL + */ + private String buildUrl(String path, List queryParams, List collectionQueryParams) { + final StringBuilder url = new StringBuilder(); + url.append(basePath).append(path); + + if (queryParams != null && !queryParams.isEmpty()) { + // support (constant) query string in `path`, e.g. "/posts?draft=1" + String prefix = path.contains("?") ? "&" : "?"; + for (Pair param : queryParams) { + if (param.getValue() != null) { + if (prefix != null) { + url.append(prefix); + prefix = null; + } else { + url.append("&"); + } + String value = parameterToString(param.getValue()); + url.append(escapeString(param.getName())).append("=").append(escapeString(value)); + } + } + } + + if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) { + String prefix = url.toString().contains("?") ? "&" : "?"; + for (Pair param : collectionQueryParams) { + if (param.getValue() != null) { + if (prefix != null) { + url.append(prefix); + prefix = null; + } else { + url.append("&"); + } + String value = parameterToString(param.getValue()); + // collection query parameter value already escaped as part of parameterToPairs + url.append(escapeString(param.getName())).append("=").append(value); + } + } + } + + return url.toString(); + } + + /** + * Set header parameters to the request builder, including default headers. + * + * @param headerParams Header parameters in the ofrm of Map + * @param reqBuilder Reqeust.Builder + */ + private void processHeaderParams(Map headerParams, Request.Builder reqBuilder) { + for (Entry param : headerParams.entrySet()) { + reqBuilder.header(param.getKey(), parameterToString(param.getValue())); + } + for (Entry header : defaultHeaderMap.entrySet()) { + if (!headerParams.containsKey(header.getKey())) { + reqBuilder.header(header.getKey(), parameterToString(header.getValue())); + } + } + } + + /** + * Update query and header parameters based on authentication settings. + * + * @param authNames The authentications to apply + * @param queryParams List of query parameters + * @param headerParams Map of header parameters + */ + private void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams) { + for (String authName : authNames) { + Authentication auth = authentications.get(authName); + if (auth == null) throw new RuntimeException("Authentication undefined: " + authName); + auth.applyToParams(queryParams, headerParams); + } + } + + /** + * Build a form-encoding request body with the given form parameters. + * + * @param formParams Form parameters in the form of Map + * @return RequestBody + */ + private RequestBody buildRequestBodyFormEncoding(Map formParams) { + FormBody.Builder formBuilder = new FormBody.Builder(); + for (Entry param : formParams.entrySet()) { + formBuilder.add(param.getKey(), parameterToString(param.getValue())); + } + return formBuilder.build(); + } + + /** + * Build a multipart (file uploading) request body with the given form parameters, + * which could contain text fields and file fields. + * + * @param formParams Form parameters in the form of Map + * @return RequestBody + */ + private RequestBody buildRequestBodyMultipart(Map formParams) { + MultipartBody.Builder mpBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); + for (Entry param : formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\"; filename=\"" + file.getName() + "\""); + MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file)); + mpBuilder.addPart(partHeaders, RequestBody.create(mediaType, file)); + } else { + Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + param.getKey() + "\""); + mpBuilder.addPart(partHeaders, RequestBody.create(parameterToString(param.getValue()), null)); + } + } + return mpBuilder.build(); + } + + /** + * Guess Content-Type header from the given file (defaults to "application/octet-stream"). + * + * @param file The given file + * @return The guessed Content-Type + */ + private String guessContentTypeFromFile(File file) { + String contentType = URLConnection.guessContentTypeFromName(file.getName()); + if (contentType == null) { + return "application/octet-stream"; + } else { + return contentType; + } + } + +} diff --git a/src/main/resources/mustache/Java/libraries/okhttp-gson/ApiResponse.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiResponse.mustache similarity index 100% rename from src/main/resources/mustache/Java/libraries/okhttp-gson/ApiResponse.mustache rename to src/main/resources/handlebars/Java/libraries/okhttp4-gson/ApiResponse.mustache diff --git a/src/main/resources/mustache/Java/libraries/okhttp-gson/GzipRequestInterceptor.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/GzipRequestInterceptor.mustache similarity index 98% rename from src/main/resources/mustache/Java/libraries/okhttp-gson/GzipRequestInterceptor.mustache rename to src/main/resources/handlebars/Java/libraries/okhttp4-gson/GzipRequestInterceptor.mustache index 23224cf5d5..27c536c21a 100644 --- a/src/main/resources/mustache/Java/libraries/okhttp-gson/GzipRequestInterceptor.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/GzipRequestInterceptor.mustache @@ -2,7 +2,7 @@ package {{invokerPackage}}; -import com.squareup.okhttp.*; +import okhttp3.*; import okio.Buffer; import okio.BufferedSink; import okio.GzipSink; diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/JSON.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/JSON.mustache new file mode 100644 index 0000000000..02b2fa04ed --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/JSON.mustache @@ -0,0 +1,528 @@ +{{>licenseInfo}} + +package {{invokerPackage}}; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import io.gsonfire.GsonFireBuilder; +import io.gsonfire.PostProcessor; +import io.gsonfire.TypeSelector; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.internal.bind.util.ISO8601Utils; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +{{#joda}} +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.DateTimeFormatterBuilder; +import org.joda.time.format.ISODateTimeFormat; +{{/joda}} +{{#threetenbp}} +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; +{{/threetenbp}} + +{{#hasModel}}import {{modelPackage}}.*;{{/hasModel}} + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +{{#java8}} +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +{{/java8}} +import java.util.Date; +import java.util.Map; +import java.util.HashMap; + +public class JSON { + private Gson gson; + private boolean isLenientOnJson = false; + private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); + private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter(); + {{#joda}} + private DateTimeTypeAdapter dateTimeTypeAdapter = new DateTimeTypeAdapter(); + private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + {{/joda}} + {{#jsr310}} + private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); + private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + {{/jsr310}} + + public static GsonBuilder createGson() { + GsonFireBuilder fireBuilder = new GsonFireBuilder() + {{#parent}} + {{#discriminator}} + .registerTypeSelector({{classname}}.class, new TypeSelector<{{classname}}>() { + @Override + public Class getClassForElement(JsonElement readElement) { + Map> classByDiscriminatorValue = new HashMap<>(); + {{#if discriminator.mapping}} + {{#each discriminator.mapping}} + classByDiscriminatorValue.put("{{@key}}".toUpperCase(), {{this}}.class); + {{/each}} + {{else}} + {{#children}} + classByDiscriminatorValue.put("{{name}}".toUpperCase(), {{classname}}.class); + {{/children}} + classByDiscriminatorValue.put("{{classname}}".toUpperCase(), {{classname}}.class); + {{/if}} + return getClassByDiscriminator( + classByDiscriminatorValue, + getDiscriminatorValue(readElement, "{{discriminator.propertyName}}")); + } + }) + .registerPostProcessor({{classname}}.class, new PostProcessor<{{classname}}>() { + @Override + public void postDeserialize({{classname}} result, JsonElement src, Gson gson) { + + } + + @Override + public void postSerialize(JsonElement result, {{classname}} src, Gson gson) { + Map, String> discriminatorValueByClass = new HashMap<>(); + {{#if discriminator.mapping}} + {{#each discriminator.mapping}} + discriminatorValueByClass.put({{this}}.class, "{{@key}}"); + {{/each}} + {{else}} + {{#children}} + discriminatorValueByClass.put({{classname}}.class, "{{name}}"); + {{/children}} + discriminatorValueByClass.put({{classname}}.class, "{{classname}}"); + {{/if}} + if(result instanceof JsonObject) + { + if(!((JsonObject) result).has("{{discriminator.propertyName}}")) + { + ((JsonObject) result).addProperty("{{discriminator.propertyName}}", discriminatorValueByClass.get(src.getClass())); + } + } + } + }) + {{/discriminator}} + {{/parent}} + ; + return fireBuilder.createGsonBuilder(); + } + + private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { + JsonElement element = readElement.getAsJsonObject().get(discriminatorField); + if(null == element) { + throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">"); + } + return element.getAsString(); + } + + private static Class getClassByDiscriminator(Map> classByDiscriminatorValue, String discriminatorValue) { + Class clazz = classByDiscriminatorValue.get(discriminatorValue.toUpperCase()); + if(null == clazz) { + throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">"); + } + return clazz; + } + + public JSON() { + gson = createGson() + .registerTypeAdapter(Date.class, dateTypeAdapter) + .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter) + {{#joda}} + .registerTypeAdapter(DateTime.class, dateTimeTypeAdapter) + .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) + {{/joda}} + {{#jsr310}} + .registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter) + .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) + {{/jsr310}} + .create(); + } + + /** + * Get Gson. + * + * @return Gson + */ + public Gson getGson() { + return gson; + } + + /** + * Set Gson. + * + * @param gson Gson + * @return JSON + */ + public JSON setGson(Gson gson) { + this.gson = gson; + return this; + } + + public JSON setLenientOnJson(boolean lenientOnJson) { + isLenientOnJson = lenientOnJson; + return this; + } + + /** + * Serialize the given Java object into JSON string. + * + * @param obj Object + * @return String representation of the JSON + */ + public String serialize(Object obj) { + return gson.toJson(obj); + } + + /** + * Deserialize the given JSON string to Java object. + * + * @param Type + * @param body The JSON string + * @param returnType The type to deserialize into + * @return The deserialized Java object + */ + @SuppressWarnings("unchecked") + public T deserialize(String body, Type returnType) { + try { + if (isLenientOnJson) { + JsonReader jsonReader = new JsonReader(new StringReader(body)); + // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean) + jsonReader.setLenient(true); + return gson.fromJson(jsonReader, returnType); + } else { + return gson.fromJson(body, returnType); + } + } catch (JsonParseException e) { + // Fallback processing when failed to parse JSON form response body: + // return the response body string directly for the String return type; + if (returnType.equals(String.class)) + return (T) body; + else throw (e); + } + } + + {{#joda}} + /** + * Gson TypeAdapter for Joda DateTime type + */ + public static class DateTimeTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public DateTimeTypeAdapter() { + this(new DateTimeFormatterBuilder() + .append(ISODateTimeFormat.dateTime().getPrinter(), ISODateTimeFormat.dateOptionalTimeParser().getParser()) + .toFormatter()); + } + + public DateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, DateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.print(date)); + } + } + + @Override + public DateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return formatter.parseDateTime(date); + } + } + } + + /** + * Gson TypeAdapter for Joda LocalDate type + */ + public class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(ISODateTimeFormat.date()); + } + + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.print(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return formatter.parseLocalDate(date); + } + } + } + + public JSON setDateTimeFormat(DateTimeFormatter dateFormat) { + dateTimeTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + return this; + } + + {{/joda}} + {{#jsr310}} + /** + * Gson TypeAdapter for JSR310 OffsetDateTime type + */ + public static class OffsetDateTimeTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public OffsetDateTimeTypeAdapter() { + this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + public OffsetDateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, OffsetDateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public OffsetDateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + if (date.endsWith("+0000")) { + date = date.substring(0, date.length()-5) + "Z"; + } + return OffsetDateTime.parse(date, formatter); + } + } + } + + /** + * Gson TypeAdapter for JSR310 LocalDate type + */ + public class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(DateTimeFormatter.ISO_LOCAL_DATE); + } + + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return LocalDate.parse(date, formatter); + } + } + } + + public JSON setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + offsetDateTimeTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + return this; + } + + {{/jsr310}} + /** + * Gson TypeAdapter for java.sql.Date type + * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used + * (more efficient than SimpleDateFormat). + */ + public static class SqlDateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public SqlDateTypeAdapter() { + } + + public SqlDateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, java.sql.Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = date.toString(); + } + out.value(value); + } + } + + @Override + public java.sql.Date read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return new java.sql.Date(dateFormat.parse(date).getTime()); + } + return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime()); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } + } + + /** + * Gson TypeAdapter for java.util.Date type + * If the dateFormat is null, ISO8601Utils will be used. + */ + public static class DateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public DateTypeAdapter() { + } + + public DateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = ISO8601Utils.format(date, true); + } + out.value(value); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + try { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return dateFormat.parse(date); + } + return ISO8601Utils.parse(date, new ParsePosition(0)); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } + } + + public JSON setDateFormat(DateFormat dateFormat) { + dateTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setSqlDateFormat(DateFormat dateFormat) { + sqlDateTypeAdapter.setFormat(dateFormat); + return this; + } + +} diff --git a/src/main/resources/mustache/Java/libraries/okhttp-gson/ProgressRequestBody.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ProgressRequestBody.mustache similarity index 95% rename from src/main/resources/mustache/Java/libraries/okhttp-gson/ProgressRequestBody.mustache rename to src/main/resources/handlebars/Java/libraries/okhttp4-gson/ProgressRequestBody.mustache index 0f15c1f415..d9ceeab12a 100644 --- a/src/main/resources/mustache/Java/libraries/okhttp-gson/ProgressRequestBody.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ProgressRequestBody.mustache @@ -2,8 +2,8 @@ package {{invokerPackage}}; -import com.squareup.okhttp.MediaType; -import com.squareup.okhttp.RequestBody; +import okhttp3.MediaType; +import okhttp3.RequestBody; import java.io.IOException; diff --git a/src/main/resources/mustache/Java/libraries/okhttp-gson/ProgressResponseBody.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ProgressResponseBody.mustache similarity index 89% rename from src/main/resources/mustache/Java/libraries/okhttp-gson/ProgressResponseBody.mustache rename to src/main/resources/handlebars/Java/libraries/okhttp4-gson/ProgressResponseBody.mustache index 3f53133697..34713eca11 100644 --- a/src/main/resources/mustache/Java/libraries/okhttp-gson/ProgressResponseBody.mustache +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/ProgressResponseBody.mustache @@ -2,8 +2,8 @@ package {{invokerPackage}}; -import com.squareup.okhttp.MediaType; -import com.squareup.okhttp.ResponseBody; +import okhttp3.MediaType; +import okhttp3.ResponseBody; import java.io.IOException; @@ -34,12 +34,12 @@ public class ProgressResponseBody extends ResponseBody { } @Override - public long contentLength() throws IOException { + public long contentLength() { return responseBody.contentLength(); } @Override - public BufferedSource source() throws IOException { + public BufferedSource source() { if (bufferedSource == null) { bufferedSource = Okio.buffer(source(responseBody.source())); } diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/api.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/api.mustache new file mode 100644 index 0000000000..4a13e61eea --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/api.mustache @@ -0,0 +1,250 @@ +{{>licenseInfo}} + +package {{package}}; + +import {{invokerPackage}}.ApiCallback; +import {{invokerPackage}}.ApiClient; +import {{invokerPackage}}.ApiException; +import {{invokerPackage}}.ApiResponse; +import {{invokerPackage}}.Configuration; +import {{invokerPackage}}.Pair; +import {{invokerPackage}}.ProgressRequestBody; +import {{invokerPackage}}.ProgressResponseBody; +{{#performBeanValidation}} +import {{invokerPackage}}.BeanValidationException; +{{/performBeanValidation}} + +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; + +{{#useBeanValidation}} +import javax.validation.constraints.*; +{{/useBeanValidation}} +{{#performBeanValidation}} +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; +import java.util.Set; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +{{/performBeanValidation}} + +{{#imports}}import {{import}}; +{{/imports}} + +import java.lang.reflect.Type; +{{^fullJavaUtil}} +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +{{/fullJavaUtil}} + +{{#operations}} +public class {{classname}} { + private ApiClient {{localVariablePrefix}}apiClient; + + public {{classname}}() { + this(Configuration.getDefaultApiClient()); + } + + public {{classname}}(ApiClient apiClient) { + this.{{localVariablePrefix}}apiClient = apiClient; + } + + public ApiClient getApiClient() { + return {{localVariablePrefix}}apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.{{localVariablePrefix}}apiClient = apiClient; + } + + {{#operation}} + {{#contents}} + /** + * Build call for {{operationId}}{{#parameters}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} + * @param progressListener Progress listener + * @param progressRequestListener Progress request listener + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + public okhttp3.Call {{operationId}}Call({{#parameters}}{{{dataType}}} {{paramName}}, {{/parameters}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + Object {{localVariablePrefix}}localVarPostBody = {{^isForm}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/isForm}}{{#isForm}}null{{/isForm}}; + + // create path and map variables + String {{localVariablePrefix}}localVarPath = "{{{path}}}"{{#pathParams}} + .replaceAll("\\{" + "{{baseName}}" + "\\}", {{localVariablePrefix}}apiClient.escapeString({{{paramName}}}.toString())){{/pathParams}}; + + {{javaUtilPrefix}}List {{localVariablePrefix}}localVarQueryParams = new {{javaUtilPrefix}}ArrayList(); + {{javaUtilPrefix}}List {{localVariablePrefix}}localVarCollectionQueryParams = new {{javaUtilPrefix}}ArrayList();{{#queryParams}} + if ({{paramName}} != null) + {{localVariablePrefix}}{{#collectionFormat}}localVarCollectionQueryParams.addAll({{localVariablePrefix}}apiClient.parameterToPairs("{{{collectionFormat}}}", {{/collectionFormat}}{{^collectionFormat}}localVarQueryParams.addAll({{localVariablePrefix}}apiClient.parameterToPair({{/collectionFormat}}"{{baseName}}", {{paramName}}));{{/queryParams}} + + {{javaUtilPrefix}}Map {{localVariablePrefix}}localVarHeaderParams = new {{javaUtilPrefix}}HashMap();{{#headerParams}} + if ({{paramName}} != null) + {{localVariablePrefix}}localVarHeaderParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}}));{{/headerParams}} + + {{javaUtilPrefix}}Map {{localVariablePrefix}}localVarFormParams = new {{javaUtilPrefix}}HashMap(); + {{#isForm}} + {{#formParams}} + if ({{paramName}} != null) + {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}}); + {{/formParams}} + {{/isForm}} + + final String[] {{localVariablePrefix}}localVarAccepts = { + {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} + }; + final String {{localVariablePrefix}}localVarAccept = {{localVariablePrefix}}apiClient.selectHeaderAccept({{localVariablePrefix}}localVarAccepts); + if ({{localVariablePrefix}}localVarAccept != null) {{localVariablePrefix}}localVarHeaderParams.put("Accept", {{localVariablePrefix}}localVarAccept); + + final String[] {{localVariablePrefix}}localVarContentTypes = { + {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} + }; + final String {{localVariablePrefix}}localVarContentType = {{localVariablePrefix}}apiClient.selectHeaderContentType({{localVariablePrefix}}localVarContentTypes); + {{localVariablePrefix}}localVarHeaderParams.put("Content-Type", {{localVariablePrefix}}localVarContentType); + + if(progressListener != null) { + {{localVariablePrefix}}apiClient.getHttpClient().networkInterceptors().add(new okhttp3.Interceptor() { + @Override + public okhttp3.Response intercept(okhttp3.Interceptor.Chain chain) throws IOException { + okhttp3.Response originalResponse = chain.proceed(chain.request()); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), progressListener)) + .build(); + } + }); + } + + String[] {{localVariablePrefix}}localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; + return {{localVariablePrefix}}apiClient.buildCall({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarCollectionQueryParams, {{localVariablePrefix}}localVarPostBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAuthNames, progressRequestListener); + } + + {{#isDeprecated}} + @Deprecated + {{/isDeprecated}} + @SuppressWarnings("rawtypes") + private okhttp3.Call {{operationId}}ValidateBeforeCall({{#parameters}}{{{dataType}}} {{paramName}}, {{/parameters}}final ProgressResponseBody.ProgressListener progressListener, final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException { + {{^performBeanValidation}} + {{#parameters}}{{#required}} + // verify the required parameter '{{paramName}}' is set + if ({{paramName}} == null) { + throw new ApiException("Missing the required parameter '{{paramName}}' when calling {{operationId}}(Async)"); + } + {{/required}}{{/parameters}} + + okhttp3.Call {{localVariablePrefix}}call = {{operationId}}Call({{#parameters}}{{paramName}}, {{/parameters}}progressListener, progressRequestListener); + return {{localVariablePrefix}}call; + + {{/performBeanValidation}} + {{#performBeanValidation}} + try { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + ExecutableValidator executableValidator = factory.getValidator().forExecutables(); + + Object[] parameterValues = { {{#parameters}}{{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}} }; + Method method = this.getClass().getMethod("{{operationId}}WithHttpInfo"{{#parameters}}, {{#is this 'list-container'}}java.util.List{{/is}}{{#is this 'map-container'}}java.util.Map{{/is}}{{#isNot this 'list-container'}}{{#isNot this 'map-container'}}{{{dataType}}}{{/isNot}}{{/isNot}}.class{{/parameters}}); + Set> violations = executableValidator.validateParameters(this, method, + parameterValues); + + if (violations.size() == 0) { + okhttp3.Call {{localVariablePrefix}}call = {{operationId}}Call({{#parameters}}{{paramName}}, {{/parameters}}progressListener, progressRequestListener); + return {{localVariablePrefix}}call; + + } else { + throw new BeanValidationException((Set) violations); + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + throw new ApiException(e.getMessage()); + } catch (SecurityException e) { + e.printStackTrace(); + throw new ApiException(e.getMessage()); + } + + {{/performBeanValidation}} + } + + /** + * {{summary}} + * {{notes}}{{#parameters}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}}{{#returnType}} + * @return {{returnType}}{{/returnType}} + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}}) throws ApiException { + {{#returnType}}ApiResponse<{{{returnType}}}> {{localVariablePrefix}}resp = {{/returnType}}{{operationId}}WithHttpInfo({{#parameters}}{{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}});{{#returnType}} + return {{localVariablePrefix}}resp.getData();{{/returnType}} + } + + /** + * {{summary}} + * {{notes}}{{#parameters}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} + * @return ApiResponse<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + public ApiResponse<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#parameters}}{{#if useBeanValidation}}{{>beanValidationQueryParams}}{{/if}}{{{dataType}}} {{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}}) throws ApiException { + okhttp3.Call {{localVariablePrefix}}call = {{operationId}}ValidateBeforeCall({{#parameters}}{{paramName}}, {{/parameters}}null, null); + {{#returnType}}Type {{localVariablePrefix}}localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); + return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call, {{localVariablePrefix}}localVarReturnType);{{/returnType}}{{^returnType}}return {{localVariablePrefix}}apiClient.execute({{localVariablePrefix}}call);{{/returnType}} + } + + /** + * {{summary}} (asynchronously) + * {{notes}}{{#parameters}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} + * @param callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + public okhttp3.Call {{operationId}}Async({{#parameters}}{{{dataType}}} {{paramName}}, {{/parameters}}final ApiCallback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{localVariablePrefix}}callback) throws ApiException { + + ProgressResponseBody.ProgressListener progressListener = null; + ProgressRequestBody.ProgressRequestListener progressRequestListener = null; + + if (callback != null) { + progressListener = new ProgressResponseBody.ProgressListener() { + @Override + public void update(long bytesRead, long contentLength, boolean done) { + callback.onDownloadProgress(bytesRead, contentLength, done); + } + }; + + progressRequestListener = new ProgressRequestBody.ProgressRequestListener() { + @Override + public void onRequestProgress(long bytesWritten, long contentLength, boolean done) { + callback.onUploadProgress(bytesWritten, contentLength, done); + } + }; + } + + okhttp3.Call {{localVariablePrefix}}call = {{operationId}}ValidateBeforeCall({{#parameters}}{{paramName}}, {{/parameters}}progressListener, progressRequestListener); + {{#returnType}}Type {{localVariablePrefix}}localVarReturnType = new TypeToken<{{{returnType}}}>(){}.getType(); + {{localVariablePrefix}}apiClient.executeAsync({{localVariablePrefix}}call, {{localVariablePrefix}}localVarReturnType, {{localVariablePrefix}}callback);{{/returnType}}{{^returnType}}{{localVariablePrefix}}apiClient.executeAsync({{localVariablePrefix}}call, {{localVariablePrefix}}callback);{{/returnType}} + return {{localVariablePrefix}}call; + } + {{/contents}} + {{/operation}} +} +{{/operations}} diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/auth/HttpBasicAuth.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/auth/HttpBasicAuth.mustache new file mode 100644 index 0000000000..6356e227a1 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/auth/HttpBasicAuth.mustache @@ -0,0 +1,43 @@ +{{>licenseInfo}} + +package {{invokerPackage}}.auth; + +import {{invokerPackage}}.Pair; + +import okhttp3.Credentials; + +import java.util.Map; +import java.util.List; + +import java.io.UnsupportedEncodingException; + +public class HttpBasicAuth implements Authentication { + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public void applyToParams(List queryParams, Map headerParams) { + if (username == null && password == null) { + return; + } + headerParams.put("Authorization", Credentials.basic( + username == null ? "" : username, + password == null ? "" : password)); + } +} diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.gradle.java11.mustache new file mode 100644 index 0000000000..80bd646b5c --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.gradle.java11.mustache @@ -0,0 +1,59 @@ +/* +* okhttp +*/ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +dependencies { + compile 'io.swagger:swagger-annotations:1.6.9' + compile 'com.squareup.okhttp:okhttp:4.10.0' + compile 'com.squareup.okhttp:logging-interceptor:4.10.0' + compile 'com.google.code.gson:gson:2.10.1' + compile 'io.gsonfire:gson-fire:1.8.5' + {{#joda}} + compile 'joda-time:joda-time:2.12.1' + {{/joda}} + {{#threetenbp}} + compile 'org.threeten:threetenbp:1.6.5' + {{/threetenbp}} + testCompile 'junit:junit:4.13.2' +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.gradle.mustache new file mode 100644 index 0000000000..eef44a829a --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.gradle.mustache @@ -0,0 +1,115 @@ +apply plugin: 'idea' +apply plugin: 'eclipse' + +group = '{{groupId}}' +version = '{{artifactVersion}}' + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.3.+' + classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' + } +} + +repositories { + jcenter() +} + + +if(hasProperty('target') && target == 'android') { + + apply plugin: 'com.android.library' + apply plugin: 'com.github.dcendents.android-maven' + + android { + compileSdkVersion 25 + buildToolsVersion '25.0.2' + defaultConfig { + minSdkVersion 14 + targetSdkVersion 25 + } + compileOptions { + {{#java8}} + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + {{/java8}} + {{^java8}} + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + {{/java8}} + } + + // Rename the aar correctly + libraryVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.aar')) { + def fileName = "${project.name}-${variant.baseName}-${version}.aar" + output.outputFile = new File(outputFile.parent, fileName) + } + } + } + + dependencies { + provided 'javax.annotation:jsr250-api:1.0' + } + } + + afterEvaluate { + android.libraryVariants.all { variant -> + def task = project.tasks.create "jar${variant.name.capitalize()}", Jar + task.description = "Create jar artifact for ${variant.name}" + task.dependsOn variant.javaCompile + task.from variant.javaCompile.destinationDir + task.destinationDir = project.file("${project.buildDir}/outputs/jar") + task.archiveName = "${project.name}-${variant.baseName}-${version}.jar" + artifacts.add('archives', task); + } + } + + task sourcesJar(type: Jar) { + from android.sourceSets.main.java.srcDirs + classifier = 'sources' + } + + artifacts { + archives sourcesJar + } + +} else { + + apply plugin: 'java' + apply plugin: 'maven' + + sourceCompatibility = JavaVersion.VERSION_{{^java8}}1_7{{/java8}}{{#java8}}1_8{{/java8}} + targetCompatibility = JavaVersion.VERSION_{{^java8}}1_7{{/java8}}{{#java8}}1_8{{/java8}} + + install { + repositories.mavenInstaller { + pom.artifactId = '{{artifactId}}' + } + } + + task execute(type:JavaExec) { + main = System.getProperty('mainClass') + classpath = sourceSets.main.runtimeClasspath + } +} + +dependencies { + compile 'io.swagger:swagger-annotations:1.6.9' + compile 'com.squareup.okhttp:okhttp:4.10.0' + compile 'com.squareup.okhttp:logging-interceptor:4.10.0' + compile 'com.google.code.gson:gson:2.10.1' + compile 'io.gsonfire:gson-fire:1.8.5' + {{#joda}} + compile 'joda-time:joda-time:2.12.1' + {{/joda}} + {{#threetenbp}} + compile 'org.threeten:threetenbp:1.6.5' + {{/threetenbp}} + testCompile 'junit:junit:4.13.2' +} diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.sbt.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.sbt.mustache new file mode 100644 index 0000000000..9a7e22cb0f --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/build.sbt.mustache @@ -0,0 +1,26 @@ +lazy val root = (project in file(".")). + settings( + organization := "{{groupId}}", + name := "{{artifactId}}", + version := "{{artifactVersion}}", + scalaVersion := "2.11.4", + scalacOptions ++= Seq("-feature"), + javacOptions in compile ++= Seq("-Xlint:deprecation"), + publishArtifact in (Compile, packageDoc) := false, + resolvers += Resolver.mavenLocal, + libraryDependencies ++= Seq( + "io.swagger" % "swagger-annotations" % "1.6.9", + "com.squareup.okhttp" % "okhttp" % "4.10.0", + "com.squareup.okhttp" % "logging-interceptor" % "4.10.0", + "com.google.code.gson" % "gson" % "2.10.1", + {{#joda}} + "joda-time" % "joda-time" % "2.12.1" % "compile", + {{/joda}} + {{#threetenbp}} + "org.threeten" % "threetenbp" % "1.6.5" % "compile", + {{/threetenbp}} + "io.gsonfire" % "gson-fire" % "1.8.5" % "compile", + "junit" % "junit" % "4.13.2" % "test", + "com.novocode" % "junit-interface" % "0.10" % "test" + ) + ) diff --git a/src/main/resources/handlebars/Java/libraries/okhttp4-gson/pom.mustache b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/pom.mustache new file mode 100644 index 0000000000..bb69b9c41f --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/okhttp4-gson/pom.mustache @@ -0,0 +1,341 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + {{artifactUrl}} + {{artifactDescription}} + + {{scmConnection}} + {{scmDeveloperConnection}} + {{scmUrl}} + + + + + {{licenseName}} + {{licenseUrl}} + repo + + + + + + {{developerName}} + {{developerEmail}} + {{developerOrganization}} + {{developerOrganizationUrl}} + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M1 + + + enforce-maven + + enforce + + + + + 2.2.0 + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + + + loggerPath + conf/log4j.properties + + + -Xms512m -Xmx1500m + methods + pertest + + + + maven-dependency-plugin + + + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + + jar + test-jar + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.10 + + + add_sources + generate-sources + + add-source + + + + + src/main/java + + + + + add_test_sources + generate-test-sources + + add-test-source + + + + + src/test/java + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + + + + + sign-artifacts + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + 2.3.3 + pom + + + + {{/java11}} + + + + {{#useOas2}} + + io.swagger + swagger-annotations + ${swagger-core-version} + + {{/useOas2}} + {{^useOas2}} + + io.swagger.core.v3 + swagger-annotations + ${swagger-core-version} + + {{/useOas2}} + + com.squareup.okhttp3 + okhttp + ${okhttp-version} + + + com.squareup.okhttp3 + logging-interceptor + ${okhttp-version} + + + com.google.code.gson + gson + ${gson-version} + + + io.gsonfire + gson-fire + ${gson-fire-version} + + {{#joda}} + + joda-time + joda-time + ${jodatime-version} + + {{/joda}} + {{#threetenbp}} + + org.threeten + threetenbp + ${threetenbp-version} + + {{/threetenbp}} + {{#useBeanValidation}} + + + javax.validation + validation-api + 2.0.1.Final + provided + + {{/useBeanValidation}} + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + 2.14.1 + + {{/notNullJacksonAnnotation}} + {{^notNullJacksonAnnotation}} + {{#ignoreUnknownJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + 2.14.1 + + {{/ignoreUnknownJacksonAnnotation}} + {{/notNullJacksonAnnotation}} + {{#performBeanValidation}} + + + org.hibernate + hibernate-validator + 8.0.0.Final + + + javax.el + el-api + 2.2 + + {{/performBeanValidation}} + {{#parcelableModel}} + + + com.google.android + android + 4.1.1.4 + provided + + {{/parcelableModel}} + + + junit + junit + ${junit-version} + test + + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} + + + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} + ${java.version} + ${java.version} + 1.8.5 + {{#useOas2}} + 1.5.15 + {{/useOas2}} + {{^useOas2}} + 2.0.0 + {{/useOas2}} + 4.10.0 + 2.10.1 + {{#joda}} + 2.12.1 + {{/joda}} + {{#threetenbp}} + 1.6.5 + {{/threetenbp}} + 1.0.0 + 4.13.2 + UTF-8 + + diff --git a/src/main/resources/handlebars/Java/libraries/resteasy/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/resteasy/ApiClient.mustache index a5929154fe..110f07e3a8 100644 --- a/src/main/resources/handlebars/Java/libraries/resteasy/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/resteasy/ApiClient.mustache @@ -8,6 +8,7 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.file.Files; +import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -22,6 +23,19 @@ import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; +{{#jakarta}} +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.Invocation; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Form; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; @@ -32,6 +46,7 @@ import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +{{/jakarta}} import org.jboss.logging.Logger; import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration; @@ -447,7 +462,7 @@ public class ApiClient { public Entity serialize(Object obj, Map formParams, String contentType) throws ApiException { Entity entity = null; if (contentType.startsWith("multipart/form-data")) { - MultipartFormDataOutput multipart = new MultipartFormDataOutput(); + MultipartFormDataOutput multipart = new MultipartFormDataOutput(); //MultiPart multiPart = new MultiPart(); for (Entry param: formParams.entrySet()) { if (param.getValue() instanceof File) { @@ -553,9 +568,9 @@ public class ApiClient { } if (tempFolderPath == null) - return File.createTempFile(prefix, suffix); + return Files.createTempFile(prefix, suffix).toFile(); else - return File.createTempFile(prefix, suffix, new File(tempFolderPath)); + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); } /** @@ -589,7 +604,7 @@ public class ApiClient { } Invocation.Builder invocationBuilder = target.request(); - + if (accept != null) { invocationBuilder = invocationBuilder.accept(accept); } diff --git a/src/main/resources/handlebars/Java/libraries/resteasy/JSON.mustache b/src/main/resources/handlebars/Java/libraries/resteasy/JSON.mustache index 27d2aa65d2..ae8f9dd597 100644 --- a/src/main/resources/handlebars/Java/libraries/resteasy/JSON.mustache +++ b/src/main/resources/handlebars/Java/libraries/resteasy/JSON.mustache @@ -11,7 +11,12 @@ import com.fasterxml.jackson.datatype.joda.*; import java.text.DateFormat; +{{#jakarta}} +import jakarta.ws.rs.ext.ContextResolver; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ContextResolver; +{{/jakarta}} {{>generatedAnnotation}} public class JSON implements ContextResolver { diff --git a/src/main/resources/handlebars/Java/libraries/resteasy/api.mustache b/src/main/resources/handlebars/Java/libraries/resteasy/api.mustache index 0016ae8779..ab1aa90ec8 100644 --- a/src/main/resources/handlebars/Java/libraries/resteasy/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/resteasy/api.mustache @@ -5,7 +5,12 @@ import {{invokerPackage}}.ApiClient; import {{invokerPackage}}.Configuration; import {{invokerPackage}}.Pair; -import javax.ws.rs.core.GenericType; +{{#jakarta}} + import jakarta.ws.rs.core.GenericType; +{{/jakarta}} +{{^jakarta}} + import javax.ws.rs.core.GenericType; +{{/jakarta}} {{#imports}}import {{import}}; {{/imports}} @@ -58,7 +63,7 @@ public class {{classname}} { @Deprecated {{/isDeprecated}} public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}{{#has this 'more'}}, {{/has}}{{/parameters}}) throws ApiException { - Object {{localVariablePrefix}}localVarPostBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + Object {{localVariablePrefix}}localVarPostBody = {{^isForm}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/isForm}}{{#isForm}}null{{/isForm}}; {{#parameters}}{{#required}} // verify the required parameter '{{paramName}}' is set if ({{paramName}} == null) { @@ -81,10 +86,11 @@ public class {{classname}} { {{#headerParams}}if ({{paramName}} != null) {{localVariablePrefix}}localVarHeaderParams.put("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); {{/headerParams}} - + {{#isForm}} {{#formParams}}if ({{paramName}} != null) {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}}); {{/formParams}} + {{/isForm}} final String[] {{localVariablePrefix}}localVarAccepts = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} diff --git a/src/main/resources/handlebars/Java/libraries/resteasy/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/resteasy/build.gradle.mustache index cb4a9f8e61..fb20d58b24 100644 --- a/src/main/resources/handlebars/Java/libraries/resteasy/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/resteasy/build.gradle.mustache @@ -54,7 +54,7 @@ if(hasProperty('target') && target == 'android') { } dependencies { - provided 'javax.annotation:jsr250-api:1.0' + provided 'jakarta.annotation:jakarta.annotation-api:{{#jakarta}}2.1.1{{/jakarta}}{{^jakarta}}1.3.5{{/jakarta}}' } } @@ -111,8 +111,8 @@ ext { {{^useOas2}} swagger_annotations_version = "2.0.0" {{/useOas2}} - jackson_version = "2.7.5" - jersey_version = "2.22.2" + jackson_version = "2.10.1" + jersey_version = "{{#jakarta}}3.1.0{{/jakarta}}{{^jakarta}}2.22.2{{/jakarta}}" {{^java8}} jodatime_version = "2.9.4" {{/java8}} diff --git a/src/main/resources/handlebars/Java/libraries/resteasy/pom.mustache b/src/main/resources/handlebars/Java/libraries/resteasy/pom.mustache index 1d60815222..9fe63eb110 100644 --- a/src/main/resources/handlebars/Java/libraries/resteasy/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/resteasy/pom.mustache @@ -113,7 +113,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 @@ -211,7 +211,7 @@ {{/supportJava6}} org.jboss.resteasy - resteasy-jackson-provider + resteasy-jackson2-provider 3.1.3.Final @@ -231,6 +231,14 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} {{#useOas2}} @@ -249,6 +257,6 @@ 3.6 {{/supportJava6}} 1.0.0 - 4.12 + 4.13.1 diff --git a/src/main/resources/handlebars/Java/libraries/resttemplate/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/resttemplate/ApiClient.mustache index 7b4cf2abad..c74ff62c8f 100644 --- a/src/main/resources/handlebars/Java/libraries/resttemplate/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/resttemplate/ApiClient.mustache @@ -91,9 +91,6 @@ public class ApiClient { private RestTemplate restTemplate; private Map authentications; - - private HttpStatus statusCode; - private MultiValueMap responseHeaders; private DateFormat dateFormat; @@ -147,22 +144,6 @@ public class ApiClient { return this; } - /** - * Gets the status code of the previous request - * @return HttpStatus the status code - */ - public HttpStatus getStatusCode() { - return statusCode; - } - - /** - * Gets the response headers of the previous request - * @return MultiValueMap a map of response headers - */ - public MultiValueMap getResponseHeaders() { - return responseHeaders; - } - /** * Get authentications (key: authentication name, value: authentication). * @return Map the currently configured authentication types @@ -518,9 +499,9 @@ public class ApiClient { * @param contentType The request's Content-Type header * @param authNames The authentications to apply * @param returnType The return type into which to deserialize the response - * @return The response body in chosen type + * @return ResponseEntity<T> The response of the chosen type */ - public T invokeAPI(String path, HttpMethod method, MultiValueMap queryParams, Object body, HttpHeaders headerParams, MultiValueMap formParams, List accept, MediaType contentType, String[] authNames, ParameterizedTypeReference returnType) throws RestClientException { + public ResponseEntity invokeAPI(String path, HttpMethod method, MultiValueMap queryParams, Object body, HttpHeaders headerParams, MultiValueMap formParams, List accept, MediaType contentType, String[] authNames, ParameterizedTypeReference returnType) throws RestClientException { updateParamsForAuth(authNames, queryParams, headerParams); final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(basePath).path(path); @@ -542,20 +523,12 @@ public class ApiClient { RequestEntity requestEntity = requestBuilder.body(selectBody(body, formParams, contentType)); ResponseEntity responseEntity = restTemplate.exchange(requestEntity, returnType); - - statusCode = responseEntity.getStatusCode(); - responseHeaders = responseEntity.getHeaders(); - if (responseEntity.getStatusCode() == HttpStatus.NO_CONTENT) { - return null; - } else if (responseEntity.getStatusCode().is2xxSuccessful()) { - if (returnType == null) { - return null; - } - return responseEntity.getBody(); + if (responseEntity.getStatusCode().is2xxSuccessful()) { + return responseEntity; } else { // The error handler built into the RestTemplate should handle 400 and 500 series errors. - throw new RestClientException("API returned " + statusCode + " and it wasn't handled by the RestTemplate error handler"); + throw new RestClientException("API returned " + responseEntity.getStatusCode() + " and it wasn't handled by the RestTemplate error handler"); } } diff --git a/src/main/resources/handlebars/Java/libraries/resttemplate/api.mustache b/src/main/resources/handlebars/Java/libraries/resttemplate/api.mustache index 7e0a91627f..c4b64f5b75 100644 --- a/src/main/resources/handlebars/Java/libraries/resttemplate/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/resttemplate/api.mustache @@ -23,6 +23,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; {{>generatedAnnotation}} @Component("{{package}}.{{classname}}") @@ -56,7 +57,7 @@ public class {{classname}} { *

{{code}}{{#message}} - {{message}}{{/message}} {{/responses}} {{#parameters}} - * @param {{paramName}} {{description}}{{^description}}The {{paramName}} parameter{{/description}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} {{/parameters}} {{#returnType}} * @return {{returnType}} @@ -67,8 +68,39 @@ public class {{classname}} { * @see {{summary}} Documentation {{/externalDocs}} */ + {{#isDeprecated}} + @Deprecated + {{/isDeprecated}} public {{#returnType}}{{{returnType}}} {{/returnType}}{{^returnType}}void {{/returnType}}{{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) throws RestClientException { - Object {{localVariablePrefix}}postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + {{#returnType}} + return {{operationId}}WithHttpInfo({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}).getBody(); + {{/returnType}} + {{^returnType}} + {{operationId}}WithHttpInfo({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); + {{/returnType}} + } + + /** + * {{summary}} + * {{notes}} + {{#responses}} + *

{{code}}{{#message}} - {{message}}{{/message}} + {{/responses}} + {{#parameters}} + * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} + {{/parameters}} + * @return ResponseEntity<{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Void{{/returnType}}> + * @throws RestClientException if an error occurs while attempting to invoke the API + {{#externalDocs}} + * {{description}} + * @see {{summary}} Documentation + {{/externalDocs}} + */ + {{#isDeprecated}} + @Deprecated + {{/isDeprecated}} + public ResponseEntity<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{operationId}}WithHttpInfo({{#parameters}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) throws RestClientException { + Object {{localVariablePrefix}}postBody = {{^isForm}}{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}{{/isForm}}{{#isForm}}null{{/isForm}}; {{#parameters}} {{#required}} // verify the required parameter '{{paramName}}' is set @@ -101,10 +133,12 @@ public class {{classname}} { {{/headerParams}} {{/hasHeaderParams}} {{#hasFormParams}} + {{#isForm}} {{#formParams}} if ({{paramName}} != null) - {{localVariablePrefix}}formParams.add("{{baseName}}", {{#is this 'file'}}new FileSystemResource({{paramName}}){{/is}}{{#isNot this 'file'}}{{paramName}}{{/isNot}}); + {{localVariablePrefix}}formParams.add("{{baseName}}", {{#is this 'binary'}}new FileSystemResource({{paramName}}){{/is}}{{#isNot this 'binary'}}{{paramName}}{{/isNot}}); {{/formParams}} + {{/isForm}} {{/hasFormParams}} final String[] {{localVariablePrefix}}accepts = { {{#hasProduces}} @@ -119,7 +153,7 @@ public class {{classname}} { String[] {{localVariablePrefix}}authNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; {{#returnType}}ParameterizedTypeReference<{{{returnType}}}> {{localVariablePrefix}}returnType = new ParameterizedTypeReference<{{{returnType}}}>() {};{{/returnType}}{{^returnType}}ParameterizedTypeReference {{localVariablePrefix}}returnType = new ParameterizedTypeReference() {};{{/returnType}} - {{#returnType}}return {{/returnType}}{{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, HttpMethod.{{httpMethod}}, {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); + return {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}path, HttpMethod.{{httpMethod}}, {{localVariablePrefix}}queryParams, {{localVariablePrefix}}postBody, {{localVariablePrefix}}headerParams, {{localVariablePrefix}}formParams, {{localVariablePrefix}}accept, {{localVariablePrefix}}contentType, {{localVariablePrefix}}authNames, {{localVariablePrefix}}returnType); } {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.java11.mustache new file mode 100644 index 0000000000..7f04f3cbdf --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.java11.mustache @@ -0,0 +1,81 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + swagger_annotations_version = "{{#useOas2}}1.5.24{{/useOas2}}{{^useOas2}}2.0.0{{/useOas2}}" + jackson_version = "2.11.4" + spring_web_version = "4.3.9.RELEASE" + jodatime_version = "2.10.5" + junit_version = "4.12" + {{#threetenbp}} + jackson_threeten_version = "2.6.4" + {{/threetenbp}} +} + +dependencies { + {{#useOas2}} + implementation "io.swagger:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + implementation "org.springframework:spring-web:$spring_web_version" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version" + implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jackson_version" + {{#joda}} + implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" + implementation "joda-time:joda-time:$jodatime_version" + {{/joda}} + {{#threetenbp}} + implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threeten_version" + {{/threetenbp}} + {{#withXml}} + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:$jackson_version" + {{/withXml}} + implementation "com.sun.xml.ws:jaxws-rt:{{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}}" + testImplementation "junit:junit:$junit_version" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.mustache index 3ccd732914..e1a4c1b3fc 100644 --- a/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/resttemplate/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } @@ -112,7 +117,7 @@ ext { {{^useOas2}} swagger_annotations_version = "2.0.0" {{/useOas2}} - jackson_version = "2.8.9" + jackson_version = "2.10.1" spring_web_version = "4.3.9.RELEASE" jodatime_version = "2.9.9" junit_version = "4.12" diff --git a/src/main/resources/handlebars/Java/libraries/resttemplate/pom.mustache b/src/main/resources/handlebars/Java/libraries/resttemplate/pom.mustache index b559516a7b..bdeb2052e5 100644 --- a/src/main/resources/handlebars/Java/libraries/resttemplate/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/resttemplate/pom.mustache @@ -133,7 +133,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -181,6 +181,22 @@ + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + {{/java11}} @@ -271,6 +287,14 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} UTF-8 @@ -289,6 +313,6 @@ 2.6.4 {{/threetenbp}} 1.0.0 - 4.12 + 4.13.1 diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/ApiClient.mustache index 24fac6a4f0..487cc233d7 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit/ApiClient.mustache @@ -54,7 +54,7 @@ public class ApiClient { this(); for(String authName : authNames) { {{#hasAuthMethods}} - Interceptor auth; + Interceptor auth = null; {{#authMethods}}if ("{{name}}".equals(authName)) { {{#is this 'basic'}} auth = new HttpBasicAuth(); @@ -62,7 +62,7 @@ public class ApiClient { {{#is this 'api-key'}} auth = new ApiKeyAuth({{#is this 'key-in-header'}}"header"{{/is}}{{#isNot this 'key-in-header'}}"query"{{/isNot}}, "{{keyParamName}}");{{/is}} {{#is this 'oauth'}} - auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{scope}}{{#hasMore}}, {{/hasMore}}{{/scopes}}"); + auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#each scopes}}{{@key}}{{^@last}}, {{/@last}}{{/each}}"); {{/is}} } else {{/authMethods}}{ throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/api.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/api.mustache index 9311b59835..67b4a37f5f 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit/api.mustache @@ -46,7 +46,7 @@ public interface {{classname}} { {{/formParams}} @{{httpMethod}}("{{{path}}}") {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}} {{operationId}}({{^parameters}});{{/parameters}} - {{#parameters}}{{>libraries/retrofit/queryParams}}{{>libraries/retrofit/pathParams}}{{>libraries/retrofit/headerParams}}{{>libraries/retrofit/bodyParams}}{{>libraries/retrofit/formParams}}{{#has this 'more'}}, {{/has}}{{#hasNot this 'more'}} + {{#parameters}}{{>libraries/retrofit/queryParams}}{{>libraries/retrofit/pathParams}}{{>libraries/retrofit/headerParams}}{{>libraries/retrofit/bodyParams}}{{>libraries/retrofit/formParams}}{{>libraries/retrofit/cookieParams}}{{#has this 'more'}}, {{/has}}{{#hasNot this 'more'}} );{{/hasNot}}{{/parameters}} /** @@ -73,7 +73,7 @@ public interface {{classname}} { {{/formParams}} @{{httpMethod}}("{{{path}}}") void {{operationId}}( - {{#parameters}}{{>libraries/retrofit/queryParams}}{{>libraries/retrofit/pathParams}}{{>libraries/retrofit/headerParams}}{{>libraries/retrofit/bodyParams}}{{>libraries/retrofit/formParams}}, {{/parameters}}Callback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> cb + {{#parameters}}{{>libraries/retrofit/queryParams}}{{>libraries/retrofit/pathParams}}{{>libraries/retrofit/headerParams}}{{>libraries/retrofit/bodyParams}}{{>libraries/retrofit/formParams}}{{>libraries/retrofit/cookieParams}}, {{/parameters}}Callback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> cb ); {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/api_test.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/api_test.mustache index ac191b73e4..34e47634d4 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit/api_test.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit/api_test.mustache @@ -6,6 +6,13 @@ import {{invokerPackage}}.ApiClient; import org.junit.Before; import org.junit.Test; +{{#wiremock}} +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.net.HttpURLConnection; +import org.junit.AfterClass; +{{/wiremock}} + {{^fullJavaUtil}} import java.util.ArrayList; import java.util.HashMap; @@ -13,6 +20,10 @@ import java.util.List; import java.util.Map; {{/fullJavaUtil}} +{{#wiremock}} +import static com.github.tomakehurst.wiremock.client.WireMock.*; +{{/wiremock}} + /** * API tests for {{classname}} */ @@ -20,10 +31,36 @@ public class {{classname}}Test { private {{classname}} api; + {{#wiremock}} + private static WireMockServer wireMockServer; + + @Before + public void setup() { + wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort()); + wireMockServer.start(); + configureFor(wireMockServer.port()); + ApiClient apiClient = new ApiClient(); + apiClient.getAdapterBuilder().setEndpoint("http://localhost:" + wireMockServer.port()); + api = apiClient.createService({{classname}}.class); + + {{#operations}}{{#operation}} + stubFor({{toLowerCase httpMethod}}(urlPathMatching("{{{path}}}")) + .willReturn(aResponse() + .withStatus(HttpURLConnection.HTTP_OK))); + {{/operation}}{{/operations}} + } + + @AfterClass + public static void tearDown() { + wireMockServer.stop(); + } + {{/wiremock}} + {{^wiremock}} @Before public void setup() { api = new ApiClient().createService({{classname}}.class); } + {{/wiremock}} {{#operations}}{{#operation}}{{#contents}}{{#@first}} /** diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.java11.mustache new file mode 100644 index 0000000000..69654df15c --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.java11.mustache @@ -0,0 +1,71 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + okhttp_version = "2.7.5" + oltu_version = "1.0.2" + retrofit_version = "1.9.0" + swagger_annotations_version = "{{#useOas2}}1.5.24{{/useOas2}}{{^useOas2}}2.0.0{{/useOas2}}" + junit_version = "4.13.1" + jodatime_version = "2.10.5" +} + +dependencies { + implementation "com.squareup.okhttp:okhttp:$okhttp_version" + implementation "com.squareup.retrofit:retrofit:$retrofit_version" + {{#useOas2}} + implementation "io.swagger:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + implementation("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version") { + exclude group: 'org.json', module: 'json' + } + implementation "org.json:json:20180130" + implementation "joda-time:joda-time:$jodatime_version" + implementation "com.sun.xml.ws:jaxws-rt:{{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}}" + testImplementation "junit:junit:$junit_version" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.mustache index 0473350b52..058b2cdfb9 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } @@ -122,7 +127,10 @@ dependencies { {{^useOas2}} compile "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" {{/useOas2}} - compile "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" + compile ("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version") { + exclude group: "org.json", module: "json" + } + compile "org.json:json:20180130" compile "joda-time:joda-time:$jodatime_version" testCompile "junit:junit:$junit_version" } diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/cookieParams.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/cookieParams.mustache new file mode 100644 index 0000000000..cdb1e2289f --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/retrofit/cookieParams.mustache @@ -0,0 +1 @@ +{{~#is this 'cookie-param'}}{{{dataType}}} {{paramName}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/formParams.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/formParams.mustache index 0bc9ea5159..0bfdce65cd 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit/formParams.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit/formParams.mustache @@ -1 +1 @@ -{{~#is this 'form-param'}}{{#isNot this 'file'}}{{#is ../this 'multipart'}}@retrofit.http.Part{{/is}}{{#isNot ../this 'multipart'}}@retrofit.http.Field{{/isNot}}("{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}}{{#is ../this 'multipart'}}@retrofit.http.Part{{/is}}{{#isNot ../this 'multipart'}}@retrofit.http.Field{{/isNot}}("{{baseName}}") TypedFile {{paramName}}{{/is}}{{/is}} \ No newline at end of file +{{~#is this 'form-param'}}{{#isNot this 'binary'}}{{#is ../this 'multipart'}}@retrofit.http.Part{{/is}}{{#isNot ../this 'multipart'}}@retrofit.http.Field{{/isNot}}("{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}}{{#is ../this 'multipart'}}@retrofit.http.Part{{/is}}{{#isNot ../this 'multipart'}}@retrofit.http.Field{{/isNot}}("{{baseName}}") TypedFile {{paramName}}{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/retrofit/pom.mustache b/src/main/resources/handlebars/Java/libraries/retrofit/pom.mustache index 82c3f531d6..c099b11501 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit/pom.mustache @@ -126,7 +126,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -174,6 +174,22 @@ + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + {{/java11}} @@ -229,6 +245,14 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} {{#useOas2}} @@ -242,6 +266,6 @@ 2.9.9 1.0.2 1.0.0 - 4.12 + 4.13.1 diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/ApiClient.mustache index 8e81e572cd..64b2648585 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/ApiClient.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/ApiClient.mustache @@ -23,6 +23,9 @@ import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; {{#useRxJava2}} import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; {{/useRxJava2}} +{{#useRxJava3}} +import hu.akarnokd.rxjava3.retrofit.RxJava3CallAdapterFactory; +{{/useRxJava3}} import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; import {{invokerPackage}}.auth.HttpBasicAuth; @@ -58,7 +61,7 @@ public class ApiClient { this(); for(String authName : authNames) { {{#hasAuthMethods}} - Interceptor auth; + Interceptor auth = null; {{#authMethods}}if ("{{name}}".equals(authName)) { {{#is this 'basic'}} auth = new HttpBasicAuth(); @@ -67,7 +70,7 @@ public class ApiClient { auth = new ApiKeyAuth({{#is this 'key-in-header'}}"header"{{/is}}{{#isNot this 'key-in-header'}}"query"{{/isNot}}, "{{keyParamName}}"); {{/is}} {{#is this 'oauth'}} - auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{scope}}{{#hasMore}}, {{/hasMore}}{{/scopes}}"); + auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#each scopes}}{{@key}}{{^@last}}, {{/@last}}{{/each}}"); {{/is}} } else {{/authMethods}}{ throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); @@ -142,7 +145,9 @@ public class ApiClient { .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) {{/useRxJava}}{{#useRxJava2}} .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - {{/useRxJava2}} + {{/useRxJava2}}{{#useRxJava3}} + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + {{/useRxJava3}} .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonCustomConverterFactory.create(json.getGson())); } diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/api.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/api.mustache index 311bfe501d..2d9dfc3517 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/api.mustache @@ -8,6 +8,9 @@ import rx.Observable; {{#useRxJava2}} import io.reactivex.Observable; {{/useRxJava2}} +{{#useRxJava3}} +import io.reactivex.rxjava3.core.Observable; +{{/useRxJava3}} {{#doNotUseRx}} import retrofit2.Call; {{/doNotUseRx}} @@ -58,7 +61,7 @@ public interface {{classname}} { {{/formParams}} @{{httpMethod}}("{{{path}}}") {{^doNotUseRx}}Observable{{/doNotUseRx}}{{#doNotUseRx}}Call{{/doNotUseRx}}<{{#isResponseFile}}ResponseBody{{/isResponseFile}}{{^isResponseFile}}{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}{{/isResponseFile}}> {{operationId}}({{^parameters}});{{/parameters}} - {{#parameters}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{#has this 'more'}}, {{/has}}{{#hasNot this 'more'}} + {{#parameters}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{>libraries/retrofit2/cookieParams}}{{#has this 'more'}}, {{/has}}{{#hasNot this 'more'}} );{{/hasNot}}{{/parameters}} {{/contents}} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/api_test.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/api_test.mustache index 7c4e8e21ce..ed169f5614 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/api_test.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/api_test.mustache @@ -6,6 +6,13 @@ import {{invokerPackage}}.ApiClient; import org.junit.Before; import org.junit.Test; +{{#wiremock}} +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.net.HttpURLConnection; +import org.junit.AfterClass; +{{/wiremock}} + {{^fullJavaUtil}} import java.util.ArrayList; import java.util.HashMap; @@ -13,6 +20,10 @@ import java.util.List; import java.util.Map; {{/fullJavaUtil}} +{{#wiremock}} +import static com.github.tomakehurst.wiremock.client.WireMock.*; +{{/wiremock}} + /** * API tests for {{classname}} */ @@ -20,10 +31,36 @@ public class {{classname}}Test { private {{classname}} api; + {{#wiremock}} + private static WireMockServer wireMockServer; + + @Before + public void setup() { + wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort()); + wireMockServer.start(); + configureFor(wireMockServer.port()); + ApiClient apiClient = new ApiClient(); + apiClient.getAdapterBuilder().setEndpoint("http://localhost:" + wireMockServer.port()); + api = apiClient.createService({{classname}}.class); + + {{#operations}}{{#operation}} + stubFor({{toLowerCase httpMethod}}(urlPathMatching("{{{path}}}")) + .willReturn(aResponse() + .withStatus(HttpURLConnection.HTTP_OK))); + {{/operation}}{{/operations}} + } + + @AfterClass + public static void tearDown() { + wireMockServer.stop(); + } + {{/wiremock}} + {{^wiremock}} @Before public void setup() { api = new ApiClient().createService({{classname}}.class); } + {{/wiremock}} {{#operations}} {{#operation}} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.java11.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.java11.mustache new file mode 100644 index 0000000000..cc2368e844 --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.java11.mustache @@ -0,0 +1,116 @@ +plugins { + id 'java' + id 'maven-publish' +} + +repositories { + mavenLocal() + maven { + url = uri('https://repo.maven.apache.org/maven2/') + } +} + +ext { + oltu_version = "1.0.2" + retrofit_version = "2.7.1" + {{#usePlayWS}} + {{#play24}} + jackson_version = "2.11.4" + play_version = "2.4.11" + {{/play24}} + {{#play25}} + jackson_version = "2.11.4" + play_version = "2.5.14" + {{/play25}} + {{/usePlayWS}} + swagger_annotations_version = "{{#useOas2}}1.5.24{{/useOas2}}{{^useOas2}}2.0.0{{/useOas2}}" + junit_version = "4.12" + {{#useRxJava}} + rx_java_version = "1.3.0" + {{/useRxJava}} + {{#useRxJava2}} + rx_java_version = "2.1.1" + {{/useRxJava2}} + {{#joda}} + jodatime_version = "2.10.5" + {{/joda}} + {{#threetenbp}} + threetenbp_version = "1.4.1" + {{/threetenbp}} + json_fire_version = "1.8.3" +} + +dependencies { + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version" + implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" + {{#useRxJava}} + implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version" + implementation "io.reactivex:rxjava:$rx_java_version" + {{/useRxJava}} + {{#useRxJava2}} + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' + implementation "io.reactivex.rxjava2:rxjava:$rx_java_version" + {{/useRxJava2}} + {{#useOas2}} + implementation "io.swagger:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + {{^useOas2}} + implementation "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" + {{/useOas2}} + implementation ("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version"){ + exclude group:'org.apache.oltu.oauth2' , module: 'org.apache.oltu.oauth2.common' + exclude group: 'org.json', module: 'json' + } + implementation "org.json:json:20180130" + implementation "io.gsonfire:gson-fire:$json_fire_version" + {{#joda}} + implementation "joda-time:joda-time:$jodatime_version" + {{/joda}} + {{#threetenbp}} + implementation "org.threeten:threetenbp:$threetenbp_version" + {{/threetenbp}} + {{#usePlayWS}} + implementation "com.typesafe.play:play-java-ws_2.11:$play_version" + implementation "com.squareup.retrofit2:converter-jackson:$retrofit_version" + implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version" + implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" + {{/usePlayWS}} + implementation "com.sun.xml.ws:jaxws-rt:{{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}}" + {{#wiremock}} + testImplementation "com.github.tomakehurst:wiremock:2.27.2" + {{/wiremock}} + + testImplementation "junit:junit:$junit_version" +} + +group = '{{groupId}}' +version = '{{artifactVersion}}' +description = '{{artifactDescription}}' + +java.sourceCompatibility = 11 +java.targetCompatibility = 11 + +tasks.register('testsJar', Jar) { + archiveClassifier = 'tests' + from(sourceSets.test.output) +} + +java { + withSourcesJar() + withJavadocJar() +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + artifact(testsJar) + } + } +} + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.mustache index 523bf65124..c5fa3a8cff 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/build.gradle.mustache @@ -54,7 +54,12 @@ if(hasProperty('target') && target == 'android') { } dependencies { + {{#jakarta}} + provided 'jakarta.annotation:jakarta.annotation-api:2.1.1' + {{/jakarta}} + {{^jakarta}} provided 'javax.annotation:jsr250-api:1.0' + {{/jakarta}} } } @@ -104,13 +109,12 @@ ext { retrofit_version = "2.3.0" {{#usePlayWS}} {{#play24}} - jackson_version = "2.6.6" play_version = "2.4.11" {{/play24}} {{#play25}} - jackson_version = "2.7.8" play_version = "2.5.14" {{/play25}} + jackson_version = "2.10.1" {{/usePlayWS}} {{#useOas2}} swagger_annotations_version = "1.5.15" @@ -152,7 +156,10 @@ dependencies { {{^useOas2}} compile "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" {{/useOas2}} - compile "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" + compile ("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version") { + exclude group: "org.json", module: "json" + } + compile "org.json:json:20180130" compile "io.gsonfire:gson-fire:$json_fire_version" {{#joda}} compile "joda-time:joda-time:$jodatime_version" diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/cookieParams.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/cookieParams.mustache new file mode 100644 index 0000000000..cdb1e2289f --- /dev/null +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/cookieParams.mustache @@ -0,0 +1 @@ +{{~#is this 'cookie-param'}}{{{dataType}}} {{paramName}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/formParams.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/formParams.mustache index b141e939b2..0b58db0b40 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/formParams.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/formParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{#is this 'multipart'}}@retrofit2.http.Part{{/is}}{{#isNot this 'multipart'}}@retrofit2.http.Field{{/isNot}}("{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}}{{#is this 'multipart'}}@retrofit2.http.Part{{/is}}{{#isNot this 'multipart'}}@retrofit2.http.Field{{/isNot}}{{#usePlayWS}} okhttp3.MultipartBody.Part {{/usePlayWS}}{{^usePlayWS}}("{{baseName}}\"; filename=\"{{baseName}}") RequestBody {{/usePlayWS}}{{paramName}}{{/is}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}{{#is this 'multipart'}}@retrofit2.http.Part{{/is}}{{#isNot this 'multipart'}}@retrofit2.http.Field{{/isNot}}("{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}}{{#is this 'multipart'}}@retrofit2.http.Part{{/is}}{{#isNot this 'multipart'}}@retrofit2.http.Field{{/isNot}}{{#usePlayWS}} okhttp3.MultipartBody.Part {{/usePlayWS}}{{^usePlayWS}}("{{baseName}}\"; filename=\"{{baseName}}") RequestBody {{/usePlayWS}}{{paramName}}{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/play24/api.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/play24/api.mustache index 487822ee24..2f968ee56c 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/play24/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/play24/api.mustache @@ -50,7 +50,7 @@ public interface {{classname}} { {{/formParams}} @{{httpMethod}}("{{{path}}}") F.Promise> {{operationId}}({{^parameters}});{{/parameters}} - {{#parameters}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}} + {{#parameters}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{>libraries/retrofit2/cookieParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}} );{{/hasMore}}{{/parameters}} {{/contents}} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/play25/api.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/play25/api.mustache index 7ca1f27cb4..0e61b74cc6 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/play25/api.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/play25/api.mustache @@ -50,7 +50,7 @@ public interface {{classname}} { {{/formParams}} @{{httpMethod}}("{{{path}}}") CompletionStage> {{operationId}}({{^parameters}});{{/parameters}} - {{#parameters}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}} + {{#parameters}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{>libraries/retrofit2/cookieParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}} );{{/hasMore}}{{/parameters}} {{/contents}} diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/pom.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/pom.mustache index 34c74a6107..3404e55b5b 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/pom.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/pom.mustache @@ -118,7 +118,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -166,6 +166,22 @@ + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + {{/java11}} @@ -246,6 +262,18 @@ ${retrofit-version} {{/useRxJava2}} + {{#useRxJava3}} + + io.reactivex.rxjava3 + rxjava + ${rxjava-version} + + + com.github.akarnokd + rxjava3-retrofit-adapter + 3.0.0 + + {{/useRxJava3}} {{#usePlayWS}} @@ -308,10 +336,18 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} UTF-8 - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} 1.8.0 @@ -345,6 +381,6 @@ 1.3.5 {{/threetenbp}} 1.0.2 - 4.12 + 4.13.1 diff --git a/src/main/resources/handlebars/Java/libraries/retrofit2/queryParams.mustache b/src/main/resources/handlebars/Java/libraries/retrofit2/queryParams.mustache index e0dff7f9ef..f624114ff4 100644 --- a/src/main/resources/handlebars/Java/libraries/retrofit2/queryParams.mustache +++ b/src/main/resources/handlebars/Java/libraries/retrofit2/queryParams.mustache @@ -1 +1 @@ -{{#is this 'query-param'}}@retrofit2.http.Query("{{baseName}}") {{{dataType}}} {{paramName}}{{/is}} +{{#is this 'query-param'}}@retrofit2.http.Query("{{baseName}}") {{{dataType}}} {{paramName}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/vertx/ApiClient.mustache b/src/main/resources/handlebars/Java/libraries/vertx/ApiClient.mustache deleted file mode 100644 index 0f35af0ac9..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/ApiClient.mustache +++ /dev/null @@ -1,601 +0,0 @@ -package {{invokerPackage}}; - -import {{invokerPackage}}.auth.Authentication; -import {{invokerPackage}}.auth.HttpBasicAuth; -import {{invokerPackage}}.auth.ApiKeyAuth; -import {{invokerPackage}}.auth.OAuth; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import io.vertx.core.*; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.file.AsyncFile; -import io.vertx.core.file.FileSystem; -import io.vertx.core.file.OpenOptions; -import io.vertx.core.http.HttpHeaders; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.client.HttpRequest; -import io.vertx.ext.web.client.HttpResponse; -import io.vertx.ext.web.client.WebClient; -import io.vertx.ext.web.client.WebClientOptions; - -import java.text.DateFormat; -import java.util.*; -import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static java.util.stream.Collectors.toMap; - -{{>generatedAnnotation}} -public class ApiClient { - - private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); - private static final OpenOptions FILE_DOWNLOAD_OPTIONS = new OpenOptions().setCreate(true).setTruncateExisting(true); - - private final Vertx vertx; - private final JsonObject config; - private final String identifier; - - private MultiMap defaultHeaders = MultiMap.caseInsensitiveMultiMap(); - private Map authentications; - private String basePath = "{{{basePath}}}"; - private DateFormat dateFormat; - private ObjectMapper objectMapper; - private String downloadsDir = ""; - - public ApiClient(Vertx vertx, JsonObject config) { - Objects.requireNonNull(vertx, "Vertx must not be null"); - Objects.requireNonNull(config, "Config must not be null"); - - this.vertx = vertx; - - // Use RFC3339 format for date and datetime. - // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 - this.dateFormat = new RFC3339DateFormat(); - - // Use UTC as the default time zone. - this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - - // Build object mapper - this.objectMapper = new ObjectMapper(); - this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - this.objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false); - this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - this.objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); - this.objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); - this.objectMapper.registerModule(new JavaTimeModule()); - this.objectMapper.setDateFormat(dateFormat); - - // Setup authentications (key: authentication name, value: authentication). - this.authentications = new HashMap<>();{{#authMethods}}{{#is this 'basic'}} - authentications.put("{{name}}", new HttpBasicAuth());{{/is}}{{#is this 'api-key'}} - authentications.put("{{name}}", new ApiKeyAuth({{#is this 'key-in-header'}}"header"{{/is}}{{#isNot this 'key-in-header'}}"query"{{/isNot}}, "{{keyParamName}}"));{{/is}}{{#is this 'oauth'}} - authentications.put("{{name}}", new OAuth());{{/is}}{{#is this 'bearer'}} - authentications.put("{{name}}", new OAuth());{{/is}}{{/authMethods}} - // Prevent the authentications from being modified. - this.authentications = Collections.unmodifiableMap(authentications); - - // Configurations - this.basePath = config.getString("basePath", this.basePath); - this.downloadsDir = config.getString("downloadsDir", this.downloadsDir); - this.config = config; - this.identifier = UUID.randomUUID().toString(); - } - - public Vertx getVertx() { - return vertx; - } - - public ObjectMapper getObjectMapper() { - return objectMapper; - } - - public ApiClient setObjectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - return this; - } - - public synchronized WebClient getWebClient() { - String webClientIdentifier = "web-client-" + identifier; - WebClient webClient = Vertx.currentContext().get(webClientIdentifier); - if (webClient == null) { - webClient = buildWebClient(vertx, config); - Vertx.currentContext().put(webClientIdentifier, webClient); - } - return webClient; - } - - public String getBasePath() { - return basePath; - } - - public ApiClient setBasePath(String basePath) { - this.basePath = basePath; - return this; - } - - public String getDownloadsDir() { - return downloadsDir; - } - - public ApiClient setDownloadsDir(String downloadsDir) { - this.downloadsDir = downloadsDir; - return this; - } - - public MultiMap getDefaultHeaders() { - return defaultHeaders; - } - - public ApiClient addDefaultHeader(String key, String value) { - defaultHeaders.add(key, value); - return this; - } - - /** - * Get authentications (key: authentication name, value: authentication). - * - * @return Map of authentication object - */ - public Map getAuthentications() { - return authentications; - } - - /** - * Get authentication for the given name. - * - * @param authName The authentication name - * @return The authentication, null if not found - */ - public Authentication getAuthentication(String authName) { - return authentications.get(authName); - } - - /** - * Helper method to set username for the first HTTP basic authentication. - * - * @param username Username - */ - public ApiClient setUsername(String username) { - for (Authentication auth : authentications.values()) { - if (auth instanceof HttpBasicAuth) { - ((HttpBasicAuth) auth).setUsername(username); - return this; - } - } - throw new RuntimeException("No HTTP basic authentication configured!"); - } - - /** - * Helper method to set password for the first HTTP basic authentication. - * - * @param password Password - */ - public ApiClient setPassword(String password) { - for (Authentication auth : authentications.values()) { - if (auth instanceof HttpBasicAuth) { - ((HttpBasicAuth) auth).setPassword(password); - return this; - } - } - throw new RuntimeException("No HTTP basic authentication configured!"); - } - - /** - * Helper method to set API key value for the first API key authentication. - * - * @param apiKey API key - */ - public ApiClient setApiKey(String apiKey) { - for (Authentication auth : authentications.values()) { - if (auth instanceof ApiKeyAuth) { - ((ApiKeyAuth) auth).setApiKey(apiKey); - return this; - } - } - throw new RuntimeException("No API key authentication configured!"); - } - - /** - * Helper method to set API key prefix for the first API key authentication. - * - * @param apiKeyPrefix API key prefix - */ - public ApiClient setApiKeyPrefix(String apiKeyPrefix) { - for (Authentication auth : authentications.values()) { - if (auth instanceof ApiKeyAuth) { - ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); - return this; - } - } - throw new RuntimeException("No API key authentication configured!"); - } - - /** - * Helper method to set access token for the first OAuth2 authentication. - * - * @param accessToken Access token - */ - public ApiClient setAccessToken(String accessToken) { - for (Authentication auth : authentications.values()) { - if (auth instanceof OAuth) { - ((OAuth) auth).setAccessToken(accessToken); - return this; - } - } - throw new RuntimeException("No OAuth2 authentication configured!"); - } - - /** - * Format the given Date object into string. - * - * @param date Date - * @return Date in string format - */ - public String formatDate(Date date) { - return dateFormat.format(date); - } - - /** - * Format the given parameter object into string. - * - * @param param Object - * @return Object in string format - */ - public String parameterToString(Object param) { - if (param == null) { - return ""; - } else if (param instanceof Date) { - return formatDate((Date) param); - } else if (param instanceof Collection) { - StringBuilder b = new StringBuilder(); - for (Object o : (Collection) param) { - if (b.length() > 0) { - b.append(','); - } - b.append(String.valueOf(o)); - } - return b.toString(); - } else { - return String.valueOf(param); - } - } - - /* - * Format to {@code Pair} objects. - * @param collectionFormat Collection format - * @param name Name - * @param value Value - * @return List of pairs - */ - public List parameterToPairs(String collectionFormat, String name, Object value) { - List params = new ArrayList(); - - // preconditions - if (name == null || name.isEmpty() || value == null) return params; - - Collection valueCollection; - if (value instanceof Collection) { - valueCollection = (Collection) value; - } else { - params.add(new Pair(name, parameterToString(value))); - return params; - } - - if (valueCollection.isEmpty()) { - return params; - } - - // get the collection format (default: csv) - String format = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat); - - // create the params based on the collection format - if ("multi".equals(format)) { - for (Object item : valueCollection) { - params.add(new Pair(name, parameterToString(item))); - } - return params; - } - - String delimiter = ","; - if ("csv".equals(format)) { - delimiter = ","; - } else if ("ssv".equals(format)) { - delimiter = " "; - } else if ("tsv".equals(format)) { - delimiter = "\t"; - } else if ("pipes".equals(format)) { - delimiter = "|"; - } - - StringBuilder sb = new StringBuilder(); - for (Object item : valueCollection) { - sb.append(delimiter); - sb.append(parameterToString(item)); - } - - params.add(new Pair(name, sb.substring(1))); - - return params; - } - - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * - * @param mime MIME - * @return True if the MIME type is JSON - */ - private boolean isJsonMime(String mime) { - String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; - return mime != null && (mime.matches(jsonMime) || mime.equalsIgnoreCase("application/json-patch+json")); - } - - /** - * Select the Accept header's value from the given accepts array: - * if JSON exists in the given array, use it; - * otherwise use all of them (joining into a string) - * - * @param accepts The accepts array to select from - * @return The Accept header to use. If the given array is empty, - * null will be returned (not to set the Accept header explicitly). - */ - protected String selectHeaderAccept(String[] accepts) { - if (accepts.length == 0) { - return null; - } - for (String accept : accepts) { - if (isJsonMime(accept)) { - return accept; - } - } - return StringUtil.join(accepts, ","); - } - - /** - * Select the Content-Type header's value from the given array: - * if JSON exists in the given array, use it; - * otherwise use the first one of the array. - * - * @param contentTypes The Content-Type array to select from - * @return The Content-Type header to use. If the given array is empty, - * JSON will be used. - */ - protected String selectHeaderContentType(String[] contentTypes) { - if (contentTypes.length == 0) { - return "application/json"; - } - for (String contentType : contentTypes) { - if (isJsonMime(contentType)) { - return contentType; - } - } - return contentTypes[0]; - } - - public void sendBody(HttpRequest request, - Handler>> responseHandler, - Object body) { - if (body instanceof byte[]) { - Buffer buffer = Buffer.buffer((byte[]) body); - request.sendBuffer(buffer, responseHandler); - } else if (body instanceof AsyncFile) { - AsyncFile file = (AsyncFile) body; - request.sendStream(file, responseHandler); - } else { - request.sendJson(body, responseHandler); - } - } - - /** - * Invoke API by sending HTTP request with the given options. - * - * @param Type - * @param path The sub-path of the HTTP URL - * @param method The request method, one of "GET", "POST", "PUT", "HEAD" and "DELETE" - * @param queryParams The query parameters - * @param body The request body object - * @param headerParams The header parameters - * @param formParams The form parameters - * @param accepts The request's Accept headers - * @param contentTypes The request's Content-Type headers - * @param authNames The authentications to apply - * @param returnType The return type into which to deserialize the response - * @param resultHandler The asynchronous response handler - */ - public void invokeAPI(String path, String method, List queryParams, Object body, MultiMap headerParams, - Map formParams, String[] accepts, String[] contentTypes, String[] authNames, - TypeReference returnType, Handler> resultHandler) { - - updateParamsForAuth(authNames, queryParams, headerParams); - - if (accepts != null) { - headerParams.add(HttpHeaders.ACCEPT, selectHeaderAccept(accepts)); - } - - if (contentTypes != null) { - headerParams.add(HttpHeaders.CONTENT_TYPE, selectHeaderContentType(contentTypes)); - } - - HttpMethod httpMethod = HttpMethod.valueOf(method); - HttpRequest request = getWebClient().requestAbs(httpMethod, basePath + path); - - if (httpMethod == HttpMethod.PATCH) { - request.putHeader("X-HTTP-Method-Override", "PATCH"); - } - - queryParams.forEach(entry -> { - if (entry.getValue() != null) { - request.addQueryParam(entry.getName(), entry.getValue()); - } - }); - - headerParams.forEach(entry -> { - if (entry.getValue() != null) { - request.putHeader(entry.getKey(), entry.getValue()); - } - }); - - defaultHeaders.forEach(entry -> { - if (entry.getValue() != null) { - request.putHeader(entry.getKey(), entry.getValue()); - } - }); - - Handler>> responseHandler = buildResponseHandler(returnType, resultHandler); - if (body != null) { - sendBody(request, responseHandler, body); - } else if (formParams != null && !formParams.isEmpty()) { - Map formMap = formParams.entrySet().stream().collect(toMap(Map.Entry::getKey, entry -> parameterToString(entry.getValue()))); - MultiMap form = MultiMap.caseInsensitiveMultiMap().addAll(formMap); - request.sendForm(form, responseHandler); - } else { - request.send(responseHandler); - } - } - - /** - * Sanitize filename by removing path. - * e.g. ../../sun.gif becomes sun.gif - * - * @param filename The filename to be sanitized - * @return The sanitized filename - */ - protected String sanitizeFilename(String filename) { - return filename.replaceAll(".*[/\\\\]", ""); - } - - /** - * Create a filename from the given headers. - * When the headers have no "Content-Disposition" information, a random UUID name is generated. - * - * @param headers The HTTP response headers - * @return The filename - */ - protected String generateFilename(MultiMap headers) { - String filename = UUID.randomUUID().toString(); - String contentDisposition = headers.get("Content-Disposition"); - if (contentDisposition != null && !contentDisposition.isEmpty()) { - Matcher matcher = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition); - if (matcher.find()) { - filename = sanitizeFilename(matcher.group(1)); - } - } - return filename; - } - - /** - * File Download handling. - * - * @param response The HTTP response - * @param handler The response handler - */ - protected void handleFileDownload(HttpResponse response, Handler> handler) { - FileSystem fs = getVertx().fileSystem(); - - String filename = generateFilename(response.headers()); - Consumer fileHandler = directory -> { - fs.open(directory + filename, FILE_DOWNLOAD_OPTIONS, asyncFileResult -> { - if (asyncFileResult.succeeded()) { - AsyncFile asyncFile = asyncFileResult.result(); - asyncFile.write(response.bodyAsBuffer()); - //noinspection unchecked - handler.handle(Future.succeededFuture((T) asyncFile)); - } else { - handler.handle(ApiException.fail(asyncFileResult.cause())); - } - }); - }; - - String dir = getDownloadsDir(); - if (dir != null && !dir.isEmpty()) { - fs.mkdirs(dir, mkdirResult -> { - String sanitizedFolder = dir.endsWith("/") ? dir : dir + "/"; - fileHandler.accept(sanitizedFolder); - }); - } else { - fileHandler.accept(""); - } - } - - /** - * Build a response handler for the HttpResponse. - * - * @param returnType The return type - * @param handler The response handler - * @return The HTTP response handler - */ - protected Handler>> buildResponseHandler(TypeReference returnType, - Handler> handler) { - return response -> { - AsyncResult result; - if (response.succeeded()) { - HttpResponse httpResponse = response.result(); - if (httpResponse.statusCode() / 100 == 2) { - if (httpResponse.statusCode() == 204 || returnType == null) { - result = Future.succeededFuture(null); - } else { - T resultContent; - if ("byte[]".equals(returnType.getType().toString())) { - resultContent = (T) httpResponse.body().getBytes(); - } else if (AsyncFile.class.equals(returnType.getType())) { - handleFileDownload(httpResponse, handler); - return; - } else { - resultContent = Json.decodeValue(httpResponse.body(), returnType); - } - result = Future.succeededFuture(resultContent); - } - } else { - result = ApiException.fail(httpResponse.statusMessage(), httpResponse.statusCode(), httpResponse.headers(), httpResponse.bodyAsString()); - } - } else if (response.cause() instanceof ApiException) { - result = Future.failedFuture(response.cause()); - } else { - result = ApiException.fail(500, response.cause() != null ? response.cause().getMessage() : null); - } - handler.handle(result); - }; - } - - /** - * Build the WebClient used to make HTTP requests. - * - * @param vertx Vertx - * @return WebClient - */ - protected WebClient buildWebClient(Vertx vertx, JsonObject config) { - - if (!config.containsKey("userAgent")) { - config.put("userAgent", "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{artifactVersion}}}/java{{/httpUserAgent}}"); - } - - return WebClient.create(vertx, new WebClientOptions(config)); - } - - - /** - * Update query and header parameters based on authentication settings. - * - * @param authNames The authentications to apply - */ - protected void updateParamsForAuth(String[] authNames, List queryParams, MultiMap headerParams) { - for (String authName : authNames) { - Authentication auth = authentications.get(authName); - if (auth == null) throw new RuntimeException("Authentication undefined: " + authName); - auth.applyToParams(queryParams, headerParams); - } - } -} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/vertx/Configuration.mustache b/src/main/resources/handlebars/Java/libraries/vertx/Configuration.mustache deleted file mode 100644 index 17710ae160..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/Configuration.mustache +++ /dev/null @@ -1,42 +0,0 @@ -package {{invokerPackage}}; - -import io.vertx.core.Vertx; -import io.vertx.core.json.JsonObject; - -import java.util.Objects; - -public class Configuration { - - private static ApiClient defaultApiClient = null; - - /** - * Setup the default API client. - * Will be used by API instances when a client is not provided. - * - * @return Default API client - */ - public synchronized static ApiClient setupDefaultApiClient(Vertx vertx, JsonObject config) { - defaultApiClient = new ApiClient(vertx, config); - return defaultApiClient; - } - - /** - * Get the default API client, which would be used when creating API - * instances without providing an API client. - * - * @return Default API client - */ - public synchronized static ApiClient getDefaultApiClient() { - return defaultApiClient; - } - - /** - * Set the default API client, which would be used when creating API - * instances without providing an API client. - * - * @param apiClient API client - */ - public synchronized static void setDefaultApiClient(ApiClient apiClient) { - defaultApiClient = apiClient; - } -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/api.mustache b/src/main/resources/handlebars/Java/libraries/vertx/api.mustache deleted file mode 100644 index 6ba9fb46ce..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/api.mustache +++ /dev/null @@ -1,21 +0,0 @@ -package {{package}}; - -{{#imports}}import {{import}}; -{{/imports}} -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.json.JsonObject; - -import java.util.*; - -public interface {{classname}} { - - {{#operations}} - {{#operation}} - {{#contents}} - void {{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}, {{/parameters}}Handler> handler); - - {{/contents}} - {{/operation}} - {{/operations}} -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/apiException.mustache b/src/main/resources/handlebars/Java/libraries/vertx/apiException.mustache deleted file mode 100644 index 6e9bbdbb88..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/apiException.mustache +++ /dev/null @@ -1,110 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Future; -import io.vertx.core.MultiMap; - -{{>generatedAnnotation}} -public class ApiException extends{{#useRuntimeException}} RuntimeException {{/useRuntimeException}}{{^useRuntimeException}} Exception {{/useRuntimeException}}{ - private int code = 0; - private MultiMap responseHeaders = null; - private String responseBody = null; - - - public static AsyncResult fail(int failureCode, String message) { - return Future.failedFuture(new ApiException(failureCode, message)); - } - - public static AsyncResult fail(Throwable throwable) { - return Future.failedFuture(new ApiException(throwable)); - } - - public static AsyncResult fail(String message) { - return Future.failedFuture(new ApiException(message)); - } - - public static AsyncResult fail(String message, Throwable throwable, int code, MultiMap responseHeaders) { - return Future.failedFuture(new ApiException(message, throwable, code, responseHeaders, null)); - } - - public static AsyncResult fail(String message, Throwable throwable, int code, MultiMap responseHeaders, String responseBody) { - return Future.failedFuture(new ApiException(message, throwable, code, responseHeaders, responseBody)); - } - - public static AsyncResult fail(String message, int code, MultiMap responseHeaders, String responseBody) { - return Future.failedFuture(new ApiException(message, (Throwable) null, code, responseHeaders, responseBody)); - } - - public static AsyncResult fail(int code, MultiMap responseHeaders, String responseBody) { - return Future.failedFuture(new ApiException((String) null, (Throwable) null, code, responseHeaders, responseBody)); - } - - public ApiException() {} - - public ApiException(Throwable throwable) { - super(throwable); - } - - public ApiException(String message) { - super(message); - } - - public ApiException(String message, Throwable throwable, int code, MultiMap responseHeaders, String responseBody) { - super(message, throwable); - this.code = code; - this.responseHeaders = responseHeaders; - this.responseBody = responseBody; - } - - public ApiException(String message, int code, MultiMap responseHeaders, String responseBody) { - this(message, (Throwable) null, code, responseHeaders, responseBody); - } - - public ApiException(String message, Throwable throwable, int code, MultiMap responseHeaders) { - this(message, throwable, code, responseHeaders, null); - } - - public ApiException(int code, MultiMap responseHeaders, String responseBody) { - this((String) null, (Throwable) null, code, responseHeaders, responseBody); - } - - public ApiException(int code, String message) { - super(message); - this.code = code; - } - - public ApiException(int code, String message, MultiMap responseHeaders, String responseBody) { - this(code, message); - this.responseHeaders = responseHeaders; - this.responseBody = responseBody; - } - - /** - * Get the HTTP status code. - * - * @return HTTP status code - */ - public int getCode() { - return code; - } - - /** - * Get the HTTP response headers. - * - * @return A map of list of string - */ - public MultiMap getResponseHeaders() { - return responseHeaders; - } - - /** - * Get the HTTP response body. - * - * @return Response body in the form of string - */ - public String getResponseBody() { - return responseBody; - } -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/apiImpl.mustache b/src/main/resources/handlebars/Java/libraries/vertx/apiImpl.mustache deleted file mode 100644 index d458a3d260..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/apiImpl.mustache +++ /dev/null @@ -1,93 +0,0 @@ -package {{package}}; - -{{#imports}}import {{import}}; -{{/imports}} - -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.MultiMap; -import io.vertx.core.json.JsonObject; - -import com.fasterxml.jackson.core.type.TypeReference; - -import java.util.*; - -import {{invokerPackage}}.ApiClient; -import {{invokerPackage}}.ApiException; -import {{invokerPackage}}.Configuration; -import {{invokerPackage}}.Pair; - -{{>generatedAnnotation}} -{{#operations}} -public class {{classname}}Impl implements {{classname}} { - - private ApiClient {{localVariablePrefix}}apiClient; - - public {{classname}}Impl() { - this(null); - } - - public {{classname}}Impl(ApiClient apiClient) { - this.{{localVariablePrefix}}apiClient = apiClient != null ? apiClient : Configuration.getDefaultApiClient(); - } - - public ApiClient getApiClient() { - return {{localVariablePrefix}}apiClient; - } - - public void setApiClient(ApiClient apiClient) { - this.{{localVariablePrefix}}apiClient = apiClient; - } - - {{#operation}} - {{#contents}} - /** - * {{summary}} - * {{notes}} - {{#parameters}} - * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - * @param resultHandler Asynchronous result handler - */ - public void {{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}, {{/parameters}}Handler> resultHandler) { - Object {{localVariablePrefix}}localVarBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; - {{#parameters}}{{#required}} - // verify the required parameter '{{paramName}}' is set - if ({{paramName}} == null) { - resultHandler.handle(ApiException.fail(400, "Missing the required parameter '{{paramName}}' when calling {{operationId}}")); - return; - } - {{/required}}{{/parameters}} - // create path and map variables - String {{localVariablePrefix}}localVarPath = "{{{path}}}"{{#pathParams}}.replaceAll("\\{" + "{{baseName}}" + "\\}", {{{paramName}}}.toString()){{/pathParams}}; - - // query params - List {{localVariablePrefix}}localVarQueryParams = new ArrayList<>(); - {{#queryParams}} - {{localVariablePrefix}}localVarQueryParams.addAll({{localVariablePrefix}}apiClient.parameterToPairs("{{#collectionFormat}}{{{collectionFormat}}}{{/collectionFormat}}", "{{baseName}}", {{paramName}})); - {{/queryParams}} - - // header params - MultiMap {{localVariablePrefix}}localVarHeaderParams = MultiMap.caseInsensitiveMultiMap(); - {{#headerParams}}if ({{paramName}} != null) - {{localVariablePrefix}}localVarHeaderParams.add("{{baseName}}", {{localVariablePrefix}}apiClient.parameterToString({{paramName}})); - {{/headerParams}} - - // form params - // TODO: sending files within multipart/form-data is not supported yet (because of vertx web-client) - Map {{localVariablePrefix}}localVarFormParams = new HashMap<>(); - {{#formParams}}if ({{paramName}} != null) {{localVariablePrefix}}localVarFormParams.put("{{baseName}}", {{paramName}}); - {{/formParams}} - - String[] {{localVariablePrefix}}localVarAccepts = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }; - String[] {{localVariablePrefix}}localVarContentTypes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }; - String[] {{localVariablePrefix}}localVarAuthNames = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; - {{#returnType}} - TypeReference<{{{returnType}}}> {{localVariablePrefix}}localVarReturnType = new TypeReference<{{{returnType}}}>() {}; - {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccepts, {{localVariablePrefix}}localVarContentTypes, {{localVariablePrefix}}localVarAuthNames, {{localVariablePrefix}}localVarReturnType, resultHandler);{{/returnType}}{{^returnType}} - {{localVariablePrefix}}apiClient.invokeAPI({{localVariablePrefix}}localVarPath, "{{httpMethod}}", {{localVariablePrefix}}localVarQueryParams, {{localVariablePrefix}}localVarBody, {{localVariablePrefix}}localVarHeaderParams, {{localVariablePrefix}}localVarFormParams, {{localVariablePrefix}}localVarAccepts, {{localVariablePrefix}}localVarContentTypes, {{localVariablePrefix}}localVarAuthNames, null, resultHandler);{{/returnType}} - } - {{/contents}} - {{/operation}} -} -{{/operations}} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/api_test.mustache b/src/main/resources/handlebars/Java/libraries/vertx/api_test.mustache deleted file mode 100644 index 9aab4d3fdc..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/api_test.mustache +++ /dev/null @@ -1,70 +0,0 @@ -{{>licenseInfo}} -package {{package}}; - -{{#imports}}import {{import}}; -{{/imports}} - -import {{invokerPackage}}.Configuration; - -import org.junit.Test; -import org.junit.Ignore; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.runner.RunWith; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; -import io.vertx.core.json.JsonObject; -import io.vertx.core.Vertx; -import io.vertx.ext.unit.junit.VertxUnitRunner; -import io.vertx.ext.unit.junit.RunTestOnContext; -import io.vertx.ext.unit.TestContext; -import io.vertx.ext.unit.Async; - -{{^fullJavaUtil}} -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -{{/fullJavaUtil}} - -/** - * API tests for {{classname}} - */ -@RunWith(VertxUnitRunner.class) -@Ignore -public class {{classname}}Test { - - private {{classname}} api; - - @Rule - public RunTestOnContext rule = new RunTestOnContext(); - - @BeforeClass - public void setupApiClient() { - JsonObject config = new JsonObject(); - Vertx vertx = rule.vertx(); - Configuration.setupDefaultApiClient(vertx, config); - - api = new {{classname}}Impl(); - } - {{#operations}}{{#operation}}{{#contents}}{{#@first}} - /** - * {{summary}} - * {{notes}} - * - * @param context Vertx test context for doing assertions - */ - @Test - public void {{operationId}}Test(TestContext context) { - Async async = context.async(); - {{#parameters}} - {{{dataType}}} {{paramName}} = null; - {{/parameters}} - api.{{operationId}}({{#parameters}}{{paramName}}, {{/parameters}}result -> { - // TODO: test validations - async.complete(); - }); - } - {{/@first}}{{/contents}}{{/operation}}{{/operations}} -} \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/libraries/vertx/auth/ApiKeyAuth.mustache b/src/main/resources/handlebars/Java/libraries/vertx/auth/ApiKeyAuth.mustache deleted file mode 100644 index 43b1866e46..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/auth/ApiKeyAuth.mustache +++ /dev/null @@ -1,64 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.auth; - -import {{invokerPackage}}.Pair; -import io.vertx.core.MultiMap; - -import java.util.List; - -{{>generatedAnnotation}} -public class ApiKeyAuth implements Authentication { - private final String location; - private final String paramName; - - private String apiKey; - private String apiKeyPrefix; - - public ApiKeyAuth(String location, String paramName) { - this.location = location; - this.paramName = paramName; - } - - public String getLocation() { - return location; - } - - public String getParamName() { - return paramName; - } - - public String getApiKey() { - return apiKey; - } - - public void setApiKey(String apiKey) { - this.apiKey = apiKey; - } - - public String getApiKeyPrefix() { - return apiKeyPrefix; - } - - public void setApiKeyPrefix(String apiKeyPrefix) { - this.apiKeyPrefix = apiKeyPrefix; - } - - @Override - public void applyToParams(List queryParams, MultiMap headerParams) { - if (apiKey == null) { - return; - } - String value; - if (apiKeyPrefix != null) { - value = apiKeyPrefix + " " + apiKey; - } else { - value = apiKey; - } - if ("query".equals(location)) { - queryParams.add(new Pair(paramName, value)); - } else if ("header".equals(location)) { - headerParams.add(paramName, value); - } - } -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/auth/Authentication.mustache b/src/main/resources/handlebars/Java/libraries/vertx/auth/Authentication.mustache deleted file mode 100644 index 5dccb93f2a..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/auth/Authentication.mustache +++ /dev/null @@ -1,18 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.auth; - -import {{invokerPackage}}.Pair; -import io.vertx.core.MultiMap; - -import java.util.List; - -public interface Authentication { - /** - * Apply authentication settings to header and query params. - * - * @param queryParams List of query parameters - * @param headerParams Map of header parameters - */ - void applyToParams(List queryParams, MultiMap headerParams); -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/auth/HttpBasicAuth.mustache b/src/main/resources/handlebars/Java/libraries/vertx/auth/HttpBasicAuth.mustache deleted file mode 100644 index 43862b508b..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/auth/HttpBasicAuth.mustache +++ /dev/null @@ -1,40 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.auth; - -import {{invokerPackage}}.Pair; -import io.vertx.core.MultiMap; -import java.util.Base64; -import java.nio.charset.StandardCharsets; -import java.util.List; - -{{>generatedAnnotation}} -public class HttpBasicAuth implements Authentication { - private String username; - private String password; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public void applyToParams(List queryParams, MultiMap headerParams) { - if (username == null && password == null) { - return; - } - String str = (username == null ? "" : username) + ":" + (password == null ? "" : password); - headerParams.add("Authorization", "Basic " + Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8))); - } -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/auth/OAuth.mustache b/src/main/resources/handlebars/Java/libraries/vertx/auth/OAuth.mustache deleted file mode 100644 index f3c5b34ee1..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/auth/OAuth.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.auth; - -import {{invokerPackage}}.Pair; -import io.vertx.core.MultiMap; - -import java.util.List; - -{{>generatedAnnotation}} -public class OAuth implements Authentication { - private String accessToken; - - public String getAccessToken() { - return accessToken; - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - @Override - public void applyToParams(List queryParams, MultiMap headerParams) { - if (accessToken != null) { - headerParams.add("Authorization", "Bearer " + accessToken); - } - } -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/auth/OAuthFlow.mustache b/src/main/resources/handlebars/Java/libraries/vertx/auth/OAuthFlow.mustache deleted file mode 100644 index 002e9572f3..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/auth/OAuthFlow.mustache +++ /dev/null @@ -1,7 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.auth; - -public enum OAuthFlow { - accessCode, implicit, password, application -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/build.gradle.mustache b/src/main/resources/handlebars/Java/libraries/vertx/build.gradle.mustache deleted file mode 100644 index 99a1532270..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/build.gradle.mustache +++ /dev/null @@ -1,63 +0,0 @@ -apply plugin: 'idea' -apply plugin: 'eclipse' - -group = '{{groupId}}' -version = '{{artifactVersion}}' - -repositories { - jcenter() -} - -apply plugin: 'java' -apply plugin: 'maven' - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - -install { - repositories.mavenInstaller { - pom.artifactId = '{{artifactId}}' - } -} - -task execute(type:JavaExec) { - main = System.getProperty('mainClass') - classpath = sourceSets.main.runtimeClasspath -} - -ext { - {{#useOas2}} - swagger_annotations_version = "1.5.15" - {{/useOas2}} - {{^useOas2}} - swagger_annotations_version = "2.0.0" - {{/useOas2}} - jackson_version = "{{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}}" - vertx_version = "3.4.2" - junit_version = "4.12" -} - -dependencies { - {{#useOas2}} - compile "io.swagger:swagger-annotations:$swagger_annotations_version" - {{/useOas2}} - {{^useOas2}} - compile "io.swagger.core.v3:swagger-annotations:$swagger_annotations_version" - {{/useOas2}} - compile "io.vertx:vertx-web-client:$vertx_version" - compile "io.vertx:vertx-rx-java:$vertx_version" - compile "com.fasterxml.jackson.core:jackson-core:$jackson_version" - compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" - compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - {{#joda}} - compile "com.fasterxml.jackson.datatype:jackson-datatype-joda:$jackson_version" - {{/joda}} - {{#java8}} - compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version" - {{/java8}} - {{#threetenbp}} - compile "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_version" - {{/threetenbp}} - testCompile "junit:junit:$junit_version" - testCompile "io.vertx:vertx-unit:$vertx_version" -} diff --git a/src/main/resources/handlebars/Java/libraries/vertx/pom.mustache b/src/main/resources/handlebars/Java/libraries/vertx/pom.mustache deleted file mode 100644 index 16bebfd374..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/pom.mustache +++ /dev/null @@ -1,273 +0,0 @@ - - 4.0.0 - {{groupId}} - {{artifactId}} - jar - {{artifactId}} - {{artifactVersion}} - {{artifactUrl}} - {{artifactDescription}} - - {{scmConnection}} - {{scmDeveloperConnection}} - {{scmUrl}} - - - 2.2.0 - - - - - {{licenseName}} - {{licenseUrl}} - repo - - - - - - {{developerName}} - {{developerEmail}} - {{developerOrganization}} - {{developerOrganizationUrl}} - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.12 - - - - loggerPath - conf/log4j.properties - - - -Xms512m -Xmx1500m - methods - pertest - - - - maven-dependency-plugin - - - package - - copy-dependencies - - - ${project.build.directory}/lib - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - - jar - test-jar - - - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 3.0.0 - - - add_sources - generate-sources - - add-source - - - - src/main/java - - - - - add_test_sources - generate-test-sources - - add-test-source - - - - src/test/java - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.4 - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - attach-sources - - jar-no-fork - - - - - - - - - - sign-artifacts - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - sign-artifacts - verify - - sign - - - - - - - - - - - {{#useOas2}} - - io.swagger - swagger-annotations - ${swagger-core-version} - - {{/useOas2}} - {{^useOas2}} - - io.swagger.core.v3 - swagger-annotations - ${swagger-core-version} - - {{/useOas2}} - - - - io.vertx - vertx-rx-java - ${vertx-version} - - - io.vertx - vertx-web-client - ${vertx-version} - - - - - com.fasterxml.jackson.core - jackson-core - ${jackson-version} - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson-version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson-version} - - {{#joda}} - - com.fasterxml.jackson.datatype - jackson-datatype-joda - ${jackson-version} - - {{/joda}} - {{#java8}} - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson-version} - - {{/java8}} - {{#threetenbp}} - - com.github.joschi.jackson - jackson-datatype-threetenbp - ${jackson-version} - - {{/threetenbp}} - - - - junit - junit - ${junit-version} - test - - - io.vertx - vertx-unit - ${vertx-version} - test - - - - - UTF-8 - 3.4.2 - {{#useOas2}} - 1.5.16 - {{/useOas2}} - {{^useOas2}} - 2.0.0 - {{/useOas2}} - {{^threetenbp}}2.8.9{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}} - 4.12 - - diff --git a/src/main/resources/handlebars/Java/libraries/vertx/rxApiImpl.mustache b/src/main/resources/handlebars/Java/libraries/vertx/rxApiImpl.mustache deleted file mode 100644 index eeadbb77ac..0000000000 --- a/src/main/resources/handlebars/Java/libraries/vertx/rxApiImpl.mustache +++ /dev/null @@ -1,60 +0,0 @@ -package {{package}}.rxjava; - -{{#imports}}import {{import}}; -{{/imports}} - -import java.util.*; - -import rx.Single; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; - -{{>generatedAnnotation}} -{{#operations}} -public class {{classname}} { - - private final {{package}}.{{classname}} delegate; - - public {{classname}}({{package}}.{{classname}} delegate) { - this.delegate = delegate; - } - - public {{package}}.{{classname}} getDelegate() { - return delegate; - } - - {{#operation}} - {{#contents}} - /** - * {{summary}} - * {{notes}} - {{#parameters}} - * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - * @param resultHandler Asynchronous result handler - */ - public void {{operationId}}({{#parameters}}{{{dataType}}} {{paramName}}, {{/parameters}}Handler> resultHandler) { - delegate.{{operationId}}({{#parameters}}{{paramName}}, {{/parameters}}resultHandler); - } - - /** - * {{summary}} - * {{notes}} - {{#parameters}} - * @param {{paramName}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - * @return Asynchronous result handler (RxJava Single) - */ - public Single<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> rx{{operationIdCamelCase}}({{#parameters}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { - return Single.create(new io.vertx.rx.java.SingleOnSubscribeAdapter<>(fut -> { - delegate.{{operationId}}({{#parameters}}{{paramName}}, {{/parameters}}fut); - })); - } - {{/contents}} - {{/operation}} - - public static {{classname}} newInstance({{package}}.{{classname}} arg) { - return arg != null ? new {{classname}}(arg) : null; - } -} -{{/operations}} diff --git a/src/main/resources/handlebars/Java/model.mustache b/src/main/resources/handlebars/Java/model.mustache index 92bc301dbe..adc112c5d2 100644 --- a/src/main/resources/handlebars/Java/model.mustache +++ b/src/main/resources/handlebars/Java/model.mustache @@ -29,17 +29,23 @@ import android.os.Parcelable; import android.os.Parcel; {{/parcelableModel}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +import jakarta.validation.Valid; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; import javax.validation.Valid; +{{/jakarta}} {{/useBeanValidation}} {{/x-is-composed-model}} {{#models}} {{#model}} -{{#vendorExtensions.x-is-composed-model}} +{{#isComposedModel}} {{>interface}} -{{/vendorExtensions.x-is-composed-model}} -{{^vendorExtensions.x-is-composed-model}} +{{/isComposedModel}} +{{^isComposedModel}} {{#is this 'enum'}}{{>modelEnum}}{{/is}}{{#isNot this 'enum'}}{{>pojo}}{{/isNot}} -{{/vendorExtensions.x-is-composed-model}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/Java/modelEnum.mustache b/src/main/resources/handlebars/Java/modelEnum.mustache index 7b35804057..dd9906dc75 100644 --- a/src/main/resources/handlebars/Java/modelEnum.mustache +++ b/src/main/resources/handlebars/Java/modelEnum.mustache @@ -19,7 +19,12 @@ import com.google.gson.stream.JsonWriter; public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} + {{#gson}} + {{#value}} + @SerializedName({{{toQuotedWord value}}}) + {{/value}} + {{/gson}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -44,27 +49,27 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum {{#jackson}} @JsonCreator {{/jackson}} - public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue(String text) { + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} input) { for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { - if (String.valueOf(b.value).equals(text)) { + if (b.value.equals(input)) { return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } -{{#if gson}} +{{#gson}} public static class Adapter extends TypeAdapter<{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}> { @Override public void write(final JsonWriter jsonWriter, final {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} enumeration) throws IOException { - jsonWriter.value(enumeration.getValue()); + jsonWriter.value(String.valueOf(enumeration.getValue())); } @Override public {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException { - {{{dataType}}} value = jsonReader.{{#is this 'integer'}}nextInt(){{/is}}{{#isNot this 'integer'}}next{{{dataType}}}(){{/isNot}}; - return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.fromValue(String.valueOf(value)); + Object value = {{#isNumber}}new BigDecimal(jsonReader.nextDouble()){{/isNumber}}{{^isNumber}}jsonReader.{{#isInteger}}nextInt(){{/isInteger}}{{^isInteger}}nextString(){{/isInteger}}{{/isNumber}}; + return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.fromValue(({{{dataType}}})(value)); } } -{{/if}} +{{/gson}} } diff --git a/src/main/resources/handlebars/Java/modelInnerEnum.mustache b/src/main/resources/handlebars/Java/modelInnerEnum.mustache index cac0382d1d..7144835581 100644 --- a/src/main/resources/handlebars/Java/modelInnerEnum.mustache +++ b/src/main/resources/handlebars/Java/modelInnerEnum.mustache @@ -5,7 +5,12 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} + {{#gson}} + {{#value}} + @SerializedName({{{toQuotedWord value}}}) + {{/value}} + {{/gson}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -28,25 +33,25 @@ {{#jackson}} @JsonCreator {{/jackson}} - public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue(String text) { + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{datatype}}} input) { for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { - if (String.valueOf(b.value).equals(text)) { + if (b.value.equals(input)) { return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } {{#gson}} public static class Adapter extends TypeAdapter<{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}> { @Override public void write(final JsonWriter jsonWriter, final {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} enumeration) throws IOException { - jsonWriter.value(enumeration.getValue()); + jsonWriter.value(String.valueOf(enumeration.getValue())); } @Override public {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} read(final JsonReader jsonReader) throws IOException { - {{{datatype}}} value = jsonReader.{{#is ../this 'integer'}}nextInt(){{/is}}{{#isNot ../this 'integer'}}next{{{datatype}}}(){{/isNot}}; - return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.fromValue(String.valueOf(value)); + Object value = {{#isNumber}}new BigDecimal(jsonReader.nextDouble()){{/isNumber}}{{^isNumber}}jsonReader.{{#isInteger}}nextInt(){{/isInteger}}{{^isInteger}}nextString(){{/isInteger}}{{/isNumber}}; + return {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}.fromValue(({{{datatype}}})(value)); } }{{/gson}} } \ No newline at end of file diff --git a/src/main/resources/handlebars/Java/pojo.mustache b/src/main/resources/handlebars/Java/pojo.mustache index 9d3e09fa53..135b6e6b8f 100644 --- a/src/main/resources/handlebars/Java/pojo.mustache +++ b/src/main/resources/handlebars/Java/pojo.mustache @@ -3,37 +3,38 @@ */ {{#description}}{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description = "{{{description}}}"){{/description}} {{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} +{{#notNullJacksonAnnotation}} +@JsonInclude(JsonInclude.Include.NON_NULL) +{{/notNullJacksonAnnotation}} -public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcelableModel}}implements Parcelable {{#serializableModel}}, Serializable {{/serializableModel}}{{#interfaceModels}}, {{name}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/parcelableModel}}{{^parcelableModel}}{{#serializableModel}}implements Serializable{{#interfaceModels}}, {{name}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}} {{name}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{/parcelableModel}}{ +public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcelableModel}}implements Parcelable {{#serializableModel}}, Serializable {{/serializableModel}}{{#interfaceModels}}{{#@first}}, {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/parcelableModel}}{{^parcelableModel}}{{#serializableModel}}implements Serializable{{#interfaceModels}}{{#@first}}, {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{/parcelableModel}}{ {{#serializableModel}} private static final long serialVersionUID = 1L; {{/serializableModel}} {{#vars}} + {{#baseItems this}} {{#isEnum}} - {{^isContainer}} {{>modelInnerEnum}} - {{/isContainer}} {{/isEnum}} - {{#items.isEnum}} - {{#items}} - {{^isContainer}} -{{>modelInnerEnum}} - {{/isContainer}} - {{/items}} - {{/items.isEnum}} + {{/baseItems}} {{#jackson}} + {{#vendorExtensions.x-is-discriminator-property}} + @JsonTypeId + {{/vendorExtensions.x-is-discriminator-property}} + {{^vendorExtensions.x-is-discriminator-property}} @JsonProperty("{{baseName}}") - {{#withXml}} - {{^isContainer}} + {{#withXml}} + {{^isContainer}} @JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}") - {{/isContainer}} - {{#isContainer}} - {{#isXmlWrapped}} + {{/isContainer}} + {{#isContainer}} + {{#isXmlWrapped}} // items.xmlName={{items.xmlName}} @JacksonXmlElementWrapper(useWrapping = {{isXmlWrapped}}, {{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#items.xmlName}}{{items.xmlName}}{{/items.xmlName}}{{^items.xmlName}}{{items.baseName}}{{/items.xmlName}}") - {{/isXmlWrapped}} - {{/isContainer}} - {{/withXml}} + {{/isXmlWrapped}} + {{/isContainer}} + {{/withXml}} + {{/vendorExtensions.x-is-discriminator-property}} {{/jackson}} {{#withXml}} {{#isXmlAttribute}} @@ -167,7 +168,7 @@ public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcela return false; }{{#hasVars}} {{classname}} {{classVarName}} = ({{classname}}) o; - return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{#isBinary}}Arrays{{/isBinary}}{{^isByteArray}}{{^isBinary}}Objects{{/isBinary}}{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{#hasMore}} && + return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{#isBinary}}Objects{{/isBinary}}{{^isByteArray}}{{^isBinary}}Objects{{/isBinary}}{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{#hasMore}} && {{/hasMore}}{{/vars}}{{#parent}} && super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}} return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};{{/hasVars}} @@ -175,7 +176,7 @@ public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcela @Override public int hashCode() { - return Objects.hash({{#vars}}{{^isByteArray}}{{^isBinary}}{{name}}{{/isBinary}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{#isBinary}}Arrays.hashCode({{name}}){{/isBinary}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}); + return Objects.hash({{#vars}}{{^isByteArray}}{{^isBinary}}{{name}}{{/isBinary}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{#isBinary}}Objects.hashCode({{name}}){{/isBinary}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}); } {{/supportJava6}} @@ -243,7 +244,9 @@ public class {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{{#parcela {{classname}}(Parcel in) { {{#isArrayModel}} +{{^vendorExtensions.x-array-model-type-is-interface}} in.readTypedList(this, {{arrayModelType}}.CREATOR); +{{/vendorExtensions.x-array-model-type-is-interface}} {{/isArrayModel}} {{^isArrayModel}} {{#parent}} diff --git a/src/main/resources/handlebars/Java/pom.mustache b/src/main/resources/handlebars/Java/pom.mustache index 16433d4506..db48e3bab1 100644 --- a/src/main/resources/handlebars/Java/pom.mustache +++ b/src/main/resources/handlebars/Java/pom.mustache @@ -133,7 +133,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 attach-javadocs @@ -181,6 +181,22 @@ + {{#java11}} + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + {{/java11}} @@ -285,12 +301,22 @@ {{/supportJava6}} {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} {{#parcelableModel}} @@ -308,6 +334,14 @@ ${junit-version} test + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} UTF-8 @@ -322,8 +356,8 @@ 2.5 3.6 {{/supportJava6}} - {{^threetenbp}}2.7.5{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}} + {{^threetenbp}}2.10.1{{/threetenbp}}{{#threetenbp}}2.6.4{{/threetenbp}} 1.0.0 - 4.12 + 4.13.1 diff --git a/src/main/resources/handlebars/JavaInflector/api.mustache b/src/main/resources/handlebars/JavaInflector/api.mustache index 055ef574eb..48101979ba 100644 --- a/src/main/resources/handlebars/JavaInflector/api.mustache +++ b/src/main/resources/handlebars/JavaInflector/api.mustache @@ -2,7 +2,12 @@ package {{invokerPackage}}; import io.swagger.oas.inflector.models.RequestContext; import io.swagger.oas.inflector.models.ResponseContext; +{{#jakarta}} +import jakarta.ws.rs.core.Response.Status; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response.Status; +{{/jakarta}} import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import java.io.File; diff --git a/src/main/resources/handlebars/JavaInflector/enumClass.mustache b/src/main/resources/handlebars/JavaInflector/enumClass.mustache index 5d3ac5173a..5321f3ddec 100644 --- a/src/main/resources/handlebars/JavaInflector/enumClass.mustache +++ b/src/main/resources/handlebars/JavaInflector/enumClass.mustache @@ -14,7 +14,7 @@ {{#unless gson}} {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -39,6 +39,6 @@ return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaInflector/enumOuterClass.mustache b/src/main/resources/handlebars/JavaInflector/enumOuterClass.mustache index e06df3c9f7..3645cc6724 100644 --- a/src/main/resources/handlebars/JavaInflector/enumOuterClass.mustache +++ b/src/main/resources/handlebars/JavaInflector/enumOuterClass.mustache @@ -9,7 +9,7 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum {{#if gson}} {{#if allowableValues}}{{#if allowableValues.enumVars}} @SerializedName({{#is this 'integer'}}"{{/is}}{{#is this 'double'}}"{{/is}}{{#is this 'long'}}"{{/is}}{{#is this 'float'}}"{{/is}}{{{value}}}{{#is this 'integer'}}"{{/is}}{{#is this 'double'}}"{{/is}}{{#is this 'long'}}"{{/is}}{{#is this 'float'}}"{{/is}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}} {{/if}} {{/if}} @@ -42,6 +42,6 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaInflector/formParams.mustache b/src/main/resources/handlebars/JavaInflector/formParams.mustache index ae90ae4c74..2b68f2fc24 100644 --- a/src/main/resources/handlebars/JavaInflector/formParams.mustache +++ b/src/main/resources/handlebars/JavaInflector/formParams.mustache @@ -1 +1 @@ - {{#is this 'form-param'}}{{#notFile}}{{{dataType}}} {{paramName}}{{/notFile}}{{#is this 'file'}}FormDataContentDisposition fileDetail{{/is}}{{/is}} \ No newline at end of file + {{#is this 'form-param'}}{{#isNot this 'binary'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}}FormDataContentDisposition fileDetail{{/is}}{{/is}} diff --git a/src/main/resources/handlebars/JavaInflector/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaInflector/generatedAnnotation.mustache index a47b6faa85..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaInflector/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaInflector/generatedAnnotation.mustache @@ -1 +1 @@ -{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaInflector/interface.mustache b/src/main/resources/handlebars/JavaInflector/interface.mustache new file mode 100644 index 0000000000..abec32f768 --- /dev/null +++ b/src/main/resources/handlebars/JavaInflector/interface.mustache @@ -0,0 +1,11 @@ +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaInflector/model.mustache b/src/main/resources/handlebars/JavaInflector/model.mustache index b050a713b7..ee7a1c055e 100644 --- a/src/main/resources/handlebars/JavaInflector/model.mustache +++ b/src/main/resources/handlebars/JavaInflector/model.mustache @@ -1,18 +1,26 @@ package {{package}}; - +{{^x-is-composed-model}} import java.util.Objects; {{#imports}}import {{import}}; {{/imports}} -{{#serializableModel}}import java.io.Serializable;{{/serializableModel~}} -{{#models~}} -{{#model}}{{#description}} +{{#serializableModel}}import java.io.Serializable;{{/serializableModel}} +{{/x-is-composed-model}} +{{#models}} +{{#model}} +{{#description}} /** * {{description}} - **/{{/description~}} + **/ +{{/description}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#is this 'enum'}} {{>enumOuterClass}} -{{/is~}} +{{/is}} {{#isNot this 'enum'}}{{>pojo}}{{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaInflector/pojo.mustache b/src/main/resources/handlebars/JavaInflector/pojo.mustache index 50a3911ef9..4d27629b58 100644 --- a/src/main/resources/handlebars/JavaInflector/pojo.mustache +++ b/src/main/resources/handlebars/JavaInflector/pojo.mustache @@ -1,6 +1,7 @@ {{#description}}{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description = "{{{description}}}"){{/description}} {{>generatedAnnotation}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { + +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#vars}} {{#baseItems this}} {{#is this 'enum'}} diff --git a/src/main/resources/handlebars/JavaInflector/pom.mustache b/src/main/resources/handlebars/JavaInflector/pom.mustache index 8038c89633..b01b8b4495 100644 --- a/src/main/resources/handlebars/JavaInflector/pom.mustache +++ b/src/main/resources/handlebars/JavaInflector/pom.mustache @@ -117,11 +117,15 @@ + {{#java11}} + 11 + 11 + {{/java11}} UTF-8 1.0.0 9.4.9.v20180320 - 1.0.1 - 4.8.2 + 1.2.9 + 4.13.1 1.6.3 2.0.0 diff --git a/src/main/resources/handlebars/JavaInflector/web.mustache b/src/main/resources/handlebars/JavaInflector/web.mustache index 16a254d111..5ff9821692 100644 --- a/src/main/resources/handlebars/JavaInflector/web.mustache +++ b/src/main/resources/handlebars/JavaInflector/web.mustache @@ -4,7 +4,7 @@ swagger-inflector org.glassfish.jersey.servlet.ServletContainer - javax.ws.rs.Application + {{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.ws.rs.Application io.swagger.oas.inflector.OpenAPIInflector 1 @@ -21,4 +21,4 @@ CORSFilter /* - \ No newline at end of file + diff --git a/src/main/resources/handlebars/JavaJaxRS/ApiOriginFilter.mustache b/src/main/resources/handlebars/JavaJaxRS/ApiOriginFilter.mustache index b8af270a05..f9ef60c3ee 100644 --- a/src/main/resources/handlebars/JavaJaxRS/ApiOriginFilter.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/ApiOriginFilter.mustache @@ -2,11 +2,17 @@ package {{apiPackage}}; import java.io.IOException; +{{#jakarta}} +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletResponse; +{{/jakarta}} +{{^jakarta}} import javax.servlet.*; import javax.servlet.http.HttpServletResponse; +{{/jakarta}} {{>generatedAnnotation}} -public class ApiOriginFilter implements javax.servlet.Filter { +public class ApiOriginFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = (HttpServletResponse) response; @@ -19,4 +25,4 @@ public class ApiOriginFilter implements javax.servlet.Filter { public void destroy() {} public void init(FilterConfig filterConfig) throws ServletException {} -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/ApiResponseMessage.mustache b/src/main/resources/handlebars/JavaJaxRS/ApiResponseMessage.mustache index c883e16b5e..50f428a3aa 100644 --- a/src/main/resources/handlebars/JavaJaxRS/ApiResponseMessage.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/ApiResponseMessage.mustache @@ -1,8 +1,15 @@ package {{apiPackage}}; +{{#jakarta}} +import jakarta.xml.bind.annotation.XmlTransient; + +@jakarta.xml.bind.annotation.XmlRootElement +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.XmlTransient; @javax.xml.bind.annotation.XmlRootElement +{{/jakarta}} {{>generatedAnnotation}} public class ApiResponseMessage { public static final int ERROR = 1; diff --git a/src/main/resources/handlebars/JavaJaxRS/JodaDateTimeProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/JodaDateTimeProvider.mustache index f942179098..2e81525879 100644 --- a/src/main/resources/handlebars/JavaJaxRS/JodaDateTimeProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/JodaDateTimeProvider.mustache @@ -4,6 +4,16 @@ import com.sun.jersey.core.spi.component.ComponentContext; import com.sun.jersey.spi.inject.Injectable; import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider; +{{#jakarta}} +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.UriInfo; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; @@ -11,6 +21,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Provider; +{{/jakarta}} import org.joda.time.DateTime; import java.util.List; @@ -41,4 +52,4 @@ public class JodaDateTimeProvider extends PerRequestTypeInjectableProviderqueryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},{{/parameters}}@Context SecurityContext securityContext) + public Response {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}},{{/parameters}}@Context SecurityContext securityContext) throws NotFoundException { - return delegate.{{nickname}}({{#parameters}}{{#isFile}}{{paramName}}InputStream, {{paramName}}Detail{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}},{{/parameters}}securityContext); + return delegate.{{nickname}}({{#parameters}}{{#isBinary}}{{#isBodyParam}}{{paramName}}{{/isBodyParam}}{{^isBodyParam}}{{paramName}}InputStream, {{paramName}}Detail{{/isBodyParam}}{{/isBinary}}{{^isBinary}}{{paramName}}{{/isBinary}},{{/parameters}}securityContext); } +{{/@first}} {{/contents}} {{/operation}} } diff --git a/src/main/resources/handlebars/JavaJaxRS/apiService.mustache b/src/main/resources/handlebars/JavaJaxRS/apiService.mustache index 860dda7270..570856c13e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/apiService.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/apiService.mustache @@ -14,17 +14,28 @@ import {{package}}.NotFoundException; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{>generatedAnnotation}} {{#operations}} public abstract class {{classname}}Service { {{#operation}} {{#contents}} - public abstract Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}},{{/parameters}}SecurityContext securityContext) throws NotFoundException; + public abstract Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>serviceCookieParams}},{{/parameters}}SecurityContext securityContext) throws NotFoundException; {{/contents}} {{/operation}} } diff --git a/src/main/resources/handlebars/JavaJaxRS/apiServiceImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/apiServiceImpl.mustache index f43cc2774a..4ae2646850 100644 --- a/src/main/resources/handlebars/JavaJaxRS/apiServiceImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/apiServiceImpl.mustache @@ -14,10 +14,21 @@ import java.io.InputStream; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} import javax.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} +import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{>generatedAnnotation}} {{#operations}} @@ -25,7 +36,7 @@ public class {{classname}}ServiceImpl extends {{classname}}Service { {{#operation}} {{#contents}} @Override - public Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}, {{/parameters}}SecurityContext securityContext) throws NotFoundException { + public Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>serviceCookieParams}}, {{/parameters}}SecurityContext securityContext) throws NotFoundException { // do some magic! return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); } diff --git a/src/main/resources/handlebars/JavaJaxRS/beanValidation.mustache b/src/main/resources/handlebars/JavaJaxRS/beanValidation.mustache index c8c6946fef..25e9ce282b 100644 --- a/src/main/resources/handlebars/JavaJaxRS/beanValidation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/beanValidation.mustache @@ -1,4 +1,16 @@ {{#required}} @NotNull {{/required}} -{{>beanValidationCore}} \ No newline at end of file +{{#is this 'container'}} +{{#isNot this 'primitive-type'}} +{{#isNot this 'enum'}} + @Valid +{{/isNot}} +{{/isNot}} +{{/is}} +{{#isNot this 'container'}} +{{#isNot this 'primitive-type'}} + @Valid +{{/isNot}} +{{/isNot}} +{{>beanValidationCore}} diff --git a/src/main/resources/handlebars/JavaJaxRS/bodyParams.mustache b/src/main/resources/handlebars/JavaJaxRS/bodyParams.mustache index e590766510..708039d621 100644 --- a/src/main/resources/handlebars/JavaJaxRS/bodyParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/bodyParams.mustache @@ -3,6 +3,6 @@ @ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}} {{/useOas2}} {{^useOas2}} -@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}} +@Parameter(in = ParameterIn.DEFAULT, description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}} {{/useOas2}} {{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/bootstrap.mustache b/src/main/resources/handlebars/JavaJaxRS/bootstrap.mustache index 433c0389c3..72f020fcc6 100644 --- a/src/main/resources/handlebars/JavaJaxRS/bootstrap.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/bootstrap.mustache @@ -1,9 +1,17 @@ package {{apiPackage}}; +{{#jakarta}} +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletConfig; +import jakarta.servlet.ServletException; +{{/jakarta}} +{{^jakarta}} import javax.servlet.http.HttpServlet; import javax.servlet.ServletContext; import javax.servlet.ServletConfig; import javax.servlet.ServletException; +{{/jakarta}} {{#useOas2}} import io.swagger.jaxrs.config.SwaggerContextService; @@ -52,4 +60,4 @@ import io.swagger.v3.oas.annotations.info.License; ) public class Bootstrap { } -{{/useOas2}} \ No newline at end of file +{{/useOas2}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cookieParams.mustache new file mode 100644 index 0000000000..66188f8068 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/cookieParams.mustache @@ -0,0 +1,4 @@ +{{#isCookieParam}} +{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(in = ParameterIn.COOKIE, description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{/isCookieParam}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/RestApplication.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/RestApplication.mustache index d3d8b238d7..722cb94e47 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/RestApplication.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/RestApplication.mustache @@ -1,9 +1,15 @@ package {{invokerPackage}}; +{{#jakarta}} +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; +{{/jakarta}} @ApplicationPath("/") public class RestApplication extends Application { // Add implementation-specific details here -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/api.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/api.mustache index 1fa6183916..41780bfce4 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/api.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/api.mustache @@ -4,12 +4,22 @@ package {{package}}; {{/imports}} import {{package}}.{{classname}}Service; +{{#jakarta}} +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; +{{/jakarta}} {{#useOas2}} import io.swagger.annotations.*; @@ -32,7 +42,12 @@ import org.apache.cxf.jaxrs.ext.multipart.Multipart; import java.util.Map; import java.util.List; {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} @Path("/{{{baseName}}}") @RequestScoped @@ -59,8 +74,8 @@ public class {{classname}} { {{#useOas2}} @ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnBaseType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { {{#authMethods}}@Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}@AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @@ -70,13 +85,13 @@ public class {{classname}} { {{^useOas2}} @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}"{{scope}}"{{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}"{{@key}}"{{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) {{/useOas2}} public Response {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { return delegate.{{nickname}}({{#parameters}}{{#isFile}}{{paramName}}InputStream, {{paramName}}Detail{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}}, {{/parameters}}securityContext); diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiService.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiService.mustache index d75faaca09..7055bc34d6 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiService.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiService.mustache @@ -13,8 +13,14 @@ import java.util.List; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{>generatedAnnotation}} {{#operations}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiServiceImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiServiceImpl.mustache index b0af063d33..812338de91 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiServiceImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/apiServiceImpl.mustache @@ -12,9 +12,16 @@ import java.util.List; import java.io.InputStream; +{{#jakarta}} +import jakarta.enterprise.context.RequestScoped; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.enterprise.context.RequestScoped; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} @RequestScoped {{>generatedAnnotation}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/beanValidation.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/beanValidation.mustache index c8c6946fef..bb8ecd0b94 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/beanValidation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/beanValidation.mustache @@ -1,4 +1,16 @@ {{#required}} @NotNull {{/required}} -{{>beanValidationCore}} \ No newline at end of file +{{#isContainer}} +{{^isPrimitiveType}} +{{^isEnum}} + @Valid +{{/isEnum}} +{{/isPrimitiveType}} +{{/isContainer}} +{{#isNotContainer}} +{{^isPrimitiveType}} + @Valid +{{/isPrimitiveType}} +{{/isNotContainer}} +{{>beanValidationCore}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/bodyParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/bodyParams.mustache index 19bf8985a0..9ad8f3307e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/bodyParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/bodyParams.mustache @@ -1,4 +1,4 @@ {{#is this 'body-param'}} {{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}} -{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}}{{/useOas2}} {{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/enumClass.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/enumClass.mustache index 8468ae2cfe..a4bdc0dc04 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/enumClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/enumClass.mustache @@ -3,7 +3,7 @@ public enum {{datatypeWithEnum}} { {{#allowableValues}} - {{#enumVars}}@XmlEnumValue({{{value}}}) {{name}}({{datatype}}.valueOf({{{value}}})){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}} + {{#enumVars}}{{#value}}@XmlEnumValue({{{value}}}) {{name}}({{datatype}}.valueOf({{{value}}})){{/value}}{{^value}}@XmlEnumValue("") {{name}}(null){{/value}}{{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}} {{/allowableValues}} @@ -28,6 +28,6 @@ public enum {{datatypeWithEnum}} { return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/formParams.mustache index 362ebd9bb3..44953d477e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/formParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}@Multipart(value = "{{baseName}}"{{^required}}, required = false{{/required}}) {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}} @Multipart(value = "{{baseName}}"{{^required}}, required = false{{/required}}) InputStream {{paramName}}InputStream, @Multipart(value = "{{baseName}}" {{^required}}, required = false{{/required}}) Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}@Multipart(value = "{{baseName}}"{{^required}}, required = false{{/required}}) {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}} @Multipart(value = "{{baseName}}"{{^required}}, required = false{{/required}}) InputStream {{paramName}}InputStream, @Multipart(value = "{{baseName}}" {{^required}}, required = false{{/required}}) Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/generatedAnnotation.mustache index a47b6faa85..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/generatedAnnotation.mustache @@ -1 +1 @@ -{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/headerParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/headerParams.mustache index 03d9996941..034f7386a7 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/headerParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/headerParams.mustache @@ -1,4 +1,4 @@ {{#is this 'header-param'}} {{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} -{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} {{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/interface.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/interface.mustache new file mode 100644 index 0000000000..abec32f768 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/interface.mustache @@ -0,0 +1,11 @@ +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/model.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/model.mustache index 4f404cc293..5edf75f7d8 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/model.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/model.mustache @@ -1,16 +1,29 @@ package {{package}}; +{{^x-is-composed-model}} {{#imports}}import {{import}}; {{/imports}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} +{{/x-is-composed-model}} {{#models}} -{{#model}}{{#description}} +{{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} +{{#description}} /** * {{description}} **/{{/description}} {{#is this 'enum'}}{{>enumClass}}{{/is}} {{#isNot this 'enum'}}{{>pojo}}{{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pathParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pathParams.mustache index 1e6de2eb24..75f17f029e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pathParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pathParams.mustache @@ -1,4 +1,4 @@ {{#is this 'path-param'}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}} {{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} -{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} {{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pojo.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pojo.mustache index 9a93cb86a4..d8cc0f03f1 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pojo.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pojo.mustache @@ -6,11 +6,16 @@ import io.swagger.v3.oas.annotations.media.Schema; {{/useOas2}} import java.util.Objects; +{{#jakarta}} +import jakarta.xml.bind.annotation.*; +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.*; +{{/jakarta}} {{#description}}{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description = "{{{description}}}"){{/description}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#vars}} {{#baseItems this}} {{#is this 'enum'}} @@ -41,7 +46,7 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#seriali {{#useOas2}}@ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useOas2}} {{^useOas2}}@Schema({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useOas2}} @JsonProperty("{{baseName}}") -{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { +{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; } public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pom.mustache index 070c9f7c2b..fe70e414b4 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/pom.mustache @@ -46,12 +46,22 @@ + {{#jakarta}} + + jakarta.platform + jakarta.jakartaee-api + 10.0.0 + provided + + {{/jakarta}} + {{^jakarta}} javax javaee-api 7.0 provided + {{/jakarta}} @@ -59,7 +69,7 @@ cxf-rt-frontend-jaxrs - 3.0.2 + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}3.5.5{{/jakarta}} provided @@ -88,14 +98,31 @@ {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} + {{#java11}} + + 11 + 11 + + {{/java11}} + diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/queryParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/queryParams.mustache index 5469b8f45f..27d735dd37 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/queryParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/queryParams.mustache @@ -1,4 +1,4 @@ {{#is this 'query-param'}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}} {{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{#defaultValue}}@DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} -{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{#defaultValue}}@DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{#defaultValue}}@DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} {{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/serviceFormParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/serviceFormParams.mustache index d5294a8b96..4bf0ae7c29 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/serviceFormParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf-cdi/serviceFormParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}}InputStream {{paramName}}InputStream, Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}}InputStream {{paramName}}InputStream, Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/CXF2InterfaceComparator.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/CXF2InterfaceComparator.mustache index d1fd0bf82c..8e4f060577 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/CXF2InterfaceComparator.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/CXF2InterfaceComparator.mustache @@ -5,8 +5,26 @@ import java.lang.reflect.Method; import java.util.regex.Matcher; import java.util.regex.Pattern; +{{#jakarta}} +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.HEAD; +import jakarta.ws.rs.HttpMethod; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.OPTIONS; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +{{/jakarta}} +{{^jakarta}} +import javax.ws.rs.DELETE; +import javax.ws.rs.HEAD; import javax.ws.rs.HttpMethod; +import javax.ws.rs.GET; +import javax.ws.rs.OPTIONS; import javax.ws.rs.Path; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +{{/jakarta}} import org.apache.cxf.jaxrs.ext.ResourceComparator; import org.apache.cxf.jaxrs.model.ClassResourceInfo; @@ -60,7 +78,7 @@ public class CXFInterfaceComparator implements ResourceComparator { Method[] methods = cri.getServiceClass().getInterfaces()[0].getMethods(); // Java reflexion. Check all the methods of an interface. for (Method method : methods) { - Path pathAnnotation = method.getAnnotation(javax.ws.rs.Path.class); + Path pathAnnotation = method.getAnnotation(Path.class); if (pathAnnotation != null && pathAnnotation.value() != null) { String pathValue = pathAnnotation.value(); String methodHttpVerb = getMethodHttpVerb(method); @@ -79,17 +97,17 @@ public class CXFInterfaceComparator implements ResourceComparator { } private static String getMethodHttpVerb(Method method) { - if (method.getAnnotation(javax.ws.rs.POST.class) != null) { + if (method.getAnnotation(POST.class) != null) { return HttpMethod.POST; - } else if (method.getAnnotation(javax.ws.rs.GET.class) != null) { + } else if (method.getAnnotation(GET.class) != null) { return HttpMethod.GET; - } else if (method.getAnnotation(javax.ws.rs.PUT.class) != null) { + } else if (method.getAnnotation(PUT.class) != null) { return HttpMethod.PUT; - } else if (method.getAnnotation(javax.ws.rs.OPTIONS.class) != null) { + } else if (method.getAnnotation(OPTIONS.class) != null) { return HttpMethod.OPTIONS; - } else if (method.getAnnotation(javax.ws.rs.DELETE.class) != null) { + } else if (method.getAnnotation(DELETE.class) != null) { return HttpMethod.DELETE; - } else if (method.getAnnotation(javax.ws.rs.HEAD.class) != null) { + } else if (method.getAnnotation(HEAD.class) != null) { return HttpMethod.HEAD; } assert false; @@ -117,4 +135,4 @@ public class CXFInterfaceComparator implements ResourceComparator { public int compare(OperationResourceInfo ori1, OperationResourceInfo ori2, Message message) { return 0; // Leave CXF decision } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/api.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/api.mustache index 70c4ebdf3c..c2d3005aa9 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/api.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/api.mustache @@ -7,9 +7,16 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Map; +{{#jakarta}} +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.MediaType; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.*; import javax.ws.rs.core.Response; import javax.ws.rs.core.MediaType; +{{/jakarta}} import org.apache.cxf.jaxrs.ext.multipart.*; {{#useOas2}} @@ -28,8 +35,14 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; {{/useOas2}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +import jakarta.validation.Valid; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; import javax.validation.Valid; +{{/jakarta}} {{/useBeanValidation}} {{#appName}} @@ -81,9 +94,9 @@ public interface {{classname}} { {{^useOas2}} @Operation(summary = "{{{summary}}}", tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) {{/useOas2}} - public {{>returnTypes}} {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); + public {{>returnTypes}} {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); {{/contents}} {{/operation}} } diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/apiServiceImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/apiServiceImpl.mustache index 82ebd6da18..7e54832af9 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/apiServiceImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/apiServiceImpl.mustache @@ -8,8 +8,14 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.Map; +{{#jakarta}} +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.*; import javax.ws.rs.core.Response; +{{/jakarta}} import org.apache.cxf.jaxrs.model.wadl.Description; import org.apache.cxf.jaxrs.model.wadl.DocTarget; @@ -48,7 +54,7 @@ public class {{classname}}ServiceImpl implements {{classname}} { {{/notes}} */ {{/summary}} - public {{>returnTypes}} {{nickname}}({{#parameters}}{{>queryParamsImpl}}{{>pathParamsImpl}}{{>headerParamsImpl}}{{>bodyParamsImpl}}{{>formParamsImpl}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { + public {{>returnTypes}} {{nickname}}({{#parameters}}{{>queryParamsImpl}}{{>pathParamsImpl}}{{>headerParamsImpl}}{{>cookieParamsImpl}}{{>bodyParamsImpl}}{{>formParamsImpl}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { // TODO: Implement... {{#useGenericResponse}}return Response.ok().entity("magic!").build();{{/useGenericResponse}}{{^useGenericResponse}}{{^vendorExtensions.x-java-is-response-void}}return null;{{/vendorExtensions.x-java-is-response-void}}{{/useGenericResponse}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/api_test.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/api_test.mustache index 5194af8457..b1b6bbacac 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/api_test.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/api_test.mustache @@ -8,7 +8,12 @@ import org.junit.Test; import org.junit.Before; import static org.junit.Assert.*; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; +{{/jakarta}} import org.apache.cxf.jaxrs.client.JAXRSClientFactory; import org.apache.cxf.jaxrs.client.ClientConfiguration; import org.apache.cxf.jaxrs.client.WebClient; @@ -113,7 +118,7 @@ public class {{classname}}Test { @Test public void {{operationId}}Test() { {{#parameters}} - {{^isFile}}{{{dataType}}} {{paramName}} = null;{{/isFile}}{{#isFile}}org.apache.cxf.jaxrs.ext.multipart.Attachment {{paramName}} = null;{{/isFile}} + {{^isBinary}}{{{dataType}}} {{paramName}} = null;{{/isBinary}}{{#isBinary}}org.apache.cxf.jaxrs.ext.multipart.Attachment {{paramName}} = null;{{/isBinary}} {{/parameters}} //{{^vendorExtensions.x-java-is-response-void}}{{>returnTypes}} response = {{/vendorExtensions.x-java-is-response-void}}api.{{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); {{^vendorExtensions.x-java-is-response-void}}//assertNotNull(response);{{/vendorExtensions.x-java-is-response-void}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/cookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/cookieParams.mustache new file mode 100644 index 0000000000..4af2e57d24 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/cookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}@CookieParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/cookieParamsImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/cookieParamsImpl.mustache new file mode 100644 index 0000000000..70871f0f8c --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/cookieParamsImpl.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{{dataType}}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/enumClass.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/enumClass.mustache index 6877d65cef..a995e67f88 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/enumClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/enumClass.mustache @@ -3,7 +3,7 @@ public enum {{datatypeWithEnum}} { {{#allowableValues}} -{{#enumVars}}@XmlEnumValue({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) {{name}}({{datatype}}.valueOf({{{value}}})){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}} +{{#enumVars}}@XmlEnumValue({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) {{name}}({{#value}}{{datatype}}.valueOf({{{value}}}){{/value}}{{^value}}null{{/value}})){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}} {{/allowableValues}} @@ -28,6 +28,6 @@ public enum {{datatypeWithEnum}} { return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/enumOuterClass.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/enumOuterClass.mustache index 96d3759f0d..5973e0434e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/enumOuterClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/enumOuterClass.mustache @@ -3,9 +3,16 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; {{/jackson}} {{#withXml}} +{{#jakarta}} +import jakarta.xml.bind.annotation.XmlType; +import jakarta.xml.bind.annotation.XmlEnum; +import jakarta.xml.bind.annotation.XmlEnumValue; +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlEnum; import javax.xml.bind.annotation.XmlEnumValue; +{{/jakarta}} {{/withXml}} /** @@ -14,24 +21,30 @@ import javax.xml.bind.annotation.XmlEnumValue; {{#if withXml}} @XmlType(name="{{classname}}") @XmlEnum({{dataType}}.class) -{{/if~}} +{{/if}} public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { {{#if gson}} - {{#allowableValues}}{{#enumVars}} + {{#allowableValues}} + {{#enumVars}} @SerializedName({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) {{#if withXml}} - @XmlEnumValue({{{value}}}) - {{/if~}} - {{{name}}}({{{value}}}){{^@last}}, - {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} + @XmlEnumValue({{#value}}{{{value}}}{{/value}}{{^value}}""{{/value}}) + {{/if}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, + {{/@last}}{{#@last}};{{/@last}} + {{/enumVars}} + {{/allowableValues}} {{/if}} {{#unless gson}} - {{#allowableValues}}{{#enumVars}} + {{#allowableValues}} + {{#enumVars}} {{#if withXml}} - @XmlEnumValue({{{value}}}) - {{/if~}} - {{{name}}}({{{value}}}){{^@last}}, - {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} + @XmlEnumValue({{#value}}{{{value}}}{{/value}}{{^value}}""{{/value}}) + {{/if}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, + {{/@last}}{{#@last}};{{/@last}} + {{/enumVars}} + {{/allowableValues}} {{/unless}} private {{{dataType}}} value; @@ -57,7 +70,7 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/formParams.mustache index 3a58a53af4..c3039d77ba 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/formParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}@Multipart(value = "{{baseName}}"{{^required}}, required = false{{/required}}) {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}} @Multipart(value = "{{baseName}}" {{^required}}, required = false{{/required}}) Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}@Multipart(value = "{{baseName}}"{{^required}}, required = false{{/required}}) {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}} @Multipart(value = "{{baseName}}" {{^required}}, required = false{{/required}}) Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/formParamsImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/formParamsImpl.mustache index 2c42609fc8..1d683f5b40 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/formParamsImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/formParamsImpl.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}} Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}} Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/generatedAnnotation.mustache index 49110fc1ad..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/generatedAnnotation.mustache @@ -1 +1 @@ -@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}") \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/interface.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/interface.mustache new file mode 100644 index 0000000000..abec32f768 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/interface.mustache @@ -0,0 +1,11 @@ +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/model.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/model.mustache index 20e40f7f1a..8642b990ba 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/model.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/model.mustache @@ -1,18 +1,30 @@ package {{package}}; +{{^isComposedModel}} {{#imports}}import {{import}}; {{/imports}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} +{{/isComposedModel}} {{#models}} {{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#is this 'enum'}} {{>enumOuterClass}} {{/is}} {{#isNot this 'enum'}} {{>pojo}} {{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/modelInnerEnum.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/modelInnerEnum.mustache index 5307c94b04..384db158f5 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/modelInnerEnum.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/modelInnerEnum.mustache @@ -1,7 +1,14 @@ + {{#withXml}} + @XmlType(name="{{datatypeWithEnum}}") + @XmlEnum({{datatypeWithEnum}}.class) + {{/withXml}} public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} + {{#withXml}} + @XmlEnumValue({{#value}}{{{value}}}{{/value}}{{^value}}""{{/value}}) + {{/withXml}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/pojo.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/pojo.mustache index 7d61c74953..656f475a03 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/pojo.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/pojo.mustache @@ -4,6 +4,16 @@ import io.swagger.annotations.ApiModelProperty; {{^useOas2}} import io.swagger.v3.oas.annotations.media.Schema; {{/useOas2}} +{{#jakarta}} +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlType; +import jakarta.xml.bind.annotation.XmlEnum; +import jakarta.xml.bind.annotation.XmlEnumValue; +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAccessType; @@ -11,6 +21,7 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.XmlEnum; import javax.xml.bind.annotation.XmlEnumValue; +{{/jakarta}} import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonCreator; @@ -29,9 +40,13 @@ import com.fasterxml.jackson.annotation.JsonCreator; **/ {{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description="{{{description}}}") {{/description}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} { - {{#vars}}{{#baseItems this}}{{#is this 'enum'}} -{{>modelInnerEnum}}{{/is~}}{{/baseItems}} +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}} { + {{#vars}} + {{#baseItems this}} + {{#is this 'enum'}} +{{>modelInnerEnum}} + {{/is}} + {{/baseItems}} {{#withXml}} @XmlElement(name="{{baseName}}"{{#required}}, required = {{required}}{{/required}}) {{/withXml}} @@ -69,16 +84,16 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} { {{#vendorExtensions.extraAnnotation}} {{{vendorExtensions.extraAnnotation}}} {{/vendorExtensions.extraAnnotation}} -{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} {{#is this 'enum'}}{{#isNot this 'list-container'}}{{#isNot this 'map-container'}}public {{datatype}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { +{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} {{#is this 'enum'}}{{#isNot this 'list-container'}}{{#isNot this 'map-container'}}public {{datatype}} {{getter}}() { if ({{name}} == null) { return null; } return {{name}}.getValue(); - }{{/isNot}}{{/isNot}}{{/is}}{{#is this 'enum'}}{{#is this 'list-container'}}public {{{datatypeWithEnum}}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { + }{{/isNot}}{{/isNot}}{{/is}}{{#is this 'enum'}}{{#is this 'list-container'}}public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; - }{{/is}}{{/is}}{{#is this 'enum'}}{{#is this 'map-container'}}public {{{datatypeWithEnum}}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { + }{{/is}}{{/is}}{{#is this 'enum'}}{{#is this 'map-container'}}public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; - }{{/is}}{{/is}}{{#isNot this 'enum'}}public {{{datatypeWithEnum}}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { + }{{/is}}{{/is}}{{#isNot this 'enum'}}public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; }{{/isNot}} diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/pom.mustache index c995c8a0ab..a36384c6e7 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/pom.mustache @@ -41,11 +41,22 @@ {{#useBeanValidation}} + {{#jakarta}} - javax.validation - validation-api - ${beanvalidation-version} + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + provided + {{/jakarta}} + {{^jakarta}} + + javax.validation + validation-api + ${beanvalidation-version} + provided + + {{/jakarta}} {{/useBeanValidation}} @@ -127,12 +138,22 @@ {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api ${beanvalidation-version} provided + {{/jakarta}} {{/useBeanValidation}} @@ -141,7 +162,7 @@ ${cxf-version} test - + org.apache.cxf @@ -187,13 +208,31 @@ ${jackson-jaxrs-version} {{/java8}} -{{#useBeanValidationFeature}} +{{#useBeanValidationFeature}} org.hibernate hibernate-validator - 5.2.2.Final + {{#jakarta}}8.0.0.Final{{/jakarta}}{{^jakarta}}5.2.2.Final{{/jakarta}} {{/useBeanValidationFeature}} + {{#jakarta}} + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + + + com.sun.xml.bind + jaxb-impl + 4.0.1 + + + jakarta.activation + jakarta.activation-api + 2.1.0 + + {{/jakarta}} + {{^jakarta}} javax.xml.bind jaxb-api @@ -204,6 +243,7 @@ activation 1.1.1 + {{/jakarta}} @@ -215,7 +255,7 @@ - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} {{#useOas2}} @@ -225,13 +265,13 @@ 2.0.0 {{/useOas2}} 9.2.9.v20150224 - 4.12 - 1.1.7 + 4.13.1 + 1.2.9 2.5 {{#useBeanValidation}} - 1.1.0.Final + {{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}1.1.0.Final{{/jakarta}} {{/useBeanValidation}} - 3.2.4 + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}3.2.4{{/jakarta}} 2.9.1 UTF-8 diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/server/ApplicationContext.xml.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/server/ApplicationContext.xml.mustache index fd1b6d6f8f..1fa7aea495 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/server/ApplicationContext.xml.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/server/ApplicationContext.xml.mustache @@ -84,7 +84,7 @@ {{/useGzipFeature}} - + diff --git a/src/main/resources/handlebars/JavaJaxRS/cxf/server/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/cxf/server/pom.mustache index 802c1e9538..31c6ff7b36 100644 --- a/src/main/resources/handlebars/JavaJaxRS/cxf/server/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/cxf/server/pom.mustache @@ -41,11 +41,20 @@ {{#useBeanValidation}} + {{#jakarta}} - javax.validation - validation-api - ${beanvalidation-version} + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + {{/jakarta}} + {{^jakarta}} + + javax.validation + validation-api + ${beanvalidation-version} + + {{/jakarta}} {{/useBeanValidation}} @@ -88,7 +97,7 @@ - + maven-war-plugin @@ -136,12 +145,22 @@ {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api ${beanvalidation-version} provided + {{/jakarta}} {{/useBeanValidation}} @@ -150,7 +169,7 @@ ${cxf-version} test - + org.apache.cxf @@ -212,7 +231,7 @@ ${jackson-jaxrs-version} {{/java8}} -{{#generateSpringApplication}} +{{#generateSpringApplication}} org.springframework @@ -223,7 +242,7 @@ org.springframework spring-web ${spring-version} - + {{/generateSpringApplication}} {{#generateSpringBootApplication}} @@ -240,7 +259,7 @@ ${spring.boot-version} test - + org.apache.cxf cxf-spring-boot-starter-jaxrs @@ -255,16 +274,35 @@ 3.6.1 {{/useSwaggerUI}} + {{#jakarta}} + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + - javax.xml.bind - jaxb-api - 2.2.6 + com.sun.xml.bind + jaxb-impl + 4.0.1 - javax.activation - activation - 1.1.1 + jakarta.activation + jakarta.activation-api + 2.1.0 + {{/jakarta}} + {{^jakarta}} + + javax.xml.bind + jaxb-api + 2.2.6 + + + javax.activation + activation + 1.1.1 + + {{/jakarta}} @@ -276,7 +314,7 @@ - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} {{#useOas2}} @@ -286,19 +324,19 @@ 2.0.0 {{/useOas2}} 9.2.9.v20150224 - 4.12 - 1.1.7 + 4.13.1 + 1.2.9 2.5 {{#useBeanValidation}} - 1.1.0.Final + {{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}1.1.0.Final{{/jakarta}} {{/useBeanValidation}} -{{#generateSpringApplication}} +{{#generateSpringApplication}} 4.3.13.RELEASE -{{/generateSpringApplication}} +{{/generateSpringApplication}} {{#generateSpringBootApplication}} 1.5.9.RELEASE -{{/generateSpringBootApplication}} - 3.2.4 +{{/generateSpringBootApplication}} + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}3.2.4{{/jakarta}} 2.9.1 UTF-8 diff --git a/src/main/resources/handlebars/JavaJaxRS/di/api.mustache b/src/main/resources/handlebars/JavaJaxRS/di/api.mustache index 6ac2b09fbf..6c79865b54 100644 --- a/src/main/resources/handlebars/JavaJaxRS/di/api.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/di/api.mustache @@ -9,6 +9,7 @@ import io.swagger.annotations.ApiParam; {{^useOas2}} import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.media.ArraySchema; @@ -28,12 +29,25 @@ import java.io.InputStream; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; +{{#jakarta}} +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.ws.rs.*; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.*; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} @Path("/{{{baseName}}}") @@ -51,7 +65,7 @@ public class {{classname}} { protected {{classname}}() { } - @javax.inject.Inject + @{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.inject.Inject public {{classname}}({{classname}}Service delegate) { this.delegate = delegate; } @@ -65,8 +79,8 @@ public class {{classname}} { {{#useOas2}} @io.swagger.annotations.ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnBaseType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { {{#authMethods}}@io.swagger.annotations.Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@io.swagger.annotations.AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}@io.swagger.annotations.AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}",{{/vendorExtensions.x-tags}} }) @@ -77,18 +91,18 @@ public class {{classname}} { {{^useOas2}} @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}"{{scope}}"{{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}"{{@key}}"{{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#has this 'more'}}, + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#has this 'more'}}, {{/has}}{{/responses}} }) {{/useOas2}} public Response {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},{{/parameters}}@Context SecurityContext securityContext) throws NotFoundException { - return delegate.{{nickname}}({{#parameters}}{{#isFile}}{{paramName}}InputStream, {{paramName}}Detail{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}},{{/parameters}}securityContext); + return delegate.{{nickname}}({{#parameters}}{{#isBinary}}{{paramName}}InputStream, {{paramName}}Detail{{/isBinary}}{{^isBinary}}{{paramName}}{{/isBinary}},{{/parameters}}securityContext); } {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/JavaJaxRS/di/apiService.mustache b/src/main/resources/handlebars/JavaJaxRS/di/apiService.mustache index 56092f5e7c..414550b752 100644 --- a/src/main/resources/handlebars/JavaJaxRS/di/apiService.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/di/apiService.mustache @@ -13,10 +13,21 @@ import java.util.List; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{>generatedAnnotation}} {{#operations}} diff --git a/src/main/resources/handlebars/JavaJaxRS/enumClass.mustache b/src/main/resources/handlebars/JavaJaxRS/enumClass.mustache index 9c7d07e5ab..e8ee70384b 100644 --- a/src/main/resources/handlebars/JavaJaxRS/enumClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/enumClass.mustache @@ -6,7 +6,7 @@ {{#allowableValues}} {{#enumVars}} @SerializedName({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -14,7 +14,7 @@ {{#unless gson}} {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -39,6 +39,6 @@ return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/enumOuterClass.mustache b/src/main/resources/handlebars/JavaJaxRS/enumOuterClass.mustache index 97a0a180d9..c31aa1b5ce 100644 --- a/src/main/resources/handlebars/JavaJaxRS/enumOuterClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/enumOuterClass.mustache @@ -9,12 +9,12 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum {{#if gson}} {{#allowableValues}}{{#enumVars}} @SerializedName({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/if}} {{#unless gson}} {{#allowableValues}}{{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/unless}} @@ -37,6 +37,6 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/formParams.mustache index 0080b9b373..5bd5a1cf3f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/formParams.mustache @@ -1,2 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/useOas2}}{{/isNot}}{{#is this 'file'}}@FormDataParam("{{baseName}}") InputStream {{paramName}}InputStream, - @FormDataParam("{{baseName}}") FormDataContentDisposition {{paramName}}Detail{{/is}}{{/is}} +{{#isFormParam}}{{^isBinary}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/useOas2}}{{/isBinary}}{{#isBinary}}@FormDataParam("{{baseName}}") InputStream {{paramName}}InputStream, @FormDataParam("{{baseName}}") FormDataContentDisposition {{paramName}}Detail{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaJaxRS/generatedAnnotation.mustache index a47b6faa85..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/generatedAnnotation.mustache @@ -1 +1 @@ -{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaJaxRS/headerParams.mustache b/src/main/resources/handlebars/JavaJaxRS/headerParams.mustache index 03d9996941..58841b48a2 100644 --- a/src/main/resources/handlebars/JavaJaxRS/headerParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/headerParams.mustache @@ -1,4 +1,4 @@ {{#is this 'header-param'}} {{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} -{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(in = ParameterIn.HEADER, description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}} {{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/interface.mustache b/src/main/resources/handlebars/JavaJaxRS/interface.mustache new file mode 100644 index 0000000000..abec32f768 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/interface.mustache @@ -0,0 +1,11 @@ +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaJaxRS/jacksonJsonProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/jacksonJsonProvider.mustache index 5fa284e809..132341ff36 100644 --- a/src/main/resources/handlebars/JavaJaxRS/jacksonJsonProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/jacksonJsonProvider.mustache @@ -13,9 +13,16 @@ import com.fasterxml.jackson.datatype.joda.*; import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; +{{#jakarta}} +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.Provider; +{{/jakarta}} @Provider @Produces({MediaType.APPLICATION_JSON}) @@ -36,4 +43,4 @@ public class JacksonJsonProvider extends JacksonJaxbJsonProvider { setMapper(objectMapper); } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/LocalDateProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/LocalDateProvider.mustache index 8c4cd4cbd1..a264da486f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/LocalDateProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/LocalDateProvider.mustache @@ -4,6 +4,16 @@ import com.sun.jersey.core.spi.component.ComponentContext; import com.sun.jersey.spi.inject.Injectable; import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider; +{{#jakarta}} +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.UriInfo; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; @@ -11,6 +21,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Provider; +{{/jakarta}} import java.time.LocalDate; import java.util.List; @@ -41,4 +52,4 @@ public class LocalDateProvider extends PerRequestTypeInjectableProviderqueryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}, + {{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>serviceCookieParams}}, {{/parameters}}@Context SecurityContext securityContext) throws NotFoundException { - return delegate.{{nickname}}({{#parameters}}{{#isFile}}inputStream, fileDetail{{/isFile}}{{^isFile}}{{paramName}}{{/isFile}},{{/parameters}}securityContext); + return delegate.{{nickname}}({{#parameters}}{{#isBinary}}{{#isBodyParam}}{{paramName}}{{/isBodyParam}}{{^isBodyParam}}{{paramName}}InputStream, {{paramName}}Detail{{/isBodyParam}}{{/isBinary}}{{^isBinary}}{{paramName}}{{/isBinary}},{{/parameters}}securityContext); } {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiService.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiService.mustache index 06d2d6a051..6b18780d60 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiService.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiService.mustache @@ -17,17 +17,28 @@ import java.io.InputStream; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataParam; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{>generatedAnnotation}} {{#operations}} public abstract class {{classname}}Service { {{#operation}} {{#contents}} - public abstract Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}},{{/parameters}}SecurityContext securityContext) + public abstract Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>serviceCookieParams}},{{/parameters}}SecurityContext securityContext) throws NotFoundException; {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiServiceImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiServiceImpl.mustache index d22f98fb8c..ee19b24d80 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiServiceImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/apiServiceImpl.mustache @@ -17,10 +17,21 @@ import java.io.InputStream; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataParam; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{>generatedAnnotation}} {{#operations}} @@ -28,7 +39,7 @@ public class {{classname}}ServiceImpl extends {{classname}}Service { {{#operation}} {{#contents}} @Override - public Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}, {{/parameters}}SecurityContext securityContext) + public Response {{nickname}}({{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>serviceCookieParams}}, {{/parameters}}SecurityContext securityContext) throws NotFoundException { // do some magic! return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/formParams.mustache index 9d505ebea4..5bd5a1cf3f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/formParams.mustache @@ -1,2 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{#isNot this 'multipart'}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/isNot}}{{#is this 'multipart'}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/is}}{{#isNot this 'multipart'}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{/isNot}}{{#is this 'file'}}@FormDataParam("{{baseName}}") InputStream inputStream, - @FormDataParam("{{baseName}}") FormDataContentDisposition fileDetail{{/is}}{{/is}} \ No newline at end of file +{{#isFormParam}}{{^isBinary}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}){{#vendorExtensions.x-multipart}}@FormDataParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{^vendorExtensions.x-multipart}} {{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/vendorExtensions.x-multipart}}{{/useOas2}}{{/isBinary}}{{#isBinary}}@FormDataParam("{{baseName}}") InputStream {{paramName}}InputStream, @FormDataParam("{{baseName}}") FormDataContentDisposition {{paramName}}Detail{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/pom.mustache index e4daf2e860..0ab2bef863 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey1/pom.mustache @@ -44,11 +44,20 @@ {{#useBeanValidation}} + {{#jakarta}} - javax.validation - validation-api - ${beanvalidation-version} + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + {{/jakarta}} + {{^jakarta}} + + javax.validation + validation-api + ${beanvalidation-version} + + {{/jakarta}} {{/useBeanValidation}} @@ -129,11 +138,27 @@ jersey-server ${jersey-version} + {{#jakarta}} + + jakarta.servlet + jakarta.servlet-api + ${servlet-api-version} + + + + jakarta.platform + jakarta.jakartaee-api + 10.0.0 + provided + + {{/jakarta}} + {{^jakarta}} javax.servlet servlet-api ${servlet-api-version} + {{/jakarta}} junit @@ -179,13 +204,37 @@ {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api ${beanvalidation-version} provided -{{/useBeanValidation}} + {{/jakarta}} +{{/useBeanValidation}} + {{#java8}} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-version} + + {{/java8}} + {{^java8}} + + com.fasterxml.jackson.datatype + jackson-datatype-joda + ${jackson-version} + + {{/java8}} @@ -197,18 +246,18 @@ - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} 1.5.18 9.2.9.v20150224 1.19.1 - 2.8.9 + 2.9.5 1.7.21 - 4.12 - 2.5 + 4.13.1 + {{#jakarta}}6.0.0{{/jakarta}}{{^jakarta}}2.5{{/jakarta}} {{#useBeanValidation}} - 1.1.0.Final + {{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}1.1.0.Final{{/jakarta}} {{/useBeanValidation}} UTF-8 diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/LocalDateProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/LocalDateProvider.mustache index 90a5fb6208..45a30ffee6 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/LocalDateProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/LocalDateProvider.mustache @@ -1,8 +1,15 @@ package {{apiPackage}}; +{{#jakarta}} +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; +{{/jakarta}} import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.time.LocalDate; @@ -25,4 +32,4 @@ public class LocalDateProvider implements ParamConverterProvider { } return null; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/OffsetDateTimeProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/OffsetDateTimeProvider.mustache index fccb0deb16..6ab5876892 100644 --- a/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/OffsetDateTimeProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/libraries/jersey2/OffsetDateTimeProvider.mustache @@ -1,8 +1,15 @@ package {{apiPackage}}; +{{#jakarta}} +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; +{{/jakarta}} import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.time.OffsetDateTime; @@ -25,4 +32,4 @@ public class OffsetDateTimeProvider implements ParamConverterProvider { } return null; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/model.mustache b/src/main/resources/handlebars/JavaJaxRS/model.mustache index 8cd0a87aa6..36b27798e7 100644 --- a/src/main/resources/handlebars/JavaJaxRS/model.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/model.mustache @@ -2,6 +2,7 @@ package {{package}}; +{{^x-is-composed-model}} {{^supportJava6}} import java.util.Objects; {{/supportJava6}} @@ -14,11 +15,24 @@ import org.apache.commons.lang3.ObjectUtils; import java.io.Serializable; {{/serializableModel}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +import jakarta.validation.Valid; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +import javax.validation.Valid; +{{/jakarta}} {{/useBeanValidation}} +{{/x-is-composed-model}} {{#models}} {{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#is this 'enum'}}{{>modelEnum}}{{/is}}{{#isNot this 'enum'}}{{>pojo}}{{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaJaxRS/modelEnum.mustache b/src/main/resources/handlebars/JavaJaxRS/modelEnum.mustache index e811e777f5..46cb7b4688 100644 --- a/src/main/resources/handlebars/JavaJaxRS/modelEnum.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/modelEnum.mustache @@ -9,12 +9,12 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum {{#if gson}} {{#allowableValues}}{{#enumVars}} @SerializedName({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/if}} {{#unless gson}} {{#allowableValues}}{{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/unless}} diff --git a/src/main/resources/handlebars/JavaJaxRS/pathParams.mustache b/src/main/resources/handlebars/JavaJaxRS/pathParams.mustache index b0a7d6fdde..f692904946 100644 --- a/src/main/resources/handlebars/JavaJaxRS/pathParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/pathParams.mustache @@ -1 +1 @@ -{{~#is this 'path-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file +{{~#is this 'path-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.PATH, description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) @PathParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/pojo.mustache b/src/main/resources/handlebars/JavaJaxRS/pojo.mustache index 0aafa7b8ae..68ebb507d0 100644 --- a/src/main/resources/handlebars/JavaJaxRS/pojo.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/pojo.mustache @@ -3,7 +3,7 @@ */{{#description}} {{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description = "{{{description}}}"){{/description}} {{>generatedAnnotation}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}{{#@first}},{{/@first}} {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#vars}} {{#baseItems this}} {{#is this 'enum'}} diff --git a/src/main/resources/handlebars/JavaJaxRS/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/pom.mustache index 4c33923098..2c3b9d0799 100644 --- a/src/main/resources/handlebars/JavaJaxRS/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/pom.mustache @@ -13,7 +13,7 @@ repo - + src/main/java @@ -53,11 +53,20 @@ {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + + {{/jakarta}} + {{^jakarta}} - javax.validation - validation-api - ${beanvalidation-version} + javax.validation + validation-api + ${beanvalidation-version} + {{/jakarta}} {{/useBeanValidation}} @@ -137,11 +146,27 @@ ${junit-version} test + {{#jakarta}} - javax.servlet - servlet-api - ${servlet-api-version} + jakarta.servlet + jakarta.servlet-api + ${servlet-api-version} + + + jakarta.platform + jakarta.jakartaee-api + 10.0.0 + provided + + {{/jakarta}} + {{^jakarta}} + + javax.servlet + servlet-api + ${servlet-api-version} + + {{/jakarta}} org.glassfish.jersey.containers jersey-container-servlet-core @@ -201,15 +226,30 @@ ${commons_io_version} {{/supportJava6}} - + {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + ${beanvalidation-version} + + + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api ${beanvalidation-version} - provided + {{/jakarta}} + {{/useBeanValidation}} @@ -223,7 +263,7 @@ - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} {{#useOas2}} @@ -239,11 +279,11 @@ 2.5 3.5 {{/supportJava6}} - 4.12 - 1.1.7 - 2.5 + 4.13.1 + 1.2.9 + {{#jakarta}}6.0.0{{/jakarta}}{{^jakarta}}2.5{{/jakarta}} {{#useBeanValidation}} - 1.1.0.Final + {{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}1.1.0.Final{{/jakarta}} {{/useBeanValidation}} UTF-8 diff --git a/src/main/resources/handlebars/JavaJaxRS/queryParams.mustache b/src/main/resources/handlebars/JavaJaxRS/queryParams.mustache index c5bf2d4b84..5ef6417229 100644 --- a/src/main/resources/handlebars/JavaJaxRS/queryParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/queryParams.mustache @@ -1 +1 @@ -{{#is this 'query-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file +{{#is this 'query-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.QUERY, description = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}){{#defaultValue}} @DefaultValue("{{{defaultValue}}}"){{/defaultValue}} @QueryParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiOriginFilter.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiOriginFilter.mustache index 090fd8cb55..f9ef60c3ee 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiOriginFilter.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiOriginFilter.mustache @@ -2,11 +2,17 @@ package {{apiPackage}}; import java.io.IOException; +{{#jakarta}} +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletResponse; +{{/jakarta}} +{{^jakarta}} import javax.servlet.*; import javax.servlet.http.HttpServletResponse; +{{/jakarta}} {{>generatedAnnotation}} -public class ApiOriginFilter implements javax.servlet.Filter { +public class ApiOriginFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = (HttpServletResponse) response; diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiResponseMessage.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiResponseMessage.mustache index f47a535094..5851bdd03f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiResponseMessage.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/ApiResponseMessage.mustache @@ -1,8 +1,15 @@ package {{apiPackage}}; +{{#jakarta}} +import jakarta.xml.bind.annotation.XmlTransient; + +@jakarta.xml.bind.annotation.XmlRootElement +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.XmlTransient; @javax.xml.bind.annotation.XmlRootElement +{{/jakarta}} {{>generatedAnnotation}} public class ApiResponseMessage { public static final int ERROR = 1; diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/JacksonConfig.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/JacksonConfig.mustache index 5a0da70233..abcbaac4e3 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/JacksonConfig.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/JacksonConfig.mustache @@ -5,13 +5,24 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; +{{#java8}} +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +{{/java8}} +{{#joda}} import com.fasterxml.jackson.datatype.joda.JodaModule; import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.joda.time.format.ISODateTimeFormat; +{{/joda}} +{{#jakarta}} +import jakarta.ws.rs.ext.ContextResolver; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; +{{/jakarta}} import java.io.IOException; @Provider @@ -21,7 +32,11 @@ public class JacksonConfig implements ContextResolver { public JacksonConfig() throws Exception { objectMapper = new ObjectMapper() - .setDateFormat(new RFC3339DateFormat()) + .setDateFormat(new RFC3339DateFormat()){{#legacyDates}};{{/legacyDates}} +{{#java8}} + .registerModule(new JavaTimeModule()); +{{/java8}} +{{#joda}} .registerModule(new JodaModule() { { addSerializer(DateTime.class, new StdSerializer(DateTime.class) { @@ -39,9 +54,10 @@ public class JacksonConfig implements ContextResolver { } }); +{{/joda}} } public ObjectMapper getContext(Class arg0) { return objectMapper; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaDateTimeProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaDateTimeProvider.mustache index 74c24c8777..b0a115a41f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaDateTimeProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaDateTimeProvider.mustache @@ -1,13 +1,22 @@ package {{apiPackage}}; import org.joda.time.DateTime; +{{#jakarta}} +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; +import jakarta.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; +{{/jakarta}} +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; @Provider @@ -36,4 +45,4 @@ public class JodaDateTimeProvider implements ParamConverterProvider { } return null; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaLocalDateProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaLocalDateProvider.mustache index 0b28c915dd..6d51e070a6 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaLocalDateProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/JodaLocalDateProvider.mustache @@ -1,13 +1,22 @@ package {{apiPackage}}; import org.joda.time.LocalDate; +{{#jakarta}} +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; +import jakarta.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; +{{/jakarta}} +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; @Provider @@ -36,4 +45,4 @@ public class JodaLocalDateProvider implements ParamConverterProvider { } return null; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/LocalDateProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/LocalDateProvider.mustache index a57e3e7475..86350d230e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/LocalDateProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/LocalDateProvider.mustache @@ -1,9 +1,16 @@ package {{apiPackage}}; import java.time.LocalDate; +{{#jakarta}} +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; +{{/jakarta}} import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -28,4 +35,4 @@ public class LocalDateProvider implements ParamConverterProvider { } return null; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/OffsetDateTimeProvider.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/OffsetDateTimeProvider.mustache index a3974c3c53..d3093bae45 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/OffsetDateTimeProvider.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/OffsetDateTimeProvider.mustache @@ -1,9 +1,16 @@ package {{apiPackage}}; import java.time.OffsetDateTime; +{{#jakarta}} +import jakarta.ws.rs.ext.ParamConverter; +import jakarta.ws.rs.ext.ParamConverterProvider; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; +{{/jakarta}} import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -28,4 +35,4 @@ public class OffsetDateTimeProvider implements ParamConverterProvider { } return null; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/README.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/README.mustache index 45ce075085..55614c33fb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/README.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/README.mustache @@ -10,7 +10,7 @@ This example uses the [JAX-RS](https://jax-rs-spec.java.net/) framework. To run the server, please execute the following: ``` -mvn clean package jetty:run +mvn clean package ``` You can then view the swagger listing here: diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/RestApplication.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/RestApplication.mustache index df9a31434b..74127894d7 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/RestApplication.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/RestApplication.mustache @@ -1,9 +1,15 @@ package {{invokerPackage}}; +{{#jakarta}} +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; +{{/jakarta}} @ApplicationPath("/") public class RestApplication extends Application { -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/api.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/api.mustache index d37b6b3936..63df307143 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/api.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/api.mustache @@ -27,14 +27,28 @@ import {{package}}.NotFoundException; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.ws.rs.*; +import jakarta.inject.Inject; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.*; import javax.inject.Inject; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{#operations}} {{#operation}} @@ -64,8 +78,8 @@ public class {{classname}} { {{#useOas2}} @io.swagger.annotations.ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnBaseType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { {{#authMethods}}@io.swagger.annotations.Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@io.swagger.annotations.AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}},{{/hasMore}} - {{/scopes}} + {{#each scopes}}@io.swagger.annotations.AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}},{{/@last}} + {{/each}} }{{/isOAuth}}){{#hasMore}},{{/hasMore}} {{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}",{{/vendorExtensions.x-tags}} }) @@ -77,18 +91,18 @@ public class {{classname}} { {{^useOas2}} @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}"{{scope}}"{{#hasMore}},{{/hasMore}} - {{/scopes}} + {{#each scopes}}"{{@key}}"{{^@last}},{{/@last}} + {{/each}} }{{/isOAuth}}){{#hasMore}},{{/hasMore}} {{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}}, + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}}, {{/hasMore}}{{/responses}} }) {{/useOas2}} - public Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{^isMultipart}}{{>formParams}},{{/isMultipart}}{{#isMultipart}}{{^isFormParam}},{{/isFormParam}}{{/isMultipart}}{{/parameters}}@Context SecurityContext securityContext) + public Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{>comma}}{{/parameters}}@Context SecurityContext securityContext) throws NotFoundException { - return service.{{nickname}}({{#isMultipart}}input,{{/isMultipart}}{{#parameters}}{{^isMultipart}}{{paramName}},{{/isMultipart}}{{#isMultipart}}{{^isFormParam}}{{paramName}},{{/isFormParam}}{{/isMultipart}}{{/parameters}}securityContext); + return service.{{nickname}}({{#isMultipart}}input,{{/isMultipart}}{{#parameters}}{{^isFormParam}}{{paramName}}{{/isFormParam}}{{#isFormParam}}{{^isBinary}}{{paramName}}{{/isBinary}}{{/isFormParam}}{{>comma}}{{/parameters}}securityContext); } {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/apiService.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/apiService.mustache index 83741b6ec0..1fe2bf110c 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/apiService.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/apiService.mustache @@ -9,20 +9,26 @@ import {{package}}.*; {{/imports}} import java.util.List; +import java.util.Map; import {{package}}.NotFoundException; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{>generatedAnnotation}} {{#operations}} public interface {{classname}}Service { {{#operation}} {{#contents}} - Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{^isMultipart}}{{>serviceFormParams}},{{/isMultipart}}{{#isMultipart}}{{^isFormParam}},{{/isFormParam}}{{/isMultipart}}{{/parameters}}SecurityContext securityContext) - throws NotFoundException; + Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>serviceQueryParams}}{{>serviceCookieParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>comma}}{{/parameters}}SecurityContext securityContext) throws NotFoundException; {{/contents}} {{/operation}} } diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/apiServiceImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/apiServiceImpl.mustache index aa22aae714..379ff2bf0e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/apiServiceImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/apiServiceImpl.mustache @@ -9,13 +9,21 @@ import {{package}}.*; {{/imports}} import java.util.List; +import java.util.Map; import {{package}}.NotFoundException; import java.io.InputStream; +{{#jakarta}} +import jakarta.enterprise.context.RequestScoped; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.enterprise.context.RequestScoped; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} @RequestScoped {{>generatedAnnotation}} @@ -23,7 +31,7 @@ import javax.ws.rs.core.SecurityContext; public class {{classname}}ServiceImpl implements {{classname}}Service { {{#operation}} {{#contents}} - public Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{^isMultipart}}{{>serviceFormParams}},{{/isMultipart}}{{#isMultipart}}{{^isFormParam}},{{/isFormParam}}{{/isMultipart}}{{/parameters}}SecurityContext securityContext) + public Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>serviceCookieParams}}{{>comma}}{{/parameters}}SecurityContext securityContext) throws NotFoundException { // do some magic! return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build(); diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/bodyParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/bodyParams.mustache index 3d22f0b06b..9ad8f3307e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/bodyParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/bodyParams.mustache @@ -1 +1,4 @@ -{{#is this 'body-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file +{{#is this 'body-param'}} +{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/comma.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/comma.mustache new file mode 100644 index 0000000000..5d8c1f9602 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/comma.mustache @@ -0,0 +1 @@ +{{^isFormParam}},{{/isFormParam}}{{#isFormParam}}{{^isBinary}},{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/cookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/cookieParams.mustache new file mode 100644 index 0000000000..c8dae79c63 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/cookieParams.mustache @@ -0,0 +1,4 @@ +{{#isCookieParam}} +{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{/isCookieParam}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/JacksonConfig.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/JacksonConfig.mustache index 923d26477d..e2eda9dc19 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/JacksonConfig.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/JacksonConfig.mustache @@ -1,9 +1,17 @@ package {{invokerPackage}}; +{{#jakarta}} +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.ext.ContextResolver; +import jakarta.ws.rs.ext.Provider; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; +{{/jakarta}} import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,4 +49,4 @@ public class JacksonConfig implements ContextResolver { public ObjectMapper getContext(Class objectType) { return objectMapper; } -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/RestApplication.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/RestApplication.mustache index f208b4e4da..1ddfaf8946 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/RestApplication.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/RestApplication.mustache @@ -1,7 +1,17 @@ package {{invokerPackage}}; +{{#jakarta}} +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; +import jakarta.servlet.ServletConfig; +import jakarta.ws.rs.core.Context; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; +import javax.servlet.ServletConfig; +import javax.ws.rs.core.Context; +{{/jakarta}} import java.util.Set; import java.util.HashSet; @@ -10,7 +20,6 @@ import java.util.HashSet; import io.swagger.jaxrs.config.BeanConfig; {{/useOas2}} {{^useOas2}} -import javax.servlet.ServletConfig; import io.swagger.v3.jaxrs2.integration.JaxrsOpenApiContextBuilder; import io.swagger.v3.oas.integration.OpenApiConfigurationException; import io.swagger.v3.oas.integration.SwaggerConfiguration; @@ -18,7 +27,6 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; -import javax.ws.rs.core.Context; import java.util.stream.Collectors; import java.util.stream.Stream; {{/useOas2}} @@ -98,4 +106,4 @@ public class RestApplication extends Application { -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/api.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/api.mustache index bc4925176e..a0a6c30bad 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/api.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/api.mustache @@ -25,12 +25,25 @@ import java.util.Map; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +import jakarta.ws.rs.*; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.*; +{{/jakarta}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{#operations}} {{#operation}} @@ -58,8 +71,8 @@ public interface {{classname}} { {{#useOas2}} @io.swagger.annotations.ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnBaseType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { {{#authMethods}}@io.swagger.annotations.Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@io.swagger.annotations.AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}@io.swagger.annotations.AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}",{{/vendorExtensions.x-tags}} }) @@ -70,17 +83,17 @@ public interface {{classname}} { {{^useOas2}} @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}"{{scope}}"{{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}"{{@key}}"{{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}} + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}} {{/responses}} }) {{/useOas2}} - Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{^isMultipart}}{{>formParams}},{{/isMultipart}}{{#isMultipart}}{{^isFormParam}},{{/isFormParam}}{{/isMultipart}}{{/parameters}}@Context SecurityContext securityContext); + Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{>comma}}{{/parameters}}@Context SecurityContext securityContext); {{/contents}} {{/operation}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/apiServiceImpl.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/apiServiceImpl.mustache index b37b1cf289..eeae9022e1 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/apiServiceImpl.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/apiServiceImpl.mustache @@ -9,18 +9,25 @@ import {{package}}.*; {{/imports}} import java.util.List; +import java.util.Map; import java.io.InputStream; +{{#jakarta}} +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +{{/jakarta}} {{>generatedAnnotation}} {{#operations}} public class {{classname}}ServiceImpl implements {{classname}} { {{#operation}} {{#contents}} - public Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{^isMultipart}}{{>serviceFormParams}},{{/isMultipart}}{{#isMultipart}}{{^isFormParam}},{{/isFormParam}}{{/isMultipart}}{{/parameters}}SecurityContext securityContext) { + public Response {{nickname}}({{#isMultipart}}MultipartFormDataInput input,{{/isMultipart}}{{#parameters}}{{>serviceQueryParams}}{{>servicePathParams}}{{>serviceHeaderParams}}{{>serviceBodyParams}}{{>serviceFormParams}}{{>serviceCookieParams}}{{>comma}}{{/parameters}}SecurityContext securityContext) { // do some magic! return Response.ok().build(); } diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/bodyParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/bodyParams.mustache index 3d22f0b06b..d9250c7e56 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/bodyParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/bodyParams.mustache @@ -1 +1 @@ -{{#is this 'body-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file +{{#is this 'body-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/comma.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/comma.mustache new file mode 100644 index 0000000000..5d8c1f9602 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/comma.mustache @@ -0,0 +1 @@ +{{^isFormParam}},{{/isFormParam}}{{#isFormParam}}{{^isBinary}},{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/cookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/cookieParams.mustache new file mode 100644 index 0000000000..c8dae79c63 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/cookieParams.mustache @@ -0,0 +1,4 @@ +{{#isCookieParam}} +{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}) {{{dataType}}} {{paramName}}{{/useOas2}} +{{/isCookieParam}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/enumClass.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/enumClass.mustache index ca4431a72a..f8f6502e0c 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/enumClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/enumClass.mustache @@ -4,9 +4,8 @@ public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, - - {{/@last}}{{#@last}}; + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, +{{/@last}}{{#@last}}; {{/@last}} {{/enumVars}} {{/allowableValues}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/formParams.mustache index 8039a30433..52ddceda5d 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/formParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/isNot}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/isNot}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/generatedAnnotation.mustache index a47b6faa85..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/generatedAnnotation.mustache @@ -1 +1 @@ -{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/gradle.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/gradle.mustache index 60f4d69117..672e74726f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/gradle.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/gradle.mustache @@ -8,23 +8,24 @@ repositories { } dependencies { - providedCompile 'org.jboss.resteasy:resteasy-jaxrs:3.0.11.Final' - providedCompile 'org.jboss.resteasy:jaxrs-api:3.0.11.Final' - providedCompile 'org.jboss.resteasy:resteasy-validator-provider-11:3.0.11.Final' - providedCompile 'org.jboss.resteasy:resteasy-multipart-provider:3.0.11.Final' - providedCompile 'javax.annotation:javax.annotation-api:1.2' + providedCompile 'org.jboss.resteasy:resteasy-jaxrs:3.15.6.Final' + providedCompile 'org.jboss.resteasy:jaxrs-api:3.0.12.Final' + providedCompile 'org.jboss.resteasy:resteasy-validator-provider-11:3.6.3.Final' + providedCompile 'org.jboss.resteasy:resteasy-multipart-provider:3.15.6.Final' + providedCompile 'jakarta.annotation:jakarta.annotation-api:{{#jakarta}}2.1.1{{/jakarta}}{{^jakarta}}1.3.5{{/jakarta}}' providedCompile 'org.jboss.spec.javax.servlet:jboss-servlet-api_3.0_spec:1.0.0.Final' - compile 'org.jboss.resteasy:resteasy-jackson2-provider:3.0.11.Final' + compile 'org.jboss.resteasy:resteasy-jackson2-provider:3.15.6.Final' {{#useBeanValidation}} - providedCompile 'javax.validation:validation-api:1.1.0.Final' + providedCompile 'jakarta.validation:jakarta.validation-api:{{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}2.0.2{{/jakarta}}' {{/useBeanValidation}} {{^java8}} - compile 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.6.3' + compile 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.10.1' compile 'joda-time:joda-time:2.7' {{/java8}} {{#java8}} - compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.3' + compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.1' {{/java8}} + compile 'com.fasterxml.jackson.core:jackson-databind:2.10.1' testCompile 'junit:junit:4.12', 'org.hamcrest:hamcrest-core:1.3' } diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/headerParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/headerParams.mustache index 7b9d478841..2df32600fa 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/headerParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/headerParams.mustache @@ -1 +1 @@ -{{#is this 'header-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file +{{#is this 'header-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/interface.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/interface.mustache new file mode 100644 index 0000000000..abec32f768 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/interface.mustache @@ -0,0 +1,11 @@ +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/model.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/model.mustache index cb48311dff..8c70a27988 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/model.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/model.mustache @@ -1,22 +1,35 @@ package {{package}}; +{{^x-is-composed-model}} import java.util.Objects; import java.util.ArrayList; +import java.util.HashMap; {{#imports}}import {{import}}; {{/imports}} {{#serializableModel}} import java.io.Serializable; {{/serializableModel}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} +{{/x-is-composed-model}} {{#models}} {{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#is this 'enum'}} {{>enumOuterClass}} {{/is}} {{#isNot this 'enum'}} {{>pojo}} {{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pojo.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pojo.mustache index 3ce788e6fe..3e760e8201 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pojo.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pojo.mustache @@ -7,7 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema; {{#description}}{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}{{/useOas2}}@Schema(description="{{{description}}}"){{/description}} {{>generatedAnnotation}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#serializableModel}} private static final long serialVersionUID = 1L; {{/serializableModel}} @@ -40,7 +40,7 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#seriali @Schema({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}") {{/useOas2}} @JsonProperty("{{baseName}}") -{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { +{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; } public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pom.mustache index b21e1e251d..0c755fa3e5 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/pom.mustache @@ -14,8 +14,8 @@ maven-compiler-plugin 3.6.1 - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} @@ -97,11 +97,20 @@ slf4j-log4j12 ${slf4j-version} + {{#jakarta}} + jakarta.servlet + jakarta.servlet-api + ${servlet-api-version} + + {{/jakarta}} + {{^jakarta}} + javax.servlet servlet-api ${servlet-api-version} + {{/jakarta}} org.jboss.resteasy @@ -111,17 +120,17 @@ org.jboss.resteasy resteasy-servlet-initializer - ${resteasy-version} + 6.2.3.Final org.jboss.resteasy jaxrs-api - ${resteasy-version} + 3.0.12.Final org.jboss.resteasy resteasy-validator-provider-11 - ${resteasy-version} + 3.6.3.Final org.jboss.resteasy @@ -133,11 +142,20 @@ resteasy-jackson2-provider ${resteasy-version} + {{#jakarta}} + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + + {{/jakarta}} + {{^jakarta}} javax.annotation javax.annotation-api 1.2 + {{/jakarta}} {{#useOas2}} io.swagger @@ -180,11 +198,20 @@ {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final + {{/jakarta}} {{/useBeanValidation}} {{^java8}} @@ -195,30 +222,30 @@ com.fasterxml.jackson.datatype jackson-datatype-joda - 2.6.3 + 2.10.1 {{/java8}} {{#java8}} com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.6.3 + 2.10.1 {{/java8}} com.fasterxml.jackson.core jackson-databind - 2.6.3 + 2.10.1 com.fasterxml.jackson.core jackson-core - 2.6.3 + 2.10.1 com.fasterxml.jackson.core jackson-annotations - 2.6.3 + 2.10.1 org.apache.httpcomponents @@ -244,10 +271,10 @@ {{^useOas2}} 2.0.0 {{/useOas2}} - 9.2.9.v20150224 - 3.0.11.Final + 9.3.27.v20190418 + 3.15.6.Final 1.6.3 - 4.8.1 - 2.5 + 4.13.1 + {{#jakarta}}6.0.0{{/jakarta}}{{^jakarta}}2.5{{/jakarta}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceCookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceCookieParams.mustache new file mode 100644 index 0000000000..70871f0f8c --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceCookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{{dataType}}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceFormParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceFormParams.mustache index 5bc6d7c5d4..610b6059ac 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceFormParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/eap/serviceFormParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}}FormDataContentDisposition fileDetail{{/is}}{{/is}} \ No newline at end of file +{{#isFormParam}}{{^isBinary}}{{{dataType}}} {{paramName}}{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/enumClass.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/enumClass.mustache index ca4431a72a..f8f6502e0c 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/enumClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/enumClass.mustache @@ -4,9 +4,8 @@ public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, - - {{/@last}}{{#@last}}; + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, +{{/@last}}{{#@last}}; {{/@last}} {{/enumVars}} {{/allowableValues}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/enumOuterClass.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/enumOuterClass.mustache index fd5a5a3f5f..8b6b0b1127 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/enumOuterClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/enumOuterClass.mustache @@ -1,3 +1,23 @@ -public enum {{classname}} { - {{#allowableValues}}{{.}}{{^@last}}, {{/@last}}{{/allowableValues}} +/** o.O +* {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} +*/ +public enum {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { + {{#allowableValues}} + {{#enumVars}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, +{{/@last}}{{#@last}}; + {{/@last}} + {{/enumVars}} + {{/allowableValues}} + private {{dataType}} value; + + {{#datatypeWithEnum}}{{.}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}({{dataType}} value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } } \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/formParams.mustache index 8039a30433..52ddceda5d 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/formParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/isNot}}{{/is}} \ No newline at end of file +{{#is this 'form-param'}}{{#isNot this 'binary'}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}})@FormParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/isNot}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/generatedAnnotation.mustache index a47b6faa85..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/generatedAnnotation.mustache @@ -1 +1 @@ -{{^hideGenerationTimestamp}}@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/gradle.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/gradle.mustache index 47af212cf4..8a02257f2b 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/gradle.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/gradle.mustache @@ -8,11 +8,11 @@ repositories { } dependencies { - providedCompile 'org.jboss.resteasy:resteasy-jaxrs:3.0.11.Final' - providedCompile 'org.jboss.resteasy:jaxrs-api:3.0.11.Final' + providedCompile 'org.jboss.resteasy:resteasy-jaxrs:3.15.6.Final' + providedCompile 'org.jboss.resteasy:jaxrs-api:3.0.12.Final' providedCompile 'org.jboss.resteasy:resteasy-validator-provider-11:3.0.11.Final' - providedCompile 'org.jboss.resteasy:resteasy-multipart-provider:3.0.11.Final' - providedCompile 'javax.annotation:javax.annotation-api:1.2' + providedCompile 'org.jboss.resteasy:resteasy-multipart-provider:3.15.6.Final' + providedCompile 'jakarta.annotation:jakarta.annotation-api:{{#jakarta}}2.1.1{{/jakarta}}{{^jakarta}}1.3.5{{/jakarta}}' providedCompile 'javax:javaee-api:7.0' providedCompile 'org.jboss.spec.javax.servlet:jboss-servlet-api_3.0_spec:1.0.0.Final' {{#useOas2}} @@ -21,18 +21,25 @@ dependencies { {{^useOas2}} compile 'io.swagger.core.v3:swagger-annotations:2.0.0' {{/useOas2}} - compile 'org.jboss.resteasy:resteasy-jackson2-provider:3.0.11.Final' + compile 'org.jboss.resteasy:resteasy-jackson2-provider:3.15.6.Final' + compile 'org.apache.httpcomponents:httpclient:4.5.10' {{#useBeanValidation}} - providedCompile 'javax.validation:validation-api:1.1.0.Final' + providedCompile 'jakarta.validation:jakarta.validation-api:{{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}2.0.2{{/jakarta}}' {{/useBeanValidation}} - compile 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.4.1' +{{^java8}} + compile 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.10.1' compile 'joda-time:joda-time:2.7' +{{/java8}} +{{#java8}} + compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.1' +{{/java8}} + compile 'com.fasterxml.jackson.core:jackson-databind:2.10.1' //TODO: swaggerFeature {{#useOas2}} compile 'io.swagger:swagger-jaxrs:1.5.12' {{/useOas2}} {{^useOas2}} - compile 'io.swagger.core.v3:swagger-jaxrs2:2.0.0' + compile 'io.swagger.core.v3:swagger-jaxrs2:2.0.9' {{/useOas2}} testCompile 'junit:junit:4.12', diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/headerParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/headerParams.mustache index 7b9d478841..2df32600fa 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/headerParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/headerParams.mustache @@ -1 +1 @@ -{{#is this 'header-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file +{{#is this 'header-param'}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}})@HeaderParam("{{baseName}}") {{{dataType}}} {{paramName}}{{/useOas2}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/interface.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/interface.mustache new file mode 100644 index 0000000000..2ee7870910 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/interface.mustache @@ -0,0 +1,22 @@ +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; // +{{/jackson}} +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +{{#jackson}} +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{#discriminator}}{{#propertyName}}{{propertyName}}{{/propertyName}}{{^propertyName}}type{{/propertyName}}{{/discriminator}}{{^discriminator}}type{{/discriminator}}") + @JsonSubTypes({ + {{#subTypes}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{classname}}"){{^@last}},{{/@last}} + {{/subTypes}} +}) +{{/jackson}} +public interface {{{classname}}} { +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/model.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/model.mustache index cb48311dff..8c70a27988 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/model.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/model.mustache @@ -1,22 +1,35 @@ package {{package}}; +{{^x-is-composed-model}} import java.util.Objects; import java.util.ArrayList; +import java.util.HashMap; {{#imports}}import {{import}}; {{/imports}} {{#serializableModel}} import java.io.Serializable; {{/serializableModel}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} +{{/x-is-composed-model}} {{#models}} {{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#is this 'enum'}} {{>enumOuterClass}} {{/is}} {{#isNot this 'enum'}} {{>pojo}} {{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/pojo.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/pojo.mustache index 42439dc03e..16c9530a7d 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/pojo.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/pojo.mustache @@ -7,7 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema; {{#description}}{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description="{{{description}}}"){{/description}} {{>generatedAnnotation}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#serializableModel}} private static final long serialVersionUID = 1L; {{/serializableModel}} @@ -35,7 +35,7 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#seriali @Schema({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}") {{/useOas2}} @JsonProperty("{{baseName}}") -{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{#is this 'boolean'}}is{{/is}}{{getter}}() { +{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; } public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/pom.mustache index 57cf4c95aa..8d52ff3998 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/pom.mustache @@ -14,8 +14,8 @@ maven-compiler-plugin 3.6.1 - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} @@ -59,12 +59,22 @@ + {{#jakarta}} + + jakarta.platform + jakarta.jakartaee-api + 10.0.0 + provided + + {{/jakarta}} + {{^jakarta}} javax javaee-api 7.0 provided + {{/jakarta}} {{#useOas2}} io.swagger @@ -84,12 +94,22 @@ slf4j-log4j12 ${slf4j-version} + {{#jakarta}} + + jakarta.servlet + jakarta.servlet-api + ${servlet-api-version} + provided + + {{/jakarta}} + {{^jakarta}} javax.servlet servlet-api ${servlet-api-version} provided + {{/jakarta}} org.jboss.resteasy @@ -100,12 +120,12 @@ org.jboss.resteasy jaxrs-api - ${resteasy-version} + 3.0.12.Final org.jboss.resteasy resteasy-validator-provider-11 - ${resteasy-version} + 3.6.3.Final provided @@ -120,13 +140,30 @@ ${resteasy-version} provided + {{#jakarta}} + + jakarta.annotation + jakarta.annotation-api + 2.1.1 + provided + + {{/jakarta}} + {{^jakarta}} javax.annotation javax.annotation-api 1.2 provided - + {{/jakarta}} +{{#java8}} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson-version} + +{{/java8}} +{{^java8}} com.fasterxml.jackson.datatype jackson-datatype-joda @@ -137,6 +174,7 @@ joda-time 2.7 +{{/java8}} {{#useOas2}} io.swagger @@ -177,14 +215,30 @@ + + org.apache.httpcomponents + httpclient + 4.5.10 + test + {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} @@ -202,12 +256,13 @@ 1.5.18 {{/useOas2}} {{^useOas2}} - 2.0.0 + 2.0.9 {{/useOas2}} - 9.2.9.v20150224 - 3.0.11.Final + 9.3.27.v20190418 + 3.15.6.Final 1.6.3 - 4.8.1 - 2.5 + 4.13.1 + {{#jakarta}}6.0.0{{/jakarta}}{{^jakarta}}2.5{{/jakarta}} + {{#java8}}2.10.1{{/java8}} diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceCookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceCookieParams.mustache new file mode 100644 index 0000000000..70871f0f8c --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceCookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{{dataType}}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceFormParams.mustache b/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceFormParams.mustache index 5bc6d7c5d4..610b6059ac 100644 --- a/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceFormParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/resteasy/serviceFormParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}}FormDataContentDisposition fileDetail{{/is}}{{/is}} \ No newline at end of file +{{#isFormParam}}{{^isBinary}}{{{dataType}}} {{paramName}}{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/serviceCookieParams.mustache b/src/main/resources/handlebars/JavaJaxRS/serviceCookieParams.mustache new file mode 100644 index 0000000000..70871f0f8c --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/serviceCookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{{dataType}}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/serviceFormParams.mustache b/src/main/resources/handlebars/JavaJaxRS/serviceFormParams.mustache index a88f3c0a18..56d43d61c5 100644 --- a/src/main/resources/handlebars/JavaJaxRS/serviceFormParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/serviceFormParams.mustache @@ -1 +1 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}{{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}}InputStream {{paramName}}InputStream, FormDataContentDisposition {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file +{{#isFormParam}}{{^isBinary}}{{{dataType}}} {{paramName}}{{/isBinary}}{{#isBinary}}java.io.InputStream {{paramName}}InputStream, FormDataContentDisposition {{paramName}}Detail{{/isBinary}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/RestApplication.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/RestApplication.mustache index 82b8d9533e..74127894d7 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/RestApplication.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/RestApplication.mustache @@ -1,7 +1,13 @@ package {{invokerPackage}}; +{{#jakarta}} +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; +{{/jakarta}} @ApplicationPath("/") public class RestApplication extends Application { diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/api.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/api.mustache index 305d2ac928..e942aa61e7 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/api.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/api.mustache @@ -3,8 +3,14 @@ package {{package}}; {{#imports}}import {{import}}; {{/imports}} +{{#jakarta}} +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Response; +{{/jakarta}} +{{^jakarta}} import javax.ws.rs.*; import javax.ws.rs.core.Response; +{{/jakarta}} {{#useOas2}} import io.swagger.annotations.*; @@ -22,8 +28,16 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import java.util.Map; import java.util.List; -{{#useBeanValidation}}import javax.validation.constraints.*; -import javax.validation.Valid;{{/useBeanValidation}} +{{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +import jakarta.validation.Valid; +{{/jakarta}} +{{^jakarta}} +import javax.validation.constraints.*; +import javax.validation.Valid; +{{/jakarta}} +{{/useBeanValidation}} @Path("/{{{baseName}}}") {{#useOas2}} @@ -40,4 +54,4 @@ import javax.validation.Valid;{{/useBeanValidation}} {{/contents}} {{/operation}} } -{{/operations}} \ No newline at end of file +{{/operations}} diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/apiInterface.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/apiInterface.mustache index 44d1e42a1b..5dfb24aec6 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/apiInterface.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/apiInterface.mustache @@ -5,8 +5,8 @@ {{#useOas2}} @ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}"{{#hasAuthMethods}}, authorizations = { {{#authMethods}}@Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}@AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @@ -16,12 +16,12 @@ {{^useOas2}} @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}"{{scope}}"{{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}"{{@key}}"{{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) {{/useOas2}} {{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{>returnTypeInterface}}{{/returnResponse}} {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}); \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/apiMethod.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/apiMethod.mustache index f21aa3e1dc..f26291c341 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/apiMethod.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/apiMethod.mustache @@ -5,8 +5,8 @@ {{#useOas2}} @ApiOperation(value = "{{{summary}}}", notes = "{{{notes}}}", response = {{{returnBaseType}}}.class{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { {{#authMethods}}@Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}@AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @@ -17,13 +17,13 @@ {{^useOas2}} @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}"{{scope}}"{{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#each scopes}}"{{@key}}"{{^@last}}, + {{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) @ApiResponses(value = { {{#responses}} - @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}},{{/hasMore}}{{/responses}} }) {{/useOas2}} public Response {{nickname}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/enumClass.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/enumClass.mustache index e01687ee5d..38804c59c3 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/enumClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/enumClass.mustache @@ -1,7 +1,7 @@ public enum {{datatypeWithEnum}} { {{#allowableValues}} - {{#enumVars}}{{name}}({{datatype}}.valueOf({{{value}}})){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}} + {{#enumVars}}{{name}}({{#value}}{{datatype}}.valueOf({{{value}}}){{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}} {{/allowableValues}} @@ -28,6 +28,6 @@ public enum {{datatypeWithEnum}} { return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/enumOuterClass.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/enumOuterClass.mustache index 0d33f1f57f..3da2b752ee 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/enumOuterClass.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/enumOuterClass.mustache @@ -10,12 +10,12 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum {{#if gson}} {{#allowableValues}}{{#enumVars}} @SerializedName({{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}{{{value}}}{{#is ../../this 'integer'}}"{{/is}}{{#is ../../this 'double'}}"{{/is}}{{#is ../../this 'long'}}"{{/is}}{{#is ../../this 'float'}}"{{/is}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/if}} {{#unless gson}} {{#allowableValues}}{{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/unless}} @@ -38,6 +38,6 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/formParams.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/formParams.mustache index b29f25b3ed..aeb477b05f 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/formParams.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/formParams.mustache @@ -1,2 +1,2 @@ -{{#is this 'form-param'}}{{#isNot this 'file'}}@FormParam(value = "{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'file'}} @FormParam(value = "{{baseName}}") InputStream {{paramName}}InputStream, +{{#is this 'form-param'}}{{#isNot this 'binary'}}@FormParam(value = "{{baseName}}") {{{dataType}}} {{paramName}}{{/isNot}}{{#is this 'binary'}} @FormParam(value = "{{baseName}}") InputStream {{paramName}}InputStream, @FormParam(value = "{{baseName}}") Attachment {{paramName}}Detail{{/is}}{{/is}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/generatedAnnotation.mustache index ad17a426e9..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/generatedAnnotation.mustache @@ -1,3 +1 @@ -{{^hideGenerationTimestamp}} -@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}") -{{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/interface.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/interface.mustache new file mode 100644 index 0000000000..abec32f768 --- /dev/null +++ b/src/main/resources/handlebars/JavaJaxRS/spec/interface.mustache @@ -0,0 +1,11 @@ +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/model.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/model.mustache index 9ff78cba4f..67a3c2dd73 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/model.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/model.mustache @@ -1,17 +1,30 @@ package {{package}}; +{{^x-is-composed-model}} {{#imports}}import {{import}}; {{/imports}} {{#serializableModel}} import java.io.Serializable; {{/serializableModel}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.constraints.*; +import jakarta.validation.Valid; +{{/jakarta}} +{{^jakarta}} import javax.validation.constraints.*; import javax.validation.Valid; +{{/jakarta}} {{/useBeanValidation}} +{{/x-is-composed-model}} {{#models}} -{{#model}}{{#description}} +{{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} +{{#description}} /** * {{description}} **/{{/description}} @@ -19,5 +32,6 @@ import javax.validation.Valid; {{>enumOuterClass}} {{/is}} {{#isNot this 'enum'}}{{>pojo}}{{/isNot}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/pojo.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/pojo.mustache index f3c48ec83d..e3db26923a 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/pojo.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/pojo.mustache @@ -3,21 +3,14 @@ import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; {{#description}}{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description = "{{{description}}}"){{/description}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#vars}} + + {{#baseItems this}} {{#isEnum}} - {{^isContainer}} {{>enumClass}} - {{/isContainer}} {{/isEnum}} - {{#items.isEnum}} - {{#items}} - - {{^isContainer}} - {{>enumClass}} - {{/isContainer}} - {{/items}} - {{/items.isEnum}} + {{/baseItems}} private {{#useBeanValidation}}@Valid{{/useBeanValidation}} {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}}; {{/vars}} @@ -45,7 +38,7 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#seriali {{>beanValidation}} {{/useBeanValidation}} - public {{{datatypeWithEnum}}} {{#isBoolean}}is{{/isBoolean}}{{getter}}() { + public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; } public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { diff --git a/src/main/resources/handlebars/JavaJaxRS/spec/pom.mustache b/src/main/resources/handlebars/JavaJaxRS/spec/pom.mustache index 4a8ef3c614..189ac51a9e 100644 --- a/src/main/resources/handlebars/JavaJaxRS/spec/pom.mustache +++ b/src/main/resources/handlebars/JavaJaxRS/spec/pom.mustache @@ -35,13 +35,41 @@ {{/interfaceOnly}} + {{#java11}} + + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + + {{/java11}} + {{#jakarta}} + + jakarta.ws.rs + jakarta.ws.rs-api + 3.1.0 + provided + + {{/jakarta}} + {{^jakarta}} javax.ws.rs javax.ws.rs-api 2.0 provided + {{/jakarta}} {{#useOas2}} io.swagger @@ -86,15 +114,29 @@ {{/interfaceOnly}} {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} - 4.8.1 + {{#java11}} + 11 + 11 + {{/java11}} + 4.13.1 diff --git a/src/main/resources/handlebars/JavaMicronaut/README.mustache b/src/main/resources/handlebars/JavaMicronaut/README.mustache new file mode 100644 index 0000000000..4df8ce92a7 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/README.mustache @@ -0,0 +1,18 @@ +# Swagger generated API stub + +Micronaut stub + + +## Overview +This code was generated by the [swagger-codegen-micronaut-generator](https://github.com/franz-see/swagger-codegen-micronaut-generator) project. +By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate an API stub. +This is an example of building API stub interfaces in Java using the Micronaut framework. + +The stubs generated can be used in your existing Micronaut application to create controller endpoints +by adding ```@Controller``` classes that implement the interface. Eg: +```java +@Controller +public class PetController implements PetApi { +// implement all PetApi methods +} +``` diff --git a/src/main/resources/mustache/JavaSpring/libraries/spring-boot/RFC3339DateFormat.mustache b/src/main/resources/handlebars/JavaMicronaut/RFC3339DateFormat.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/libraries/spring-boot/RFC3339DateFormat.mustache rename to src/main/resources/handlebars/JavaMicronaut/RFC3339DateFormat.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/api.mustache b/src/main/resources/handlebars/JavaMicronaut/api.mustache new file mode 100644 index 0000000000..2bc0e282ba --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/api.mustache @@ -0,0 +1,75 @@ +/** + * NOTE: This class is auto generated by the swagger code generator program ({{{generatorVersion}}}). + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micronaut.http.*; +import io.micronaut.http.annotation.*; +{{#useRxJava3}} +import io.reactivex.rxjava3.core.Single; +{{/useRxJava3}} +{{^useRxJava3}} +{{#useRxJava2}} +import io.reactivex.Single; +{{/useRxJava2}} +{{/useRxJava3}} +import io.swagger.v3.oas.annotations.*; +import io.swagger.v3.oas.annotations.responses.*; +{{#useReactor}} +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +{{/useReactor}} + +{{#useBeanValidation}} +{{#jakarta}} +import jakarta.annotation.Nullable; +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} +import javax.annotation.Nullable; +import javax.validation.Valid; +import javax.validation.constraints.*; +{{/jakarta}} +{{/useBeanValidation}} +import java.io.IOException; +import java.util.List; +import java.util.Map; +{{#useOptional}} +import java.util.Optional; +{{/useOptional}} + +{{>generatedAnnotation}} +{{#operations}} +public interface {{classname}} { + +{{#operation}} +{{#contents}} + + @Operation(summary = "{{{summary}}}", operationId = "{{{operationId}}}", description = "{{{notes}}}" {{#vendorExtensions.x-tags}}{{#@first}}, tags = {{braces "left"}}{{/@first}}"{{tag}}"{{^@last}}, {{/@last}}{{#@last}}{{braces "right"}}{{/@last}}{{/vendorExtensions.x-tags}}) + {{#responses}} + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}") + {{/responses}} + {{#implicitHeaders}} + @ApiImplicitParams({ + {{#headerParams}} + {{>implicitHeader}} + {{/headerParams}} + }) + {{/implicitHeaders}} + @{{#lambda.capitalise}}{{httpMethod}}{{/lambda.capitalise}}(value = "{{{path}}}"{{#hasProduces}}, produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }{{/hasProduces}}{{#hasConsumes}}, consumes = {{braces "left"}}{{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}{{braces "right"}}{{/hasConsumes}}) + default SinglereturnTypes}}>> {{operationId}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { + return {{^useReactor}}Single{{/useReactor}}{{#useReactor}}Mono{{/useReactor}}.fromCallable(() -> { + throw new UnsupportedOperationException(); + }); + } + +{{/contents}} +{{/operation}} +} +{{/operations}} diff --git a/src/main/resources/handlebars/JavaMicronaut/apiController.mustache b/src/main/resources/handlebars/JavaMicronaut/apiController.mustache new file mode 100644 index 0000000000..4cdc59424e --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/apiController.mustache @@ -0,0 +1,55 @@ +package {{package}}; + +{{#imports}} +import {{import}}; + +{{/imports}} +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.HttpResponse; +{{#useRxJava3}} +import io.reactivex.rxjava3.core.Single; +{{/useRxJava3}} +{{^useRxJava3}} +{{#useRxJava2}} +import io.reactivex.Single; +{{/useRxJava2}} +{{/useRxJava3}} +{{#useReactor}} +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +{{/useReactor}} + +{{#useBeanValidation}} +import javax.annotation.Nullable; +import javax.validation.Valid; +import javax.validation.constraints.*; +{{/useBeanValidation}} +import java.util.List; +import java.util.Map; +{{#useOptional}} +import java.util.Optional; +{{/useOptional}} + +{{#operations}} +@Controller +public class {{classname}}Controller implements {{classname}} { +{{#operation}} +{{#contents}} + + @Override + public SinglereturnTypes}}>> {{operationId}}({{#parameters}}{{#useBeanValidation}}{{! + Bean validation spec for path parameters (PathParam is always required) +}}{{#isPathParam}}{{>beanValidationParams}}{{/isPathParam}}{{! + Bean validation spec for any other parameters +}}{{^isPathParam}}{{>nullableBeanValidationParams}}{{/isPathParam}}{{/useBeanValidation}}{{! + Method argument type and name +}}{{>optionalDataType}} {{paramName}}{{! + Arguments separator, if required +}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { + // TODO: Implement me + return {{classname}}.super.{{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); + } +{{/contents}} +{{/operation}} +} +{{/operations}} \ No newline at end of file diff --git a/src/main/resources/mustache/JavaSpring/apiException.mustache b/src/main/resources/handlebars/JavaMicronaut/apiException.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/apiException.mustache rename to src/main/resources/handlebars/JavaMicronaut/apiException.mustache diff --git a/src/main/resources/mustache/JavaSpring/apiResponseMessage.mustache b/src/main/resources/handlebars/JavaMicronaut/apiResponseMessage.mustache similarity index 92% rename from src/main/resources/mustache/JavaSpring/apiResponseMessage.mustache rename to src/main/resources/handlebars/JavaMicronaut/apiResponseMessage.mustache index 17b155f3b6..48bf21090d 100644 --- a/src/main/resources/mustache/JavaSpring/apiResponseMessage.mustache +++ b/src/main/resources/handlebars/JavaMicronaut/apiResponseMessage.mustache @@ -1,9 +1,6 @@ package {{apiPackage}}; -import javax.xml.bind.annotation.XmlTransient; - {{>generatedAnnotation}} -@javax.xml.bind.annotation.XmlRootElement public class ApiResponseMessage { public static final int ERROR = 1; public static final int WARNING = 2; @@ -42,7 +39,6 @@ public class ApiResponseMessage { this.message = message; } - @XmlTransient public int getCode() { return code; } diff --git a/src/main/resources/handlebars/JavaMicronaut/api_test.mustache b/src/main/resources/handlebars/JavaMicronaut/api_test.mustache new file mode 100644 index 0000000000..a3f012f24b --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/api_test.mustache @@ -0,0 +1,45 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import org.junit.jupiter.api.Test; +{{#useReactor}} +import reactor.core.publisher.Mono; +{{/useReactor}} +import jakarta.inject.Inject; + +import java.util.*; + +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +@MicronautTest +class {{classname}}ControllerTest { + + @Inject + private {{classname}} api; + + {{#operations}} + {{#operation}} + {{#contents}} + {{#@first}} + @Test + void {{operationId}}{{#isForm}}Form{{/isForm}}Test() { + {{#parameters}} + {{{dataType}}} {{paramName}} = null; + {{/parameters}} + try { + //TODO: {{#useReactor}}Mono.from({{/useReactor}}api.{{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}){{#useReactor}}){{/useReactor}}{{^useReactor}}.blockingGet();{{/useReactor}}{{#useReactor}}.block();{{/useReactor}} + } catch (UnsupportedOperationException e) { + assumeTrue(false, "API is not yet implemented"); + } + } + + {{/@first}} + {{/contents}} + {{/operation}} + {{/operations}} +} diff --git a/src/main/resources/handlebars/JavaMicronaut/application.mustache b/src/main/resources/handlebars/JavaMicronaut/application.mustache new file mode 100644 index 0000000000..82c91ba45f --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/application.mustache @@ -0,0 +1,22 @@ +micronaut: + application: + name: {{artifactId}} + router: + static-resources: + swagger: + paths: classpath:META-INF/swagger + mapping: /swagger/** + server: + cors: + enabled: true + configurations: + web: + allowedOrigins: * + allowedMethods: + - GET + - POST + - DELETE + - PUT + allowedHeaders: + - Content-Type + - Authorization \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/beanValidation.mustache b/src/main/resources/handlebars/JavaMicronaut/beanValidation.mustache new file mode 100644 index 0000000000..0894c7cdbc --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/beanValidation.mustache @@ -0,0 +1,6 @@ +{{#required}} + @NotNull +{{/required}}{{#isContainer}}{{^isPrimitiveType}}{{^isEnum}} + @Valid{{/isEnum}}{{/isPrimitiveType}}{{/isContainer}}{{#isNotContainer}}{{^isPrimitiveType}} + @Valid{{/isPrimitiveType}}{{/isNotContainer}} +{{>beanValidationCore}} \ No newline at end of file diff --git a/src/main/resources/mustache/JavaSpring/beanValidationCore.mustache b/src/main/resources/handlebars/JavaMicronaut/beanValidationCore.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/beanValidationCore.mustache rename to src/main/resources/handlebars/JavaMicronaut/beanValidationCore.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/beanValidationParams.mustache b/src/main/resources/handlebars/JavaMicronaut/beanValidationParams.mustache new file mode 100644 index 0000000000..b01b404811 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/beanValidationParams.mustache @@ -0,0 +1 @@ +{{#useBeanValidation}}{{>beanValidationParamsInner}}{{>beanValidationCore}}{{/useBeanValidation}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/beanValidationParamsInner.mustache b/src/main/resources/handlebars/JavaMicronaut/beanValidationParamsInner.mustache new file mode 100644 index 0000000000..aaa696691e --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/beanValidationParamsInner.mustache @@ -0,0 +1,5 @@ +{{^isPrimitiveType}}{{^isEnum}}{{! + Non-container +}}{{^isContainer}}@Valid {{/isContainer}}{{! + Container +}}{{#isContainer}}{{#items}}{{>beanValidationParamsInner}}{{/items}}{{/isContainer}}{{/isEnum}}{{/isPrimitiveType}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/bodyParams.mustache b/src/main/resources/handlebars/JavaMicronaut/bodyParams.mustache new file mode 100644 index 0000000000..8bd655d9fa --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/bodyParams.mustache @@ -0,0 +1 @@ +{{#isBodyParam}}{{>nullableBeanValidationParams}}@Parameter(description = "{{{description}}}") @Body {{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/cookieParams.mustache b/src/main/resources/handlebars/JavaMicronaut/cookieParams.mustache new file mode 100644 index 0000000000..9e4c72a8ab --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/cookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{>nullableBeanValidationParams}}@Parameter(description = "{{{description}}}") @CookieValue(value="{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/mustache/JavaSpring/customInstantDeserializer.mustache b/src/main/resources/handlebars/JavaMicronaut/customInstantDeserializer.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/customInstantDeserializer.mustache rename to src/main/resources/handlebars/JavaMicronaut/customInstantDeserializer.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/enumClass.mustache b/src/main/resources/handlebars/JavaMicronaut/enumClass.mustache new file mode 100644 index 0000000000..f52f371d2d --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/enumClass.mustache @@ -0,0 +1,37 @@ + /** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} + */ + public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { + {{#allowableValues}} + {{#enumVars}} + {{#gson}} + {{#value}} + @SerializedName({{{toQuotedWord value}}}) + {{/value}} + {{/gson}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} + {{/enumVars}} + {{/allowableValues}} + + private {{{datatype}}} value; + + {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}({{{datatype}}} value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue(String text) { + for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} + } + } diff --git a/src/main/resources/handlebars/JavaMicronaut/enumOuterClass.mustache b/src/main/resources/handlebars/JavaMicronaut/enumOuterClass.mustache new file mode 100644 index 0000000000..14858672f1 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/enumOuterClass.mustache @@ -0,0 +1,41 @@ +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonCreator; +{{/jackson}} + +/** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} + */ +public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { + {{#allowableValues}} + {{#enumVars}} + {{#gson}} + {{#value}} + @SerializedName({{{toQuotedWord value}}}) + {{/value}} + {{/gson}} + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}},{{/@last}}{{#@last}};{{/@last}} + {{/enumVars}} + {{/allowableValues}} + + private {{{dataType}}} value; + + {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue(String text) { + for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} + } +} diff --git a/src/main/resources/mustache/JavaSpring/exampleReturnTypes.mustache b/src/main/resources/handlebars/JavaMicronaut/exampleReturnTypes.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/exampleReturnTypes.mustache rename to src/main/resources/handlebars/JavaMicronaut/exampleReturnTypes.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/formParams.mustache b/src/main/resources/handlebars/JavaMicronaut/formParams.mustache new file mode 100644 index 0000000000..494a4fb912 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/formParams.mustache @@ -0,0 +1 @@ +{{#isFormParam}}{{#notFile}}{{>nullableBeanValidationParams}}@Parameter(description = "{{{description}}}") @Body(value = "{{baseName}}") {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}@Parameter(description = "file detail") {{#useBeanValidation}}@Valid {{/useBeanValidation}}File {{baseName}}{{/isFile}}{{/isFormParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaMicronaut/generatedAnnotation.mustache new file mode 100644 index 0000000000..c6c0883bcb --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/generatedAnnotation.mustache @@ -0,0 +1 @@ +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaMicronaut/headerParams.mustache b/src/main/resources/handlebars/JavaMicronaut/headerParams.mustache new file mode 100644 index 0000000000..5f6dcf0b3e --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/headerParams.mustache @@ -0,0 +1 @@ +{{#isHeaderParam}}{{>nullableBeanValidationParams}}@Parameter(description = "{{{description}}}") @Header(value = "{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/homeController.mustache b/src/main/resources/handlebars/JavaMicronaut/homeController.mustache new file mode 100644 index 0000000000..e53ad0e81a --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/homeController.mustache @@ -0,0 +1,26 @@ +package {{configPackage}}; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; + +/** + * Home redirection to swagger api documentation + */ +@Controller +public class HomeController { + + private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class); + + @Get + public HttpResponse index() { + LOGGER.debug("swagger-ui.html"); + return HttpResponse.status(HttpStatus.FOUND).headers((headers) -> + headers.location(URI.create("swagger-ui.html"))); + } +} diff --git a/src/main/resources/mustache/JavaSpring/implicitHeader.mustache b/src/main/resources/handlebars/JavaMicronaut/implicitHeader.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/implicitHeader.mustache rename to src/main/resources/handlebars/JavaMicronaut/implicitHeader.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/mainApplication.mustache b/src/main/resources/handlebars/JavaMicronaut/mainApplication.mustache new file mode 100644 index 0000000000..653395132d --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/mainApplication.mustache @@ -0,0 +1,27 @@ +package {{basePackage}}; + +import io.micronaut.runtime.Micronaut; +import io.swagger.v3.oas.annotations.*; +import io.swagger.v3.oas.annotations.info.*; + +@OpenAPIDefinition( + info = @Info( + title = "{{appName}}", + version = "{{appVersion}}", + description = "{{{appDescription}}}", + contact = @Contact( + name = "{{infoName}}", + email = "{{infoEmail}}" + ), + license = @License( + name = "{{licenseInfo}}", + url = "{{licenseUrl}}" + ) + ) +) +public class MainApplication { + + public static void main(String[] args) { + Micronaut.run(MainApplication.class); + } +} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/model.mustache b/src/main/resources/handlebars/JavaMicronaut/model.mustache new file mode 100644 index 0000000000..5c26b09746 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/model.mustache @@ -0,0 +1,45 @@ +package {{package}}; + +import java.util.Objects; +{{#imports}}import {{import}}; +{{/imports}} +{{#serializableModel}} +import java.io.Serializable; +{{/serializableModel}} +{{#useBeanValidation}} +import io.micronaut.core.annotation.Introspected; +import io.micronaut.validation.Validated; +{{#jakarta}} +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} +import javax.validation.Valid; +import javax.validation.constraints.*; +{{/jakarta}} +{{/useBeanValidation}} +{{#jackson}} +{{#withXml}} +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +{{/withXml}} +{{/jackson}} +{{#withXml}} +{{#jakarta}} +import jakarta.xml.bind.annotation.*; +{{/jakarta}} +{{^jakarta}} +import javax.xml.bind.annotation.*; +{{/jakarta}} +{{/withXml}} + +{{#models}} +{{#model}} +{{#isEnum}} +{{>enumOuterClass}} +{{/isEnum}} +{{^isEnum}} +{{>pojo}} +{{/isEnum}} +{{/model}} +{{/models}} diff --git a/src/main/resources/handlebars/JavaMicronaut/mvnw b/src/main/resources/handlebars/JavaMicronaut/mvnw new file mode 100755 index 0000000000..d2f0ea3808 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/src/main/resources/handlebars/JavaMicronaut/mvnw.cmd b/src/main/resources/handlebars/JavaMicronaut/mvnw.cmd new file mode 100644 index 0000000000..b26ab24f03 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/src/main/resources/mustache/JavaSpring/notFoundException.mustache b/src/main/resources/handlebars/JavaMicronaut/notFoundException.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/notFoundException.mustache rename to src/main/resources/handlebars/JavaMicronaut/notFoundException.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/nullableBeanValidationParams.mustache b/src/main/resources/handlebars/JavaMicronaut/nullableBeanValidationParams.mustache new file mode 100644 index 0000000000..5d387de368 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/nullableBeanValidationParams.mustache @@ -0,0 +1 @@ +{{#useBeanValidation}}{{#required}}@NotNull {{/required}}{{^required}}@Nullable {{/required}}{{>beanValidationParams}}{{/useBeanValidation}} \ No newline at end of file diff --git a/src/main/resources/mustache/JavaSpring/optionalDataType.mustache b/src/main/resources/handlebars/JavaMicronaut/optionalDataType.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/optionalDataType.mustache rename to src/main/resources/handlebars/JavaMicronaut/optionalDataType.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/pathParams.mustache b/src/main/resources/handlebars/JavaMicronaut/pathParams.mustache new file mode 100644 index 0000000000..4ac4b0ecd0 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/pathParams.mustache @@ -0,0 +1,3 @@ +{{#isPathParam}}{{! + PathParam is always required, no @NotNull necessary +}}{{>beanValidationParams}}@Parameter(description = "{{{description}}}") @PathVariable("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isPathParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/pojo.mustache b/src/main/resources/handlebars/JavaMicronaut/pojo.mustache new file mode 100644 index 0000000000..5e86ef1bcb --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/pojo.mustache @@ -0,0 +1,136 @@ +/** + * {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} + */{{#description}} +@Schema(description = "{{{description}}}"){{/description}} +{{#useBeanValidation}} +@Validated +@Introspected +{{/useBeanValidation}} +{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +{{#serializableModel}} + private static final long serialVersionUID = 1L; + +{{/serializableModel}} + {{#vars}} + {{#baseItems this}} + {{#isEnum}} +{{>enumClass}} + {{/isEnum}} + {{/baseItems}} + {{#jackson}} + @JsonProperty("{{baseName}}"){{#withXml}} + @JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}"){{/withXml}} + {{/jackson}} + {{#gson}} + @SerializedName("{{baseName}}") + {{/gson}} + {{#isContainer}} + {{#useBeanValidation}}@Valid{{/useBeanValidation}} + private {{{datatypeWithEnum}}} {{name}}{{#required}} = {{{defaultValue}}}{{/required}}{{^required}} = null{{/required}}; + {{/isContainer}} + {{^isContainer}} + private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}}; + {{/isContainer}} + + {{/vars}} + {{#vars}} + public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) { + this.{{name}} = {{name}}; + return this; + } + {{#isListContainer}} + + public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) { + {{^required}} + if (this.{{name}} == null) { + this.{{name}} = {{{defaultValue}}}; + } + {{/required}} + this.{{name}}.add({{name}}Item); + return this; + } + {{/isListContainer}} + {{#isMapContainer}} + + public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) { + {{^required}} + if (this.{{name}} == null) { + this.{{name}} = {{{defaultValue}}}; + } + {{/required}} + this.{{name}}.put(key, {{name}}Item); + return this; + } + {{/isMapContainer}} + + /** + {{#description}} + * {{{description}}} + {{/description}} + {{^description}} + * Get {{name}} + {{/description}} + {{#minimum}} + * minimum: {{minimum}} + {{/minimum}} + {{#maximum}} + * maximum: {{maximum}} + {{/maximum}} + * @return {{name}} + **/ + {{#vendorExtensions.extraAnnotation}} + {{{vendorExtensions.extraAnnotation}}} + {{/vendorExtensions.extraAnnotation}} + @Schema({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}description = "{{{description}}}") +{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{#isBoolean}}is{{/isBoolean}}{{getter}}() { + return {{name}}; + } + + public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { + this.{{name}} = {{name}}; + } + + {{/vars}} + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + }{{#hasVars}} + {{classname}} {{classVarName}} = ({{classname}}) o; + return {{#vars}}Objects.equals(this.{{name}}, {{classVarName}}.{{name}}){{#hasMore}} && + {{/hasMore}}{{/vars}}{{#parent}} && + super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}} + return true;{{/hasVars}} + } + + @Override + public int hashCode() { + return Objects.hash({{#vars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}} + {{#vars}}sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n"); + {{/vars}}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/src/main/resources/handlebars/JavaMicronaut/pom.mustache b/src/main/resources/handlebars/JavaMicronaut/pom.mustache new file mode 100644 index 0000000000..d5db343bf6 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/pom.mustache @@ -0,0 +1,155 @@ + + + 4.0.0 + {{groupId}} + {{artifactId}} + {{artifactVersion}} + ${packaging} + + + io.micronaut + micronaut-parent + 3.0.0 + + + + jar + 1.8 + + + 3.0.0 + {{basePackage}}.MainApplication + netty + + + + + central + https://repo.maven.apache.org/maven2 + + + + + + io.micronaut + micronaut-inject + compile + +{{#useBeanValidation}} + + io.micronaut + micronaut-validation + compile + +{{/useBeanValidation}} + + io.micronaut + micronaut-http-client + compile + + + io.micronaut + micronaut-http-server-netty + compile + + + io.micronaut + micronaut-runtime + compile + + +{{#useRxJava3}} + io.micronaut.rxjava3 + micronaut-rxjava3 +{{/useRxJava3}} +{{^useRxJava3}} +{{#useRxJava2}} + io.micronaut.rxjava2 + micronaut-rxjava2 +{{/useRxJava2}} +{{/useRxJava3}} + +{{#useReactor}} + io.micronaut.reactor + micronaut-reactor +{{/useReactor}} + compile + + + ch.qos.logback + logback-classic + runtime + + + io.swagger.core.v3 + swagger-annotations + compile + +{{#useBeanValidation}} + + com.google.code.findbugs + jsr305 + +{{/useBeanValidation}} +{{#threetenbp}} + + com.github.joschi.jackson + jackson-datatype-threetenbp + 2.6.4 + +{{/threetenbp}} +{{#generateApiTests}} + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + io.micronaut.test + micronaut-test-junit5 + test + +{{/generateApiTests}} + + + + + + io.micronaut.build + micronaut-maven-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + +{{#useBeanValidation}} + + + io.micronaut + micronaut-http-validation + ${micronaut.version} + + +{{/useBeanValidation}} + + -Amicronaut.processing.group={{groupId}} + -Amicronaut.processing.module={{artifactId}} + + + + + + + + diff --git a/src/main/resources/mustache/JavaJaxRS/libraries/jersey1/project/build.properties b/src/main/resources/handlebars/JavaMicronaut/project/build.properties similarity index 100% rename from src/main/resources/mustache/JavaJaxRS/libraries/jersey1/project/build.properties rename to src/main/resources/handlebars/JavaMicronaut/project/build.properties diff --git a/src/main/resources/mustache/JavaJaxRS/libraries/jersey1/project/plugins.sbt b/src/main/resources/handlebars/JavaMicronaut/project/plugins.sbt similarity index 100% rename from src/main/resources/mustache/JavaJaxRS/libraries/jersey1/project/plugins.sbt rename to src/main/resources/handlebars/JavaMicronaut/project/plugins.sbt diff --git a/src/main/resources/handlebars/JavaMicronaut/publisher.mustache b/src/main/resources/handlebars/JavaMicronaut/publisher.mustache new file mode 100644 index 0000000000..e76087e08e --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/publisher.mustache @@ -0,0 +1 @@ +{{#useReactor}}Publisher{{/useReactor}}{{^useReactor}}Single{{/useReactor}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/queryParams.mustache b/src/main/resources/handlebars/JavaMicronaut/queryParams.mustache new file mode 100644 index 0000000000..a27659430f --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/queryParams.mustache @@ -0,0 +1 @@ +{{#isQueryParam}}{{>nullableBeanValidationParams}}@Parameter(description = "{{{description}}}") @QueryValue(value = "{{baseName}}"{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) {{>optionalDataType}} {{paramName}}{{/isQueryParam}} \ No newline at end of file diff --git a/src/main/resources/mustache/JavaJaxRS/resteasy/returnTypes.mustache b/src/main/resources/handlebars/JavaMicronaut/returnTypes.mustache similarity index 100% rename from src/main/resources/mustache/JavaJaxRS/resteasy/returnTypes.mustache rename to src/main/resources/handlebars/JavaMicronaut/returnTypes.mustache diff --git a/src/main/resources/handlebars/JavaMicronaut/typeInfoAnnotation.mustache b/src/main/resources/handlebars/JavaMicronaut/typeInfoAnnotation.mustache new file mode 100644 index 0000000000..9fbced41d8 --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/typeInfoAnnotation.mustache @@ -0,0 +1,7 @@ +{{#jackson}} +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{discriminator.propertyName}}", visible = true ) +@JsonSubTypes({ + {{#children}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"), + {{/children}} +}){{/jackson}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaMicronaut/unsupportedOperationExceptionHandler.mustache b/src/main/resources/handlebars/JavaMicronaut/unsupportedOperationExceptionHandler.mustache new file mode 100644 index 0000000000..1ea8ed604f --- /dev/null +++ b/src/main/resources/handlebars/JavaMicronaut/unsupportedOperationExceptionHandler.mustache @@ -0,0 +1,21 @@ +package {{configPackage}}; + + +import io.micronaut.context.annotation.Requires; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.annotation.Produces; +import io.micronaut.http.server.exceptions.ExceptionHandler; +import jakarta.inject.Singleton; + +@Produces +@Singleton +@Requires(classes = {UnsupportedOperationException.class, ExceptionHandler.class}) +public class UnsupportedOperationExceptionHandler implements ExceptionHandler { + + @Override + public HttpResponse handle(HttpRequest request, UnsupportedOperationException exception) { + return HttpResponse.status(HttpStatus.NOT_IMPLEMENTED); + } +} diff --git a/src/main/resources/mustache/JavaSpring/xmlAnnotation.mustache b/src/main/resources/handlebars/JavaMicronaut/xmlAnnotation.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/xmlAnnotation.mustache rename to src/main/resources/handlebars/JavaMicronaut/xmlAnnotation.mustache diff --git a/src/main/resources/handlebars/JavaSpring/LocalDateConverter.mustache b/src/main/resources/handlebars/JavaSpring/LocalDateConverter.mustache new file mode 100644 index 0000000000..b930b29ee2 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/LocalDateConverter.mustache @@ -0,0 +1,27 @@ +package {{configPackage}}; + +import org.springframework.core.convert.converter.Converter; +{{^isJava8or11}} +import org.threeten.bp.LocalDate; +import org.threeten.bp.format.DateTimeFormatter; +{{/isJava8or11}} +{{#isJava8or11}} +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +{{/isJava8or11}} + +public class LocalDateConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDate convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDate.parse(source, this.formatter); + } +} diff --git a/src/main/resources/handlebars/JavaSpring/LocalDateTimeConverter.mustache b/src/main/resources/handlebars/JavaSpring/LocalDateTimeConverter.mustache new file mode 100644 index 0000000000..e45f5f8b32 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/LocalDateTimeConverter.mustache @@ -0,0 +1,27 @@ +package {{configPackage}}; + +import org.springframework.core.convert.converter.Converter; +{{^isJava8or11}} +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.format.DateTimeFormatter; +{{/isJava8or11}} +{{#isJava8or11}} +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +{{/isJava8or11}} + +public class LocalDateTimeConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateTimeConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDateTime convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDateTime.parse(source, this.formatter); + } +} diff --git a/src/main/resources/handlebars/JavaSpring/TestUtils.mustache b/src/main/resources/handlebars/JavaSpring/TestUtils.mustache new file mode 100644 index 0000000000..2165f2232b --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/TestUtils.mustache @@ -0,0 +1,17 @@ +package {{basePackage}}; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicLong; + +public class TestUtils { + private static final AtomicLong atomicId = createAtomicId(); + + public static long nextId() { + return atomicId.getAndIncrement(); + } + + private static AtomicLong createAtomicId() { + int baseId = new Random(System.currentTimeMillis()).nextInt(1000000) + 20000; + return new AtomicLong((long) baseId); + } +} diff --git a/src/main/resources/handlebars/JavaSpring/allowableValues.mustache b/src/main/resources/handlebars/JavaSpring/allowableValues.mustache new file mode 100644 index 0000000000..f704e728f1 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/allowableValues.mustache @@ -0,0 +1,6 @@ +{{#useOas2}} +{{#allowableValues}}allowableValues="{{#values}}{{{.}}}{{^@last}}, {{/@last}}{{/values}}{{^values}}range=[{{#min}}{{.}}{{/min}}{{^min}}-infinity{{/min}}, {{#max}}{{.}}{{/max}}{{^max}}infinity{{/max}}]{{/values}}"{{/allowableValues}} +{{/useOas2}} +{{^useOas2}} +{{#allowableValues}}allowableValues={ {{#values}}"{{{.}}}"{{^@last}}, {{/@last}}{{/values}}{{^values}}{{/values}} }{{#min}}, minimum="{{.}}"{{/min}}{{#max}}, maximum="{{.}}"{{/max}}{{/allowableValues}} +{{/useOas2}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/allowableValuesAndDefaultValue.mustache b/src/main/resources/handlebars/JavaSpring/allowableValuesAndDefaultValue.mustache new file mode 100644 index 0000000000..d3258544f5 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/allowableValuesAndDefaultValue.mustache @@ -0,0 +1 @@ +{{#useOas2}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}{{/useOas2}}{{^useOas2}}, schema=@Schema({{#allowableValues}}allowableValues={ {{#values}}"{{{.}}}"{{^@last}}, {{/@last}}{{/values}}{{^values}}{{/values}} }{{#min}}, minimum="{{.}}"{{/min}}{{#max}}, maximum="{{.}}"{{/max}}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}}, {{/allowableValues}}defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/api.mustache b/src/main/resources/handlebars/JavaSpring/api.mustache index 7551be6b6f..6546e1008d 100644 --- a/src/main/resources/handlebars/JavaSpring/api.mustache +++ b/src/main/resources/handlebars/JavaSpring/api.mustache @@ -10,7 +10,20 @@ package {{package}}; {{#jdk8-no-delegate}} import com.fasterxml.jackson.databind.ObjectMapper; {{/jdk8-no-delegate}} +{{#useOas2}} import io.swagger.annotations.*; +{{/useOas2}} +{{^useOas2}} +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +{{/useOas2}} {{#jdk8-no-delegate}} import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,13 +41,25 @@ 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.multipart.MultipartFile; +import org.springframework.web.bind.annotation.CookieValue; {{#jdk8-no-delegate}} +{{#jakarta}} +import jakarta.servlet.http.HttpServletRequest; +{{/jakarta}} +{{^jakarta}} import javax.servlet.http.HttpServletRequest; +{{/jakarta}} {{/jdk8-no-delegate}} {{#useBeanValidation}} +{{#jakarta}} +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.Valid; import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{#jdk8-no-delegate}} import java.io.IOException; @@ -50,40 +75,47 @@ import java.util.Optional; {{/useOptional}} {{/jdk8-no-delegate}} {{#async}} -import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture{{/jdk8}}; +import java.util.concurrent.{{^isJava8or11}}Callable{{/isJava8or11}}{{#isJava8or11}}CompletableFuture{{/isJava8or11}}; {{/async}} + {{>generatedAnnotation}} +{{#useBeanValidation}} +@Validated +{{/useBeanValidation}} +{{#useOas2}} @Api(value = "{{{baseName}}}", description = "the {{{baseName}}} API") +{{/useOas2}} {{#operations}} public interface {{classname}} { -{{#jdk8}} +{{#isJava8or11}} {{^isDelegate}} Logger log = LoggerFactory.getLogger({{classname}}.class); - default Optional getObjectMapper() { + {{#defaultInterfaces}}default {{/defaultInterfaces}}Optional getObjectMapper(){{^defaultInterfaces}};{{/defaultInterfaces}}{{#defaultInterfaces}}{ return Optional.empty(); - } + }{{/defaultInterfaces}} - default Optional getRequest() { + {{#defaultInterfaces}}default {{/defaultInterfaces}}Optional getRequest(){{^defaultInterfaces}};{{/defaultInterfaces}}{{#defaultInterfaces}}{ return Optional.empty(); - } + }{{/defaultInterfaces}} - default Optional getAcceptHeader() { + {{#defaultInterfaces}}default Optional getAcceptHeader() { return getRequest().map(r -> r.getHeader("Accept")); - } + }{{/defaultInterfaces}} {{/isDelegate}} {{#isDelegate}} {{classname}}Delegate getDelegate(); {{/isDelegate}} -{{/jdk8}} +{{/isJava8or11}} {{#operation}} {{#contents}} +{{#@first}} + {{#useOas2}} @ApiOperation(value = "{{{summary}}}", nickname = "{{{operationId}}}", notes = "{{{notes}}}"{{#returnBaseType}}, response = {{{returnBaseType}}}.class{{/returnBaseType}}{{#returnContainer}}, responseContainer = "{{{returnContainer}}}"{{/returnContainer}}{{#hasAuthMethods}}, authorizations = { - {{#authMethods}}@Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { - {{#scopes}}@AuthorizationScope(scope = "{{scope}}", description = "{{description}}"){{#hasMore}}, - {{/hasMore}}{{/scopes}} + {{#authMethods}}@Authorization(value = "{{name}}"{{#isOAuth}}, scopes = { {{#each scopes}} + @AuthorizationScope(scope = "{{@key}}", description = "{{this}}"){{^@last}},{{/@last}}{{/each}} }{{/isOAuth}}){{#hasMore}}, {{/hasMore}}{{/authMethods}} }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}",{{/vendorExtensions.x-tags}} }) @@ -96,19 +128,32 @@ public interface {{classname}} { {{/headerParams}} }) {{/implicitHeaders}} + {{/useOas2}} + {{^useOas2}} + @Operation(summary = "{{{summary}}}", description = "{{{notes}}}"{{#hasAuthMethods}}, security = { + {{#authMethods}}@SecurityRequirement(name = "{{name}}"{{#isOAuth}}, scopes = { + {{#each scopes}}"{{@key}}"{{^@last}}, + {{/@last}}{{/each}} + }{{/isOAuth}}){{#hasMore}}, + {{/hasMore}}{{/authMethods}} + }{{/hasAuthMethods}}, tags={ {{#vendorExtensions.x-tags}}"{{tag}}"{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.x-tags}} }) + @ApiResponses(value = { {{#responses}} + @ApiResponse(responseCode = "{{{code}}}", description = "{{{message}}}"{{^vendorExtensions.x-java-is-response-void}}{{#baseType}}, content = @Content({{#schema.extensions.x-content-type}}mediaType = "{{schema.extensions.x-content-type}}", {{/schema.extensions.x-content-type}}{{^containerType}}schema = @Schema(implementation = {{{baseType}}}.class)){{/containerType}}{{#containerType}}array = @ArraySchema(schema = @Schema(implementation = {{{baseType}}}.class))){{/containerType}}{{/baseType}}{{/vendorExtensions.x-java-is-response-void}}){{#hasMore}}, + {{/hasMore}}{{/responses}} }) + {{/useOas2}} @RequestMapping(value = "{{{path}}}",{{#singleContentTypes}}{{#hasProduces}} produces = "{{{vendorExtensions.x-accepts}}}", {{/hasProduces}}{{#hasConsumes}} consumes = "{{{vendorExtensions.x-contentType}}}",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}} produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }, {{/hasProduces}}{{#hasConsumes}} - consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} },{{/hasConsumes}}{{/singleContentTypes}} + consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} }, {{/hasConsumes}}{{/singleContentTypes}} method = RequestMethod.{{httpMethod}}) - {{#jdk8}}default {{/jdk8}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}){{^jdk8}};{{/jdk8}}{{#jdk8}} { + {{#defaultInterfaces}}default {{/defaultInterfaces}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>cookieParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, {{/hasMore}}{{/parameters}}){{^defaultInterfaces}}{{#throwsException}} throws Exception{{/throwsException}};{{/defaultInterfaces}}{{#defaultInterfaces}}{{#throwsException}} throws Exception{{/throwsException}} { {{#delegate-method}} return {{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); } // Override this method - default {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#parameters}}{{^isFile}}{{{dataType}}}{{/isFile}}{{#isFile}}MultipartFile{{/isFile}} {{paramName}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { + default {{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#parameters}}{{^isBinary}}{{{dataType}}}{{/isBinary}}{{#isBinary}}MultipartFile{{/isBinary}} {{paramName}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { {{/delegate-method}} {{^isDelegate}} if(getObjectMapper().isPresent() && getAcceptHeader().isPresent()) { @@ -130,9 +175,11 @@ public interface {{classname}} { {{#isDelegate}} return getDelegate().{{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); {{/isDelegate}} - }{{/jdk8}} + }{{/defaultInterfaces}} +{{/@first}} {{/contents}} {{/operation}} } -{{/operations}} \ No newline at end of file +{{/operations}} + diff --git a/src/main/resources/handlebars/JavaSpring/apiController.mustache b/src/main/resources/handlebars/JavaSpring/apiController.mustache index ab8eb2d9bc..0ef9f4f16c 100644 --- a/src/main/resources/handlebars/JavaSpring/apiController.mustache +++ b/src/main/resources/handlebars/JavaSpring/apiController.mustache @@ -1,45 +1,73 @@ package {{package}}; -{{^jdk8}} +{{#fullController}} {{#imports}}import {{import}}; {{/imports}} -{{/jdk8}} +{{/fullController}} {{^isDelegate}} import com.fasterxml.jackson.databind.ObjectMapper; {{/isDelegate}} -{{^jdk8}} +{{#fullController}} +{{#useOas2}} import io.swagger.annotations.*; +{{/useOas2}} +{{^useOas2}} +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +{{/useOas2}} import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -{{/jdk8}} -import org.springframework.stereotype.Controller; -{{^jdk8}} +{{/fullController}} +import org.springframework.web.bind.annotation.RestController; +{{#fullController}} +import org.springframework.web.bind.annotation.CookieValue; 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.RequestParam; import org.springframework.web.bind.annotation.RequestPart; +{{^useOas2}} +import org.springframework.web.bind.annotation.RestController; +{{/useOas2}} import org.springframework.web.multipart.MultipartFile; {{#useBeanValidation}} -import javax.validation.constraints.*; +{{#jakarta}} +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.Valid; +import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} -{{/jdk8}} +{{/fullController}} {{^isDelegate}} + {{#jakarta}} +import jakarta.servlet.http.HttpServletRequest; + {{/jakarta}} + {{^jakarta}} import javax.servlet.http.HttpServletRequest; - {{#jdk8}} + {{/jakarta}} + {{#isJava8or11}} import java.util.Optional; - {{/jdk8}} + {{/isJava8or11}} {{/isDelegate}} {{^jdk8-no-delegate}} {{#useOptional}} import java.util.Optional; {{/useOptional}} {{/jdk8-no-delegate}} -{{^jdk8}} +{{#fullController}} {{^isDelegate}} import java.io.IOException; {{/isDelegate}} @@ -48,9 +76,15 @@ import java.util.Map; {{#async}} import java.util.concurrent.Callable; {{/async}} -{{/jdk8}} +{{/fullController}} + {{>generatedAnnotation}} -@Controller +{{#useOas2}} +@RestController +{{/useOas2}} +{{^useOas2}} +@RestController +{{/useOas2}} {{#operations}} public class {{classname}}Controller implements {{classname}} { @@ -61,19 +95,19 @@ public class {{classname}}Controller implements {{classname}} { public {{classname}}Controller({{classname}}Delegate delegate) { this.delegate = delegate; } - {{#jdk8}} + {{#isJava8or11}} @Override public {{classname}}Delegate getDelegate() { return delegate; } - {{/jdk8}} + {{/isJava8or11}} {{/isDelegate}} {{^isDelegate}} - {{^jdk8}} + {{#fullController}} private static final Logger log = LoggerFactory.getLogger({{classname}}Controller.class); - {{/jdk8}} + {{/fullController}} private final ObjectMapper objectMapper; private final HttpServletRequest request; @@ -83,7 +117,7 @@ public class {{classname}}Controller implements {{classname}} { this.objectMapper = objectMapper; this.request = request; } - {{#jdk8}} + {{#isJava8or11}} @Override public Optional getObjectMapper() { @@ -94,13 +128,14 @@ public class {{classname}}Controller implements {{classname}} { public Optional getRequest() { return Optional.ofNullable(request); } - {{/jdk8}} + {{/isJava8or11}} {{/isDelegate}} -{{^jdk8}} +{{#fullController}} {{#operation}} {{#contents}} - public {{#async}}Callable<{{/async}}ResponseEntity<{{>returnTypes}}>{{#async}}>{{/async}} {{operationId}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { +{{#@first}} + public {{#async}}Callable<{{/async}}ResponseEntity<{{>returnTypes}}>{{#async}}>{{/async}} {{operationId}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{>cookieParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { {{^isDelegate}} {{^async}} String accept = request.getHeader("Accept"); @@ -143,8 +178,9 @@ public class {{classname}}Controller implements {{classname}} { {{/isDelegate}} } +{{/@first}} {{/contents}} {{/operation}} -{{/jdk8}} +{{/fullController}} } {{/operations}} diff --git a/src/main/resources/handlebars/JavaSpring/apiDelegate.mustache b/src/main/resources/handlebars/JavaSpring/apiDelegate.mustache index c75596caea..3654d6ee78 100644 --- a/src/main/resources/handlebars/JavaSpring/apiDelegate.mustache +++ b/src/main/resources/handlebars/JavaSpring/apiDelegate.mustache @@ -2,36 +2,53 @@ package {{package}}; {{#imports}}import {{import}}; {{/imports}} -{{#jdk8}} +{{#isJava8or11}} import com.fasterxml.jackson.databind.ObjectMapper; -{{/jdk8}} +{{/isJava8or11}} +{{#useOas2}} import io.swagger.annotations.*; -{{#jdk8}} +{{/useOas2}} +{{^useOas2}} +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +{{/useOas2}} +{{#isJava8or11}} import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; -{{/jdk8}} +{{/isJava8or11}} import org.springframework.http.ResponseEntity; import org.springframework.web.multipart.MultipartFile; -{{#jdk8}} +{{#isJava8or11}} import java.io.IOException; -{{/jdk8}} +{{/isJava8or11}} -{{#jdk8}} +{{#isJava8or11}} +{{#jakarta}} +import jakarta.servlet.http.HttpServletRequest; +{{/jakarta}} +{{^jakarta}} import javax.servlet.http.HttpServletRequest; -{{/jdk8}} +{{/jakarta}} +{{/isJava8or11}} import java.util.List; import java.util.Map; -{{#jdk8}} +{{#isJava8or11}} import java.util.Optional; -{{/jdk8}} -{{^jdk8}} +{{/isJava8or11}} +{{^isJava8or11}} {{#useOptional}} import java.util.Optional; {{/useOptional}} -{{/jdk8}} +{{/isJava8or11}} {{#async}} -import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture{{/jdk8}}; +import java.util.concurrent.{{^isJava8or11}}Callable{{/isJava8or11}}{{#isJava8or11}}CompletableFuture{{/isJava8or11}}; {{/async}} {{#operations}} @@ -41,30 +58,31 @@ import java.util.concurrent.{{^jdk8}}Callable{{/jdk8}}{{#jdk8}}CompletableFuture */ {{>generatedAnnotation}} public interface {{classname}}Delegate { -{{#jdk8}} +{{#isJava8or11}} Logger log = LoggerFactory.getLogger({{classname}}.class); - default Optional getObjectMapper() { + {{#defaultInterfaces}}default {{/defaultInterfaces}}Optional getObjectMapper(){{^defaultInterfaces}};{{/defaultInterfaces}}{{#defaultInterfaces}}{ return Optional.empty(); - } + }{{/defaultInterfaces}} - default Optional getRequest() { + {{#defaultInterfaces}}default {{/defaultInterfaces}}Optional getRequest(){{^defaultInterfaces}};{{/defaultInterfaces}}{{#defaultInterfaces}}{ return Optional.empty(); - } + }{{/defaultInterfaces}} - default Optional getAcceptHeader() { + {{#defaultInterfaces}}default Optional getAcceptHeader() { return getRequest().map(r -> r.getHeader("Accept")); - } -{{/jdk8}} + }{{/defaultInterfaces}} +{{/isJava8or11}} {{#operation}} {{#contents}} +{{#@first}} /** * @see {{classname}}#{{operationId}} */ - {{#jdk8}}default {{/jdk8}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#parameters}}{{^isFile}} {{>optionalDataType}} {{/isFile}}{{#isFile}}MultipartFile{{/isFile}} {{paramName}}{{#hasMore}}, - {{/hasMore}}{{/parameters}}){{^jdk8}};{{/jdk8}}{{#jdk8}} { + {{#defaultInterfaces}}default {{/defaultInterfaces}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{operationId}}({{#parameters}}{{^isBinary}} {{>optionalDataType}} {{/isBinary}}{{#isBinary}}MultipartFile{{/isBinary}} {{paramName}}{{#hasMore}}, + {{/hasMore}}{{/parameters}}){{^defaultInterfaces}};{{/defaultInterfaces}}{{#defaultInterfaces}} { if(getObjectMapper().isPresent() && getAcceptHeader().isPresent()) { {{#examples}} if (getAcceptHeader().get().contains("{{{contentType}}}")) { @@ -80,8 +98,9 @@ public interface {{classname}}Delegate { log.warn("ObjectMapper or HttpServletRequest not configured in default {{classname}} interface so no example is generated"); } return {{#async}}CompletableFuture.completedFuture({{/async}}new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED){{#async}}){{/async}}; - }{{/jdk8}} + }{{/defaultInterfaces}} +{{/@first}} {{/contents}} {{/operation}} } diff --git a/src/main/resources/handlebars/JavaSpring/apiException.mustache b/src/main/resources/handlebars/JavaSpring/apiException.mustache index f616114770..7eb23b9e9b 100644 --- a/src/main/resources/handlebars/JavaSpring/apiException.mustache +++ b/src/main/resources/handlebars/JavaSpring/apiException.mustache @@ -1,7 +1,7 @@ package {{apiPackage}}; {{>generatedAnnotation}} -public class ApiException extends Exception{ +public class ApiException extends Exception { private int code; public ApiException (int code, String msg) { super(msg); diff --git a/src/main/resources/handlebars/JavaSpring/apiOriginFilter.mustache b/src/main/resources/handlebars/JavaSpring/apiOriginFilter.mustache index 5cf72a7dc4..fca340e13a 100644 --- a/src/main/resources/handlebars/JavaSpring/apiOriginFilter.mustache +++ b/src/main/resources/handlebars/JavaSpring/apiOriginFilter.mustache @@ -2,11 +2,17 @@ package {{apiPackage}}; import java.io.IOException; +{{#jakarta}} +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletResponse; +{{/jakarta}} +{{^jakarta}} import javax.servlet.*; import javax.servlet.http.HttpServletResponse; +{{/jakarta}} {{>generatedAnnotation}} -public class ApiOriginFilter implements javax.servlet.Filter { +public class ApiOriginFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { diff --git a/src/main/resources/handlebars/JavaSpring/apiResponseMessage.mustache b/src/main/resources/handlebars/JavaSpring/apiResponseMessage.mustache index 17b155f3b6..a978341556 100644 --- a/src/main/resources/handlebars/JavaSpring/apiResponseMessage.mustache +++ b/src/main/resources/handlebars/JavaSpring/apiResponseMessage.mustache @@ -1,9 +1,19 @@ package {{apiPackage}}; +{{#jakarta}} +import jakarta.xml.bind.annotation.XmlTransient; +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.XmlTransient; +{{/jakarta}} {{>generatedAnnotation}} +{{#jakarta}} +@jakarta.xml.bind.annotation.XmlRootElement +{{/jakarta}} +{{^jakarta}} @javax.xml.bind.annotation.XmlRootElement +{{/jakarta}} public class ApiResponseMessage { public static final int ERROR = 1; public static final int WARNING = 2; diff --git a/src/main/resources/handlebars/JavaSpring/application.mustache b/src/main/resources/handlebars/JavaSpring/application.mustache index e686a5a0c3..5ef27edcf1 100644 --- a/src/main/resources/handlebars/JavaSpring/application.mustache +++ b/src/main/resources/handlebars/JavaSpring/application.mustache @@ -1,5 +1,11 @@ +{{#useOas2}} springfox.documentation.swagger.v2.path=/api-docs server.contextPath={{^contextPath}}/{{/contextPath}}{{#contextPath}}{{contextPath}}{{/contextPath}} +{{/useOas2}} +{{^useOas2}} +springdoc.api-docs.path=/api-docs +{{/useOas2}} +server.servlet.contextPath={{^contextPath}}/{{/contextPath}}{{#contextPath}}{{contextPath}}{{/contextPath}} server.port={{serverPort}} spring.jackson.date-format={{basePackage}}.RFC3339DateFormat spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/application.properties b/src/main/resources/handlebars/JavaSpring/application.properties deleted file mode 100644 index 8d3a7a8292..0000000000 --- a/src/main/resources/handlebars/JavaSpring/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -springfox.documentation.swagger.v2.path=/api-docs -#server.port=8090 diff --git a/src/main/resources/handlebars/JavaSpring/application.properties.mustache b/src/main/resources/handlebars/JavaSpring/application.properties.mustache new file mode 100644 index 0000000000..325adf0c5c --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/application.properties.mustache @@ -0,0 +1,6 @@ +{{#useOas2}} +springfox.documentation.swagger.v2.path=/api-docs +{{/useOas2}} +{{^useOas2}} +springdoc.api-docs.path=/api-docs +{{/useOas2}} diff --git a/src/main/resources/handlebars/JavaSpring/bodyParams.mustache b/src/main/resources/handlebars/JavaSpring/bodyParams.mustache index 7fef9ad2b6..9bf23e308e 100644 --- a/src/main/resources/handlebars/JavaSpring/bodyParams.mustache +++ b/src/main/resources/handlebars/JavaSpring/bodyParams.mustache @@ -1 +1 @@ -{{#isBodyParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}} {{^isContainer}}{{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file +{{#isBodyParam}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{^isContainer}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{/isContainer}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.DEFAULT, description = "{{{description}}}"{{#required}}, required=true{{/required}}, schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestBody {{{dataType}}} {{paramName}}{{/isBodyParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/cookieParams.mustache b/src/main/resources/handlebars/JavaSpring/cookieParams.mustache new file mode 100644 index 0000000000..3c80b8145b --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/cookieParams.mustache @@ -0,0 +1 @@ +{{#isCookieParam}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.COOKIE, description = "{{{description}}}" {{#required}},required=true{{/required}},schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} @CookieValue(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{>optionalDataType}} {{paramName}}{{/isCookieParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/customInstantDeserializer.mustache b/src/main/resources/handlebars/JavaSpring/customInstantDeserializer.mustache index b7b8e251bd..da7b57a613 100644 --- a/src/main/resources/handlebars/JavaSpring/customInstantDeserializer.mustache +++ b/src/main/resources/handlebars/JavaSpring/customInstantDeserializer.mustache @@ -5,12 +5,12 @@ 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.DateTimeUtils; 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; @@ -205,7 +205,7 @@ public class CustomInstantDeserializer private ZoneId getZone(DeserializationContext context) { // Instants are always in UTC, so don't waste compute cycles - return (_valueClass == Instant.class) ? null : DateTimeUtils.timeZoneToZoneId(context.getTimeZone()); + return (_valueClass == Instant.class) ? null : DateTimeUtils.toZoneId(context.getTimeZone()); } private static class FromIntegerArguments { diff --git a/src/main/resources/handlebars/JavaSpring/enumClass.mustache b/src/main/resources/handlebars/JavaSpring/enumClass.mustache index 3a77cb0f36..073563d427 100644 --- a/src/main/resources/handlebars/JavaSpring/enumClass.mustache +++ b/src/main/resources/handlebars/JavaSpring/enumClass.mustache @@ -6,7 +6,7 @@ {{#allowableValues}} {{#enumVars}} @SerializedName({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -14,7 +14,7 @@ {{^gson}} {{#allowableValues}} {{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}} {{/enumVars}} {{/allowableValues}} @@ -39,6 +39,6 @@ return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaSpring/enumOuterClass.mustache b/src/main/resources/handlebars/JavaSpring/enumOuterClass.mustache index 1ca135d46b..e87a3131ab 100644 --- a/src/main/resources/handlebars/JavaSpring/enumOuterClass.mustache +++ b/src/main/resources/handlebars/JavaSpring/enumOuterClass.mustache @@ -9,12 +9,12 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum {{#gson}} {{#allowableValues}}{{#enumVars}} @SerializedName({{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}{{{value}}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isLong}}"{{/isLong}}{{#isFloat}}"{{/isFloat}}) - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/gson}} {{^gson}} {{#allowableValues}}{{#enumVars}} - {{{name}}}({{{value}}}){{^@last}}, + {{{name}}}({{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}){{^@last}}, {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} {{/gson}} @@ -37,6 +37,6 @@ public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum return b; } } - return null; + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + text + "' for '{{{classname}}}' enum.");{{/errorOnUnknownEnum}} } } diff --git a/src/main/resources/handlebars/JavaSpring/formParams.mustache b/src/main/resources/handlebars/JavaSpring/formParams.mustache index f9c3e502b8..88a2a231cd 100644 --- a/src/main/resources/handlebars/JavaSpring/formParams.mustache +++ b/src/main/resources/handlebars/JavaSpring/formParams.mustache @@ -1 +1 @@ -{{#isFormParam}}{{#notFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}@ApiParam(value = "file detail") {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart("file") MultipartFile {{baseName}}{{/isFile}}{{/isFormParam}} \ No newline at end of file +{{#isFormParam}}{{^isBinary}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.DEFAULT, description = "{{{description}}}"{{#required}}, required=true{{/required}},schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} {{#isMultipart}}@RequestPart{{/isMultipart}}{{^isMultipart}}@RequestParam{{/isMultipart}}(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{{dataType}}} {{paramName}}{{/isBinary}}{{#isBinary}}{{#useOas2}}@ApiParam(value = "{{{description}}}"){{/useOas2}}{{^useOas2}}@Parameter(description = "{{{description}}}"){{/useOas2}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestPart(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) MultipartFile {{baseName}}{{/isBinary}}{{/isFormParam}} diff --git a/src/main/resources/handlebars/JavaSpring/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaSpring/generatedAnnotation.mustache index ad17a426e9..c6c0883bcb 100644 --- a/src/main/resources/handlebars/JavaSpring/generatedAnnotation.mustache +++ b/src/main/resources/handlebars/JavaSpring/generatedAnnotation.mustache @@ -1,3 +1 @@ -{{^hideGenerationTimestamp}} -@javax.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}") -{{/hideGenerationTimestamp}} \ No newline at end of file +{{^hideGenerationTimestamp}}@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}"){{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaSpring/headerParams.mustache b/src/main/resources/handlebars/JavaSpring/headerParams.mustache index 2c8aa49d7d..38cfd8aa8a 100644 --- a/src/main/resources/handlebars/JavaSpring/headerParams.mustache +++ b/src/main/resources/handlebars/JavaSpring/headerParams.mustache @@ -1 +1 @@ -{{#isHeaderParam}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues="{{#values}}{{{.}}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestHeader(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{>optionalDataType}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file +{{#isHeaderParam}}{{#useOas2}}@ApiParam(value = "{{{description}}}" {{#required}},required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.HEADER, description = "{{{description}}}" {{#required}},required=true{{/required}},schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} @RequestHeader(value="{{baseName}}", required={{#required}}true{{/required}}{{^required}}false{{/required}}) {{>optionalDataType}} {{paramName}}{{/isHeaderParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/implicitHeader.mustache b/src/main/resources/handlebars/JavaSpring/implicitHeader.mustache index 64d7af2080..7036a3a456 100644 --- a/src/main/resources/handlebars/JavaSpring/implicitHeader.mustache +++ b/src/main/resources/handlebars/JavaSpring/implicitHeader.mustache @@ -1 +1 @@ -{{#isHeaderParam}}@ApiImplicitParam(name = "{{{paramName}}}", value = "{{{description}}}", {{#required}}required=true,{{/required}} dataType = "{{{dataType}}}", paramType = "header"){{#hasMore}},{{/hasMore}}{{/isHeaderParam}} \ No newline at end of file +{{#isHeaderParam}}{{#useOas2}}@ApiImplicitParam(name = "{{{paramName}}}", value = "{{{description}}}", {{#required}}required=true,{{/required}} dataType = "{{{dataType}}}", paramType = "header"){{#hasMore}},{{/hasMore}}{{/useOas2}}{{/isHeaderParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/interface.mustache b/src/main/resources/handlebars/JavaSpring/interface.mustache new file mode 100644 index 0000000000..0d08bbe545 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/interface.mustache @@ -0,0 +1,26 @@ +{{#jackson}} +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +{{/jackson}} +/** +* {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +*/ +{{#jackson}} +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type") +@JsonSubTypes({ + {{#subTypes}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{classname}}"){{^@last}},{{/@last}} + {{/subTypes}} +}) +{{/jackson}} +public interface {{{classname}}} { + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/README.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/README.mustache index 02d932b8ac..1a4f81a4f7 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/README.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/README.mustache @@ -6,9 +6,9 @@ Spring Boot Server ## Overview This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate a server stub. -This is an example of building a swagger-enabled server in Java using the SpringBoot framework. +This is an example of building a swagger-enabled server in Java using the SpringBoot framework. -The underlying library integrating swagger to SpringBoot is [springfox](https://github.com/springfox/springfox) +The underlying library integrating swagger to SpringBoot is {{#useOas2}}[springfox](https://github.com/springfox/springfox){{/useOas2}}{{^useOas2}}[springdoc-openapi](https://github.com/springdoc/springdoc-openapi){{/useOas2}} Start your server as an simple java application diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/api_test.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/api_test.mustache index 6558eb235c..7dcdf57563 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/api_test.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/api_test.mustache @@ -28,12 +28,12 @@ public class {{classname}}ControllerIntegrationTest { @Test public void {{operationId}}Test() throws Exception { {{#parameters}} - {{^isFile}} + {{^isBinary}} {{{dataType}}} {{paramName}} = {{{example}}}; - {{/isFile}} - {{#isFile}} + {{/isBinary}} + {{#isBinary}} org.springframework.web.multipart.MultipartFile {{paramName}} = null; - {{/isFile}} + {{/isBinary}} {{/parameters}} ResponseEntity<{{>returnTypes}}> responseEntity = api.{{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); assertEquals(HttpStatus.NOT_IMPLEMENTED, responseEntity.getStatusCode()); diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/homeController.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/homeController.mustache index 91a07d5efb..c632a2f872 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/homeController.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/homeController.mustache @@ -10,7 +10,11 @@ import org.springframework.web.bind.annotation.RequestMapping; public class HomeController { @RequestMapping(value = "/") public String index() { - System.out.println("swagger-ui.html"); + {{#useOas2}} return "redirect:swagger-ui.html"; + {{/useOas2}} + {{^useOas2}} + return "redirect:/swagger-ui/"; + {{/useOas2}} } } diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/pom.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/pom.mustache index 7fab01d4c6..54fbe99edd 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/pom.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/pom.mustache @@ -6,15 +6,20 @@ {{artifactId}} {{artifactVersion}} - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} - 2.7.0 + {{#useOas2}} + 2.9.2 + {{/useOas2}} + {{^useOas2}} + 1.7.0 + {{/useOas2}} org.springframework.boot spring-boot-starter-parent - 1.5.9.RELEASE + {{springBootVersion}} src/main/java @@ -34,6 +39,24 @@ {{/interfaceOnly}} + {{#java11}} + + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + {{#jakarta}}4.0.0{{/jakarta}}{{^jakarta}}2.3.3{{/jakarta}} + pom + + + + + {{/java11}} org.springframework.boot @@ -43,7 +66,9 @@ org.springframework.boot spring-boot-starter-tomcat + + {{#useOas2}} io.springfox springfox-swagger2 @@ -54,6 +79,16 @@ springfox-swagger-ui ${springfox-version} + {{/useOas2}} + {{^useOas2}} + + + org.springdoc + springdoc-openapi-ui + ${springdoc-version} + + {{/useOas2}} + {{#withXml}} @@ -63,13 +98,13 @@ {{/withXml}} - {{#java8}} + {{#isJava8or11}} com.fasterxml.jackson.datatype jackson-datatype-jsr310 - {{/java8}} + {{/isJava8or11}} {{#joda}} @@ -85,13 +120,37 @@ 2.6.4 {{/threetenbp}} -{{#useBeanValidation}} - + {{#useBeanValidation}} + + + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api -{{/useBeanValidation}} + {{/jakarta}} + {{/useBeanValidation}} + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + 2.10.1 + + {{/notNullJacksonAnnotation}} + + {{^useOas2}} + + org.springframework.plugin + spring-plugin-core + 2.0.0.RELEASE + + {{/useOas2}} org.springframework.boot diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swagger2SpringBoot.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swagger2SpringBoot.mustache index d329e337fb..42167055ab 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swagger2SpringBoot.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swagger2SpringBoot.mustache @@ -1,15 +1,26 @@ package {{basePackage}}; +import {{configPackage}}.LocalDateConverter; +import {{configPackage}}.LocalDateTimeConverter; + 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; +{{#useOas2}} import springfox.documentation.swagger2.annotations.EnableSwagger2; +{{/useOas2}} + +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @SpringBootApplication +{{#useOas2}} @EnableSwagger2 +{{/useOas2}} @ComponentScan(basePackages = { "{{basePackage}}", "{{apiPackage}}" , "{{configPackage}}"}) public class Swagger2SpringBoot implements CommandLineRunner { @@ -24,6 +35,15 @@ public class Swagger2SpringBoot implements CommandLineRunner { new SpringApplication(Swagger2SpringBoot.class).run(args); } + @Configuration + static class CustomDateConfig extends WebMvcConfigurerAdapter { + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new LocalDateConverter("{{#datePattern}}{{datePattern}}{{/datePattern}}{{^datePattern}}yyyy-MM-dd{{/datePattern}}")); + registry.addConverter(new LocalDateTimeConverter("{{#dateTimePattern}}{{dateTimePattern}}{{/dateTimePattern}}{{^dateTimePattern}}yyyy-MM-dd'T'HH:mm:ss.SSS{{/dateTimePattern}}")); + } + } + class ExitException extends RuntimeException implements ExitCodeGenerator { private static final long serialVersionUID = 1L; diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swaggerUiConfiguration.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swaggerUiConfiguration.mustache new file mode 100644 index 0000000000..4a8833d465 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot/swaggerUiConfiguration.mustache @@ -0,0 +1,34 @@ +package {{configPackage}}; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +{{>generatedAnnotation}} +@Configuration +public class SwaggerUiConfiguration implements WebMvcConfigurer { + + @Override + {{#useOas2}} + public void addResourceHandlers(ResourceHandlerRegistry registry) { + + registry + .addResourceHandler("/swagger-ui.html") + .addResourceLocations("classpath:/META-INF/resources/"); + + registry + .addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/"); + registry. + addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") + .resourceChain(false); + } + {{/useOas2}} + {{^useOas2}} + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/swagger-ui/").setViewName("forward:/swagger-ui/index.html"); + } + {{/useOas2}} +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/LocalDateConverter.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/LocalDateConverter.mustache new file mode 100644 index 0000000000..75481b41de --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/LocalDateConverter.mustache @@ -0,0 +1,21 @@ +package {{configPackage}}; + +import org.springframework.core.convert.converter.Converter; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class LocalDateConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDate convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDate.parse(source, this.formatter); + } +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/LocalDateTimeConverter.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/LocalDateTimeConverter.mustache new file mode 100644 index 0000000000..4854688eb6 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/LocalDateTimeConverter.mustache @@ -0,0 +1,21 @@ +package {{configPackage}}; + +import org.springframework.core.convert.converter.Converter; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class LocalDateTimeConverter implements Converter { + private final DateTimeFormatter formatter; + + public LocalDateTimeConverter(String dateFormat) { + this.formatter = DateTimeFormatter.ofPattern(dateFormat); + } + + @Override + public LocalDateTime convert(String source) { + if(source == null || source.isEmpty()) { + return null; + } + return LocalDateTime.parse(source, this.formatter); + } +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/README.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/README.mustache new file mode 100644 index 0000000000..8e5dd7bb11 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/README.mustache @@ -0,0 +1,37 @@ +{{^interfaceOnly}}# Swagger generated server + +Spring Boot Server + + +## Overview +This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate a server stub. +This is an example of building a swagger-enabled server in Java using the SpringBoot framework. + +The underlying library integrating swagger to SpringBoot is [springdoc-openapi](https://github.com/springdoc/springdoc-openapi) + +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{{/interfaceOnly}}{{#interfaceOnly}} +# Swagger generated API stub + +Spring Framework stub + + +## Overview +This code was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate an API stub. +This is an example of building API stub interfaces in Java using the Spring framework. + +The stubs generated can be used in your existing Spring-MVC or Spring-Boot application to create controller endpoints +by adding ```@Controller``` classes that implement the interface. Eg: +```java +@Controller +public class PetController implements PetApi { +// implement all PetApi methods +} +``` +{{/interfaceOnly}} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/application.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/application.mustache new file mode 100644 index 0000000000..93b903a3c2 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/application.mustache @@ -0,0 +1,3 @@ +springdoc.api-docs.path=/api-docs +server.servlet.contextPath={{^contextPath}}/{{/contextPath}}{{#contextPath}}{{contextPath}}{{/contextPath}} +server.port={{serverPort}} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/homeController.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/homeController.mustache new file mode 100644 index 0000000000..89f4069854 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/homeController.mustache @@ -0,0 +1,16 @@ +package {{configPackage}}; + +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/index.html"); + return "redirect:/swagger-ui/"; + } +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/openAPISpringBoot.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/openAPISpringBoot.mustache new file mode 100644 index 0000000000..876248c766 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/openAPISpringBoot.mustache @@ -0,0 +1,48 @@ +package {{basePackage}}; + +import {{configPackage}}.LocalDateConverter; +import {{configPackage}}.LocalDateTimeConverter; + +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; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; + +@SpringBootApplication +@ComponentScan(basePackages = { "{{basePackage}}", "{{apiPackage}}" , "{{configPackage}}"}) +public class OpenAPISpringBoot 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(OpenAPISpringBoot.class).run(args); + } + + @Configuration + static class CustomDateConfig extends WebMvcConfigurationSupport { + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new LocalDateConverter("{{#datePattern}}{{datePattern}}{{/datePattern}}{{^datePattern}}yyyy-MM-dd{{/datePattern}}")); + registry.addConverter(new LocalDateTimeConverter("{{#dateTimePattern}}{{dateTimePattern}}{{/dateTimePattern}}{{^dateTimePattern}}yyyy-MM-dd'T'HH:mm:ss.SSS{{/dateTimePattern}}")); + } + } + + class ExitException extends RuntimeException implements ExitCodeGenerator { + private static final long serialVersionUID = 1L; + + @Override + public int getExitCode() { + return 10; + } + + } +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/pom.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/pom.mustache new file mode 100644 index 0000000000..ccd6595351 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/pom.mustache @@ -0,0 +1,103 @@ + + 4.0.0 + {{groupId}} + {{artifactId}} + jar + {{artifactId}} + {{artifactVersion}} + + UTF-8 + 17 + 3.1.1 + 2.2.14 + 1.7.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.1.1 + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + ${springboot-version} + + + org.springframework.boot + spring-boot-starter-tomcat + ${springboot-version} + + {{#withXml}} + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + {{/withXml}} + {{#useBeanValidation}} + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + jakarta.xml.bind + jakarta.xml.bind-api + 4.0.0 + + + com.sun.xml.bind + jaxb-impl + 4.0.3 + + {{/useBeanValidation}} + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + 2.10.1 + + {{/notNullJacksonAnnotation}} + + + org.springdoc + springdoc-openapi-ui + ${springdoc-version} + + + + io.swagger.core.v3 + swagger-annotations + ${swagger-annotations-version} + + + org.springframework.plugin + spring-plugin-core + 3.0.0 + + + + org.springframework.boot + spring-boot-starter-test + ${springboot-version} + test + + + diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/swaggerUiConfiguration.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/swaggerUiConfiguration.mustache new file mode 100644 index 0000000000..94e7f86bbc --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-boot3/swaggerUiConfiguration.mustache @@ -0,0 +1,16 @@ +package {{configPackage}}; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +{{>generatedAnnotation}} +@Configuration +public class SwaggerUiConfiguration implements WebMvcConfigurer { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/swagger-ui/").setViewName("forward:/swagger-ui/index.html"); + } +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/Application.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/Application.mustache index 372b8da31e..3708ed46f1 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/Application.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/Application.mustache @@ -3,7 +3,12 @@ package io.swagger; import feign.Logger; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; +{{^isOpenFeign}} import org.springframework.cloud.netflix.feign.EnableFeignClients; +{{/isOpenFeign}} +{{#isOpenFeign}} +import org.springframework.cloud.openfeign.EnableFeignClients; +{{/isOpenFeign}} import org.springframework.context.annotation.Bean; @SpringBootApplication diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/apiClient.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/apiClient.mustache index 52fedbea77..029b0030a9 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/apiClient.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/apiClient.mustache @@ -1,10 +1,13 @@ package {{package}}; +{{^isOpenFeign}} import org.springframework.cloud.netflix.feign.FeignClient; +{{/isOpenFeign}} +{{#isOpenFeign}} +import org.springframework.cloud.openfeign.FeignClient; +{{/isOpenFeign}} import {{configPackage}}.ClientConfiguration; -{{=<% %>=}} -@FeignClient(name="${<%title%>.name:<%title%>}", url="${<%title%>.url:<%basePath%>}", configuration = ClientConfiguration.class) -<%={{ }}=%> +@FeignClient({{#isOpenFeign}}contextId="{{classname}}Client", {{/isOpenFeign}}name="${{braces "left"}}{{title}}.name:{{title}}{{braces "right"}}", url="${{braces "left"}}{{title}}.url:{{^wiremock}}{{basePath}}{{/wiremock}}{{#wiremock}}wiremock.base.path{{/wiremock}}{{braces "right"}}", configuration = ClientConfiguration.class) public interface {{classname}}Client extends {{classname}} { -} \ No newline at end of file +} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/api_test.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/api_test.mustache index 0723a652b4..b9cf5a2773 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/api_test.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/api_test.mustache @@ -29,12 +29,12 @@ private {{classname}} api; @Test public void {{operationId}}Test() throws Exception { {{#parameters}} - {{^isFile}} + {{^isBinary}} {{{dataType}}} {{paramName}} = {{{example}}}; - {{/isFile}} - {{#isFile}} + {{/isBinary}} + {{#isBinary}} org.springframework.web.multipart.MultipartFile {{paramName}} = null; - {{/isFile}} + {{/isBinary}} {{/parameters}} api.{{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); // todo: add verifications diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/application-test.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/application-test.mustache new file mode 100644 index 0000000000..bb1b707127 --- /dev/null +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/application-test.mustache @@ -0,0 +1,15 @@ +spring: + application: + name: {{artifactId}}-test + jackson: + serialization.WRITE_DATES_AS_TIMESTAMPS: false + +hystrix.command.default.execution.timeout.enabled: false + +logging.level.{{apiPackage}}: DEBUG + +feign.hystrix.enabled: true + +{{#wiremock}} +wiremock.base.path: http://localhost:33333 +{{/wiremock}} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/formParams.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/formParams.mustache index bd2cb8bb64..14db3fcd80 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/formParams.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/formParams.mustache @@ -1 +1 @@ -{{#isFormParam}}{{#notFile}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{#allowableValues}}, allowableValues="{{{allowableValues}}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{{dataType}}} {{paramName}}{{/notFile}}{{#isFile}}@ApiParam(value = "file detail") @RequestParam("{{baseName}}") MultipartFile {{paramName}}{{/isFile}}{{/isFormParam}} \ No newline at end of file +{{#isFormParam}}{{^isBinary}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}} {{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.DEFAULT, description = "{{{description}}}"{{#required}}, required=true{{/required}},schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} @RequestParam(value="{{baseName}}"{{#required}}, required=true{{/required}}{{^required}}, required=false{{/required}}) {{{dataType}}} {{paramName}}{{/isBinary}}{{#isBinary}}{{#useOas2}}@ApiParam(value = "file detail"){{/useOas2}}{{^useOas2}}@Parameter(description = "file detail"){{/useOas2}} @RequestParam("{{baseName}}") MultipartFile {{paramName}}{{/isBinary}}{{/isFormParam}} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/pom.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/pom.mustache index 9efcee55a5..6a68c8141c 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/pom.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-cloud/pom.mustache @@ -6,15 +6,20 @@ {{artifactId}} {{artifactVersion}} - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} + {{#useOas2}} 1.5.18 + {{/useOas2}} + {{^useOas2}} + 2.0.10 + {{/useOas2}} org.springframework.boot spring-boot-starter-parent - 1.5.4.RELEASE + {{springBootVersion}} src/main/java @@ -25,7 +30,7 @@ org.springframework.cloud spring-cloud-starter-parent - Dalston.SR1 + {{^springBootV2}}Dalston.SR1{{/springBootV2}}{{#springBootV2}}Greenwich.RELEASE{{/springBootV2}} pom import @@ -33,12 +38,21 @@ + {{#useOas2}} io.swagger swagger-annotations ${swagger-core-version} + {{/useOas2}} + {{^useOas2}} + io.swagger.core.v3 + swagger-annotations + ${swagger-core-version} + + {{/useOas2}} + {{^springBootV2}} org.springframework.cloud spring-cloud-starter-feign @@ -49,7 +63,23 @@ org.springframework.security.oauth spring-security-oauth2 + {{/springBootV2}} + {{#springBootV2}} + org.springframework.cloud + spring-cloud-starter-openfeign + 2.1.3.RELEASE + + org.springframework.cloud + spring-cloud-security + 2.1.4.RELEASE + + + org.springframework.security.oauth + spring-security-oauth2 + 2.3.6.RELEASE + {{/springBootV2}} + {{#withXml}} @@ -83,17 +113,57 @@ {{/threetenbp}} {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} org.springframework.boot spring-boot-starter-test test + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + 2.10.1 + + {{/notNullJacksonAnnotation}} + +{{#jakarta}} + + jakarta.servlet + jakarta-api + provided + +{{/jakarta}} +{{^jakarta}} + + javax.servlet + javax.servlet-api + provided + +{{/jakarta}} + {{#wiremock}} + + com.github.tomakehurst + wiremock + 2.27.2 + test + + {{/wiremock}} diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/pom.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/pom.mustache index bd4245633c..764393a6bd 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/pom.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/pom.mustache @@ -65,6 +65,24 @@ + {{#java11}} + + + jdk11 + + [11,) + + + + com.sun.xml.ws + jaxws-rt + 2.3.3 + pom + + + + + {{/java11}} org.slf4j @@ -90,6 +108,7 @@ + {{#useOas2}} io.springfox springfox-swagger2 @@ -101,6 +120,15 @@ + {{/useOas2}} + {{^useOas2}} + + io.springfox + springfox-oas + ${springfox-version} + + {{/useOas2}} + io.springfox springfox-swagger-ui @@ -147,19 +175,38 @@ ${junit-version} test +{{#jakarta}} + + jakarta.servlet + jakarta-api + ${servlet-api-version} + +{{/jakarta}} +{{^jakarta}} javax.servlet servlet-api ${servlet-api-version} +{{/jakarta}} {{#useBeanValidation}} + {{#jakarta}} + + jakarta.validation + jakarta.validation-api + 3.0.2 + provided + + {{/jakarta}} + {{^jakarta}} javax.validation validation-api 1.1.0.Final provided + {{/jakarta}} {{/useBeanValidation}} org.testng @@ -181,7 +228,13 @@ - + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + ${jackson-version} + + {{/notNullJacksonAnnotation}} org.apache.httpcomponents httpclient @@ -190,16 +243,21 @@ - {{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}} + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} ${java.version} ${java.version} - 9.2.15.v20160210 + 9.3.28.v20191105 1.7.21 - 4.12 - 2.5 - 2.7.0 - 2.8.9 - 2.6.4 - 4.3.9.RELEASE + 4.13.1 + {{#jakarta}}6.0.0{{/jakarta}}{{^jakarta}}2.5{{/jakarta}} + {{#useOas2}} + 2.9.2 + {{/useOas2}} + {{^useOas2}} + 3.0.0 + {{/useOas2}} + 2.9.10 + 2.9.10 + 5.3.27 diff --git a/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/swaggerUiConfiguration.mustache b/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/swaggerUiConfiguration.mustache index 563a76915f..0da481857f 100644 --- a/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/swaggerUiConfiguration.mustache +++ b/src/main/resources/handlebars/JavaSpring/libraries/spring-mvc/swaggerUiConfiguration.mustache @@ -10,6 +10,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Bean; +import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -21,7 +22,12 @@ import org.threeten.bp.Instant; import org.threeten.bp.OffsetDateTime; import org.threeten.bp.ZonedDateTime; {{/threetenbp}} +{{#useOas2}} import springfox.documentation.swagger2.annotations.EnableSwagger2; +{{/useOas2}} +{{^useOas2}} +import springfox.documentation.oas.annotations.EnableOpenApi; +{{/useOas2}} import java.util.List; @@ -29,7 +35,12 @@ import java.util.List; @Configuration @ComponentScan(basePackages = "{{apiPackage}}") @EnableWebMvc -@EnableSwagger2 //Loads the spring beans required by the framework +{{#useOas2}} +@EnableSwagger2 +{{/useOas2}} +{{^useOas2}} +@EnableOpenApi +{{/useOas2}} @PropertySource("classpath:swagger.properties") @Import(SwaggerDocumentationConfig.class) public class SwaggerUiConfiguration extends WebMvcConfigurerAdapter { @@ -82,6 +93,12 @@ public class SwaggerUiConfiguration extends WebMvcConfigurerAdapter { super.configureMessageConverters(converters); } + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new LocalDateConverter("{{#datePattern}}{{datePattern}}{{/datePattern}}{{^datePattern}}yyyy-MM-dd{{/datePattern}}")); + registry.addConverter(new LocalDateTimeConverter("{{#dateTimePattern}}{{dateTimePattern}}{{/dateTimePattern}}{{^dateTimePattern}}yyyy-MM-dd'T'HH:mm:ss.SSS{{/dateTimePattern}}")); + } + @Bean public ObjectMapper objectMapper(){ return builder().build(); diff --git a/src/main/resources/handlebars/JavaSpring/model.mustache b/src/main/resources/handlebars/JavaSpring/model.mustache index 180cb243f0..681b07890c 100644 --- a/src/main/resources/handlebars/JavaSpring/model.mustache +++ b/src/main/resources/handlebars/JavaSpring/model.mustache @@ -1,5 +1,6 @@ package {{package}}; +{{^x-is-composed-model}} import java.util.Objects; {{#imports}}import {{import}}; {{/imports}} @@ -8,8 +9,14 @@ import java.io.Serializable; {{/serializableModel}} {{#useBeanValidation}} import org.springframework.validation.annotation.Validated; +{{#jakarta}} +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +{{/jakarta}} +{{^jakarta}} import javax.validation.Valid; import javax.validation.constraints.*; +{{/jakarta}} {{/useBeanValidation}} {{#jackson}} {{#withXml}} @@ -18,16 +25,27 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; {{/withXml}} {{/jackson}} {{#withXml}} +{{#jakarta}} +import jakarta.xml.bind.annotation.*; +{{/jakarta}} +{{^jakarta}} import javax.xml.bind.annotation.*; +{{/jakarta}} {{/withXml}} +{{/x-is-composed-model}} {{#models}} {{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#isEnum}} {{>enumOuterClass}} {{/isEnum}} {{^isEnum}} {{>pojo}} {{/isEnum}} +{{/isComposedModel}} {{/model}} {{/models}} diff --git a/src/main/resources/handlebars/JavaSpring/pathParams.mustache b/src/main/resources/handlebars/JavaSpring/pathParams.mustache index dcc441f26f..7dd6af4690 100644 --- a/src/main/resources/handlebars/JavaSpring/pathParams.mustache +++ b/src/main/resources/handlebars/JavaSpring/pathParams.mustache @@ -1 +1 @@ -{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}},required=true{{/required}}{{#allowableValues}}, allowableValues = "{{#enumVars}}{{#lambdaEscapeDoubleQuote}}{{{value}}}{{/lambdaEscapeDoubleQuote}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/enumVars}}"{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) @PathVariable("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isPathParam}} \ No newline at end of file +{{#isPathParam}}{{#useBeanValidation}}{{>beanValidationPathParams}}{{/useBeanValidation}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required=true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.PATH, description = "{{{description}}}"{{#required}}, required=true{{/required}}, schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} @PathVariable("{{baseName}}") {{>optionalDataType}} {{paramName}}{{/isPathParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/pojo.mustache b/src/main/resources/handlebars/JavaSpring/pojo.mustache index 3a49211f64..8c87f3bb8f 100644 --- a/src/main/resources/handlebars/JavaSpring/pojo.mustache +++ b/src/main/resources/handlebars/JavaSpring/pojo.mustache @@ -1,30 +1,30 @@ /** * {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} */{{#description}} -@ApiModel(description = "{{{description}}}"){{/description}} +{{#useOas2}}@ApiModel{{/useOas2}}{{^useOas2}}@Schema{{/useOas2}}(description = "{{{description}}}"){{/description}} {{#useBeanValidation}}@Validated{{/useBeanValidation}} {{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} { +{{#notNullJacksonAnnotation}}@JsonInclude(JsonInclude.Include.NON_NULL){{/notNullJacksonAnnotation}} + +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/interfaceModels}}{{/serializableModel}} { {{#serializableModel}} private static final long serialVersionUID = 1L; {{/serializableModel}} {{#vars}} + {{#baseItems this}} {{#isEnum}} - {{^isContainer}} {{>enumClass}} - {{/isContainer}} {{/isEnum}} - {{#items.isEnum}} - {{#items}} - {{^isContainer}} -{{>enumClass}} - {{/isContainer}} - {{/items}} - {{/items.isEnum}} + {{/baseItems}} {{#jackson}} + {{#vendorExtensions.x-is-discriminator-property}} + @JsonTypeId + {{/vendorExtensions.x-is-discriminator-property}} + {{^vendorExtensions.x-is-discriminator-property}} @JsonProperty("{{baseName}}"){{#withXml}} @JacksonXmlProperty({{#isXmlAttribute}}isAttribute = true, {{/isXmlAttribute}}{{#xmlNamespace}}namespace="{{xmlNamespace}}", {{/xmlNamespace}}localName = "{{#xmlName}}{{xmlName}}{{/xmlName}}{{^xmlName}}{{baseName}}{{/xmlName}}"){{/withXml}} + {{/vendorExtensions.x-is-discriminator-property}} {{/jackson}} {{#gson}} @SerializedName("{{baseName}}") @@ -82,12 +82,17 @@ public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#seriali * maximum: {{maximum}} {{/maximum}} * @return {{name}} - **/ + **/ {{#vendorExtensions.extraAnnotation}} {{{vendorExtensions.extraAnnotation}}} {{/vendorExtensions.extraAnnotation}} + {{#useOas2}} @ApiModelProperty({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}readOnly = {{{isReadOnly}}}, {{/isReadOnly}}value = "{{{description}}}") -{{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{#isBoolean}}is{{/isBoolean}}{{getter}}() { + {{/useOas2}} + {{^useOas2}} + @Schema({{#example}}example = "{{{example}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}{{#isReadOnly}}accessMode = Schema.AccessMode.READ_ONLY, {{/isReadOnly}}description = "{{{description}}}") + {{/useOas2}} + {{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() { return {{name}}; } diff --git a/src/main/resources/handlebars/JavaSpring/queryParams.mustache b/src/main/resources/handlebars/JavaSpring/queryParams.mustache index 007d82fb2d..42e2fe62c6 100644 --- a/src/main/resources/handlebars/JavaSpring/queryParams.mustache +++ b/src/main/resources/handlebars/JavaSpring/queryParams.mustache @@ -1 +1 @@ -{{#isQueryParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, allowableValues = "{{#values}}{{{.}}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/values}}"{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}) {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{>optionalDataType}} {{paramName}}{{/isQueryParam}} \ No newline at end of file +{{#isQueryParam}}{{#useBeanValidation}}{{>beanValidationQueryParams}}{{/useBeanValidation}}{{#useOas2}}@ApiParam(value = "{{{description}}}"{{#required}}, required = true{{/required}}{{#allowableValues}}, {{> allowableValues }}{{/allowableValues}}{{#defaultValue}}, defaultValue = "{{{defaultValue}}}"{{/defaultValue}}){{/useOas2}}{{^useOas2}}@Parameter(in = ParameterIn.QUERY, description = "{{{description}}}" {{#required}},required=true{{/required}},schema=@Schema({{#allowableValues}}{{> allowableValues }}{{/allowableValues}}{{#defaultValue}}{{#allowableValues}},{{/allowableValues}} defaultValue="{{{defaultValue}}}"{{/defaultValue}})){{/useOas2}} {{#useBeanValidation}}@Valid{{/useBeanValidation}} @RequestParam(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}{{#defaultValue}}, defaultValue="{{{defaultValue}}}"{{/defaultValue}}) {{>optionalDataType}} {{paramName}}{{/isQueryParam}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaSpring/swaggerDocumentationConfig.mustache b/src/main/resources/handlebars/JavaSpring/swaggerDocumentationConfig.mustache index a0b2cded91..c251cfe49c 100644 --- a/src/main/resources/handlebars/JavaSpring/swaggerDocumentationConfig.mustache +++ b/src/main/resources/handlebars/JavaSpring/swaggerDocumentationConfig.mustache @@ -3,12 +3,19 @@ package {{configPackage}}; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; +{{#useOas2}} import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.service.ApiInfo; +{{/useOas2}} +{{^useOas2}} +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +{{/useOas2}} {{#useOptional}} import java.util.Optional; {{/useOptional}} @@ -17,20 +24,10 @@ import java.util.Optional; @Configuration public class SwaggerDocumentationConfig { - ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("{{appName}}") - .description("{{{appDescription}}}") - .license("{{licenseInfo}}") - .licenseUrl("{{licenseUrl}}") - .termsOfServiceUrl("{{infoUrl}}") - .version("{{appVersion}}") - .contact(new Contact("","", "{{infoEmail}}")) - .build(); - } - + {{#useOas2}} @Bean public Docket customImplementation(){ + return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("{{apiPackage}}")) @@ -53,4 +50,33 @@ public class SwaggerDocumentationConfig { .apiInfo(apiInfo()); } + ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("{{appName}}") + .description("{{{appDescription}}}") + .license("{{licenseInfo}}") + .licenseUrl("{{licenseUrl}}") + .termsOfServiceUrl("{{infoUrl}}") + .version("{{appVersion}}") + .contact(new Contact("","", "{{infoEmail}}")) + .build(); + } + {{/useOas2}} + {{^useOas2}} + @Bean + public OpenAPI openApi() { + return new OpenAPI() + .info(new Info() + .title("{{appName}}") + .description("{{{appDescription}}}") + .termsOfService("{{infoUrl}}") + .version("{{appVersion}}") + .license(new License() + .name("{{licenseInfo}}") + .url("{{licenseUrl}}")) + .contact(new io.swagger.v3.oas.models.info.Contact() + .email("{{infoEmail}}"))); + } + {{/useOas2}} + } diff --git a/src/main/resources/handlebars/JavaSpring/typeInfoAnnotation.mustache b/src/main/resources/handlebars/JavaSpring/typeInfoAnnotation.mustache index f2a2e1c88f..f3ed515976 100644 --- a/src/main/resources/handlebars/JavaSpring/typeInfoAnnotation.mustache +++ b/src/main/resources/handlebars/JavaSpring/typeInfoAnnotation.mustache @@ -1,7 +1,14 @@ {{#jackson}} @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{discriminator.propertyName}}", visible = true ) @JsonSubTypes({ - {{#children}} - @JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"), - {{/children}} -}){{/jackson}} + {{#if discriminator.mapping}} + {{#each discriminator.mapping}} + @JsonSubTypes.Type(value = {{this}}.class, name = "{{@key}}"), + {{/each}} + {{else}} + {{#children}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{name}}"), + {{/children}} + {{/if}} +}) +{{/jackson}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaVertXServer/DataObjectMapper.mustache b/src/main/resources/handlebars/JavaVertXServer/DataObjectMapper.mustache new file mode 100644 index 0000000000..9126854940 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/DataObjectMapper.mustache @@ -0,0 +1,55 @@ +package {{modelPackage}}; + +{{#java8}} +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +{{/java8}} +{{#threetenbp}} +import org.threeten.bp.Instant; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZonedDateTime; +{{/threetenbp}} +{{#joda}} +import org.joda.time.LocalDate; +import org.joda.time.DateTime; +{{/joda}} + +public class DataObjectMapper { + {{#java8}} + public static String serializeOffsetDateTime(OffsetDateTime value) { + return value.toString(); + } + + public static String serializeLocalDateTime(LocalDateTime value) { + return value.toString(); + } + + public static String serializeLocalDate(LocalDate value) { + return value.toString(); + } + {{/java8}} + {{#threetenbp}} + public static String serializeThreetenbpInstant(org.threeten.bp.Instant value) { + return value.toString(); + } + + public static String serializeThreetenbpOffsetDateTime(org.threeten.bp.OffsetDateTime value) { + return value.toString(); + } + + public static String serializeThreetenbpZonedDateTime(org.threeten.bp.ZonedDateTime value) { + return value.toString(); + } + {{/threetenbp}} + {{#joda}} + public static String serializeJodaLocalDate(org.joda.time.LocalDate value) { + return value.toString(); + } + + public static String serializeJodaDateTime(org.joda.time.DateTime value) { + return value.toString(); + } + {{/joda}} + +} diff --git a/src/main/resources/handlebars/JavaVertXServer/MainApiVerticle.mustache b/src/main/resources/handlebars/JavaVertXServer/MainApiVerticle.mustache new file mode 100644 index 0000000000..be3c5c1c62 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/MainApiVerticle.mustache @@ -0,0 +1,36 @@ +package {{rootPackage}}; + +{{#rxInterface}} +import io.reactivex.Completable; +import io.vertx.reactivex.core.AbstractVerticle; +{{/rxInterface}} +{{^rxInterface}} +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Promise; +{{/rxInterface}} +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MainApiVerticle extends AbstractVerticle { + static final Logger LOGGER = LoggerFactory.getLogger(MainApiVerticle.class); + + @Override + {{^rxInterface}}public void start(Promise startPromise) throws Exception { + vertx.deployVerticle("{{verticlePackage}}.{{title}}Verticle") + .onFailure(error -> { + LOGGER.error("{{title}}Verticle : Deployment failed"); + startPromise.fail(error); + }) + .onSuccess(server -> { + LOGGER.info("{{title}}Verticle : Deployed"); + startPromise.complete(); + }); + }{{/rxInterface}} + {{#rxInterface}}public Completable rxStart() { + return vertx.rxDeployVerticle("{{verticlePackage}}.{{title}}Verticle") + .doOnError(error -> LOGGER.error("{{title}}Verticle : Deployment failed")) + .doOnSuccess(server -> LOGGER.info("{{title}}Verticle : Deployed")) + .ignoreElement(); + }{{/rxInterface}} + +} diff --git a/src/main/resources/handlebars/JavaVertXServer/README.mustache b/src/main/resources/handlebars/JavaVertXServer/README.mustache new file mode 100644 index 0000000000..ac03f0bc7c --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/README.mustache @@ -0,0 +1 @@ +Project generated on : {{generatedDate}} diff --git a/src/main/resources/handlebars/JavaVertXServer/api.mustache b/src/main/resources/handlebars/JavaVertXServer/api.mustache new file mode 100644 index 0000000000..c2a2b1de84 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/api.mustache @@ -0,0 +1,37 @@ +package {{package}}; + +{{#imports}}import {{import}}; +{{/imports}} + +{{#useFuture}} +import io.vertx.core.Future; +{{/useFuture}} +{{^useFuture}} +import io.vertx.core.Handler; +import io.vertx.core.AsyncResult; +{{/useFuture}} +import io.vertx.ext.web.validation.RequestParameter; +import io.vertx.ext.web.api.service.ServiceRequest; +import io.vertx.ext.web.api.service.ServiceResponse; +{{#mountFromExtensions}} +import io.vertx.ext.web.api.service.WebApiServiceGen; +{{/mountFromExtensions}} + +import java.util.List; +import java.util.Map; + +{{#mountFromExtensions}}@WebApiServiceGen{{/mountFromExtensions}} +public interface {{classname}} { + +{{#operations}}{{#operation}}{{#@first}} String WEBSERVICE_ADDRESS_{{#lambda.uppercase}}{{classname}}{{/lambda.uppercase}} = "{{#mountFromExtensions}}{{#vendorExtensions}}{{x-event-bus-address}}{{/vendorExtensions}}{{/mountFromExtensions}}{{#mountFromInterface}}{{baseName}}.address{{/mountFromInterface}}";{{/@first}}{{/operation}}{{/operations}} +{{#operations}}{{#operation}} String OPERATION_ID_{{#lambda.uppercase}}{{operationId}}{{/lambda.uppercase}} = "{{operationId}}"; +{{/operation}}{{/operations}} + +{{#operations}} +{{#operation}} +{{#contents}} + {{#useFuture}}Future{{/useFuture}}{{^useFuture}}void{{/useFuture}} {{#vendorExtensions}}{{x-serviceid}}{{/vendorExtensions}}({{#useDataObject}}{{#parameters}}{{^isBodyParam}}{{^isEnum}}{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{dataType}}}{{/datatypeWithEnum}}{{/isEnum}}{{#isEnum}}{{{dataType}}}{{/isEnum}} {{paramName}}{{/isBodyParam}}{{#isBodyParam}}{{^isBinary}}{{^parent}}{{^children}}{{{dataType}}} body{{/children}}{{/parent}}{{/isBinary}}{{/isBodyParam}}{{#hasMore}}{{^isBinary}}, {{/isBinary}}{{/hasMore}}{{^hasMore}}{{^isBinary}}, {{/isBinary}}{{/hasMore}}{{/parameters}}{{/useDataObject}}{{^useDataObject}}RequestParameter body, {{/useDataObject}}ServiceRequest request{{^useFuture}}, Handler> resultHandler{{/useFuture}}); +{{/contents}} +{{/operation}} +{{/operations}} +} diff --git a/src/main/resources/handlebars/JavaVertXServer/apiVerticle.mustache b/src/main/resources/handlebars/JavaVertXServer/apiVerticle.mustache new file mode 100644 index 0000000000..cbdda4c679 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/apiVerticle.mustache @@ -0,0 +1,92 @@ +package {{verticlePackage}}; + +{{#mountFromInterface}}{{#apiInfo}}{{#apis}}import {{{package}}}.{{{classFilename}}}; +import static {{{package}}}.{{{classFilename}}}.WEBSERVICE_ADDRESS_{{#lambda.uppercase}}{{{classFilename}}}{{/lambda.uppercase}}; +{{/apis}}{{/apiInfo}}{{/mountFromInterface}} + +{{#rxInterface}} +import io.reactivex.Completable; +import io.vertx.reactivex.core.AbstractVerticle; +import io.vertx.reactivex.core.eventbus.MessageConsumer; +import io.vertx.reactivex.core.http.HttpServer; +import io.vertx.reactivex.ext.web.Router; +import io.vertx.reactivex.ext.web.openapi.RouterBuilder; +{{/rxInterface}} +{{^rxInterface}} +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Future; +import io.vertx.core.Promise; +import io.vertx.core.http.HttpServer; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.openapi.RouterBuilder; +{{/rxInterface}} +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.openapi.RouterBuilderOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class {{title}}Verticle extends AbstractVerticle { + static final Logger LOGGER = LoggerFactory.getLogger({{title}}Verticle.class); + + HttpServer server; + + @Override + {{^rxInterface}}public void start(Promise startPromise) throws Exception { + RouterBuilder.create(this.vertx, "{{specLocation}}") + .flatMap(routerBuilder -> { {{/rxInterface}} + {{#rxInterface}}public Completable rxStart() { + return RouterBuilder.rxCreate(this.vertx, "{{specLocation}}") + .map(routerBuilder -> { {{/rxInterface}} + RouterBuilderOptions factoryOptions = new RouterBuilderOptions() + .setRequireSecurityHandlers(false) + .setMountResponseContentTypeHandler(true); + routerBuilder.setOptions(factoryOptions); + +{{#mountFromExtensions}} routerBuilder.mountServicesFromExtensions();{{/mountFromExtensions}} +{{#mountFromInterface}}{{#apiInfo}}{{#apis}} routerBuilder.mountServiceInterface({{{classFilename}}}.class, WEBSERVICE_ADDRESS_{{#lambda.uppercase}}{{{classFilename}}}{{/lambda.uppercase}}); + {{/apis}}{{/apiInfo}}{{/mountFromInterface}} + + return {{#rxInterface}}routerBuilder.createRouter(){{/rxInterface}}{{^rxInterface}}Future.succeededFuture(routerBuilder.createRouter()){{/rxInterface}}; + }) + .flatMap(openapiRouter -> { + Router router = Router.router(vertx); + + server = vertx.createHttpServer(new HttpServerOptions().setPort({{serverPort}}).setHost("localhost")) + .requestHandler(router); + + router.route("/*").subRouter(openapiRouter); + + router.route().last().handler(context -> + context.response() + .setStatusCode(404) + .end(new JsonObject() + .put("message", "Resource not found") + .encode()) + ); + + {{#rxInterface}}return server.rxListen() + .doOnSuccess(server -> LOGGER.info("SwaggerPetstoreVerticle started on port " + server.actualPort())); + }) + .ignoreElement(); + } + + @Override + public Completable rxStop() { + return this.server.rxClose(); + }{{/rxInterface}} + {{^rxInterface}}return server.listen() + .onSuccess(server -> LOGGER.info("{{title}}Verticle started on port " + server.actualPort())); + }) + .onSuccess(server -> startPromise.complete()) + .onFailure(startPromise::fail); + } + + @Override + public void stop(Promise stopPromise) throws Exception { + this.server.close() + .onSuccess(server -> stopPromise.complete()) + .onFailure(stopPromise::fail); + }{{/rxInterface}} + +} diff --git a/src/main/resources/mustache/JavaSpring/beanValidation.mustache b/src/main/resources/handlebars/JavaVertXServer/beanValidation.mustache similarity index 100% rename from src/main/resources/mustache/JavaSpring/beanValidation.mustache rename to src/main/resources/handlebars/JavaVertXServer/beanValidation.mustache diff --git a/src/main/resources/handlebars/JavaVertXServer/beanValidationCore.mustache b/src/main/resources/handlebars/JavaVertXServer/beanValidationCore.mustache new file mode 100644 index 0000000000..29d043cc77 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/beanValidationCore.mustache @@ -0,0 +1,20 @@ +{{#pattern}}@Pattern(regexp="{{{pattern}}}"{{#vendorExtensions.x-pattern-message}}, message="{{vendorExtensions.x-pattern-message}}"{{/vendorExtensions.x-pattern-message}}) {{/pattern}}{{! +minLength && maxLength set +}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +minLength set, maxLength not +}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{! +minLength not set, maxLength set +}}{{^minLength}}{{#maxLength}}@Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{! +@Size: minItems && maxItems set +}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems set, maxItems not +}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{! +@Size: minItems not set && maxItems set +}}{{^minItems}}{{#maxItems}}@Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{! +check for integer or long / all others=decimal type with @Decimal* +isInteger set +}}{{#isInteger}}{{#minimum}}@Min({{minimum}}){{/minimum}}{{#maximum}} @Max({{maximum}}) {{/maximum}}{{/isInteger}}{{! +isLong set +}}{{#isLong}}{{#minimum}}@Min({{minimum}}L){{/minimum}}{{#maximum}} @Max({{maximum}}L) {{/maximum}}{{/isLong}}{{! +Not Integer, not Long => we have a decimal value! +}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin("{{minimum}}"){{/minimum}}{{#maximum}} @DecimalMax("{{maximum}}") {{/maximum}}{{/isLong}}{{/isInteger}} \ No newline at end of file diff --git a/src/main/resources/handlebars/JavaVertXServer/enumClass.mustache b/src/main/resources/handlebars/JavaVertXServer/enumClass.mustache new file mode 100644 index 0000000000..17981cd6d2 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/enumClass.mustache @@ -0,0 +1,35 @@ + /** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{{description}}}{{/description}} + */ + public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}} { + {{#allowableValues}}{{#enumVars}}{{{name}}}({{{value}}}){{^@last}}, + {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} + + private {{{datatype}}} value; + + {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{classname}}{{/datatypeWithEnum}}({{{datatype}}} value) { + this.value = value; + } + + public {{{datatype}}} getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{datatype}}} value) { + for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if (b.value.equals(value)) { + return b; + } + } + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + value + "' for '{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}' enum.");{{/errorOnUnknownEnum}} + } + {{#useDataObject}} + public static {{{datatype}}} serialize({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} enumValue) { + return enumValue.getValue(); + }{{/useDataObject}} + } diff --git a/src/main/resources/handlebars/JavaVertXServer/enumOuterClass.mustache b/src/main/resources/handlebars/JavaVertXServer/enumOuterClass.mustache new file mode 100644 index 0000000000..f90c462a72 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/enumOuterClass.mustache @@ -0,0 +1,35 @@ +/** + * {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} + */ +public enum {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} { + {{#allowableValues}}{{#enumVars}}{{{name}}}({{{value}}}){{^@last}}, + {{/@last}}{{#@last}};{{/@last}}{{/enumVars}}{{/allowableValues}} + + private {{{dataType}}} value; + + {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}({{{dataType}}} value) { + this.value = value; + } + + public {{{dataType}}} getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} fromValue({{{dataType}}} value) { + for ({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} b : {{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.values()) { + if (b.value.equals(value)) { + return b; + } + } + {{^errorOnUnknownEnum}}return null;{{/errorOnUnknownEnum}}{{#errorOnUnknownEnum}}throw new IllegalArgumentException("Unexpected value '" + value + "' for '{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}' enum.");{{/errorOnUnknownEnum}} + } + {{#useDataObject}} + public static {{{dataType}}} serialize({{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}} enumValue) { + return enumValue.getValue(); + }{{/useDataObject}} +} diff --git a/src/main/resources/handlebars/JavaVertXServer/generatedAnnotation.mustache b/src/main/resources/handlebars/JavaVertXServer/generatedAnnotation.mustache new file mode 100644 index 0000000000..64e613df8c --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/generatedAnnotation.mustache @@ -0,0 +1,3 @@ +{{^hideGenerationTimestamp}} +@{{#jakarta}}jakarta{{/jakarta}}{{^jakarta}}javax{{/jakarta}}.annotation.Generated(value = "{{generatorClass}}", date = "{{generatedDate}}") +{{/hideGenerationTimestamp}} diff --git a/src/main/resources/handlebars/JavaVertXServer/json-mappers.mustache b/src/main/resources/handlebars/JavaVertXServer/json-mappers.mustache new file mode 100644 index 0000000000..a15f23ed1a --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/json-mappers.mustache @@ -0,0 +1,38 @@ +{{#models}} +{{#model}} +{{#isEnum}} +{{modelPackage}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.serializer={{modelPackage}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}#serialize +{{modelPackage}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.deserializer={{modelPackage}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}#fromValue +{{/isEnum}} +{{^isEnum}} + {{#vars}} + {{#isEnum}} +{{modelPackage}}.{{classname}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.serializer={{modelPackage}}.{{classname}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}#serialize +{{modelPackage}}.{{classname}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}.deserializer={{modelPackage}}.{{classname}}.{{#datatypeWithEnum}}{{{.}}}{{/datatypeWithEnum}}{{^datatypeWithEnum}}{{{classname}}}{{/datatypeWithEnum}}#fromValue + {{/isEnum}} + {{/vars}} +{{/isEnum}} +{{/model}} +{{/models}} +{{#java8}} +java.time.LocalDate.serializer={{modelPackage}}.DataObjectMapper#serializeLocalDate +java.time.LocalDate.deserializer=java.time.LocalDate#parse +java.time.LocalDateTime.serializer={{modelPackage}}.DataObjectMapper#serializeLocalDateTime +java.time.LocalDateTime.deserializer=java.time.LocalDateTime#parse +java.time.OffsetDateTime.serializer={{modelPackage}}.DataObjectMapper#serializeOffsetDateTime +java.time.OffsetDateTime.deserializer=java.time.OffsetDateTime#parse +{{/java8}} +{{#threetenbp}} +org.threeten.bp.Instant.serializer={{modelPackage}}.DataObjectMapper#serializeThreetenbpInstant +org.threeten.bp.Instant.deserializer=org.threeten.bp.Instant#parse +org.threeten.bp.OffsetDateTime.serializer={{modelPackage}}.DataObjectMapper#serializeThreetenbpOffsetDateTime +org.threeten.bp.OffsetDateTime.deserializer=org.threeten.bp.OffsetDateTime#parse +org.threeten.bp.ZonedDateTime.serializer={{modelPackage}}.DataObjectMapper#serializeThreetenbpZonedDateTime +org.threeten.bp.ZonedDateTime.deserializer=org.threeten.bp.ZonedDateTime#parse +{{/threetenbp}} +{{#joda}} +org.joda.time.LocalDate.serializer={{modelPackage}}.DataObjectMapper#serializeJodaLocalDate +org.joda.time.LocalDate.deserializer=org.joda.time.LocalDate#parse +org.joda.time.DateTime.serializer={{modelPackage}}.DataObjectMapper#serializeJodaDateTime +org.joda.time.DateTime.deserializer=org.joda.time.DateTime#parse +{{/joda}} diff --git a/src/main/resources/handlebars/JavaVertXServer/model.mustache b/src/main/resources/handlebars/JavaVertXServer/model.mustache new file mode 100644 index 0000000000..e091cba3fe --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/model.mustache @@ -0,0 +1,37 @@ +package {{package}}; + +{{^x-is-composed-model}} +import java.util.Objects; +{{#imports}}import {{import}}; +{{/imports}} +{{#serializableModel}} +import java.io.Serializable; +{{/serializableModel}} +{{#useBeanValidation}} +{{#jakarta}} +import javax.validation.constraints.*; +import javax.validation.Valid; +{{/jakarta}} +{{^jakarta}} +import javax.validation.constraints.*; +import javax.validation.Valid; +{{/jakarta}} +{{/useBeanValidation}} +{{/x-is-composed-model}} +import io.vertx.core.json.JsonObject; +import io.vertx.codegen.annotations.DataObject; +{{#models}} +{{#model}} +{{#isComposedModel}} +{{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} +{{#isEnum}} +{{>enumOuterClass}} +{{/isEnum}} +{{^isEnum}} +{{>pojo}} +{{/isEnum}} +{{/isComposedModel}} +{{/model}} +{{/models}} diff --git a/src/main/resources/handlebars/JavaVertXServer/package-info-model.mustache b/src/main/resources/handlebars/JavaVertXServer/package-info-model.mustache new file mode 100644 index 0000000000..4d5382212e --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/package-info-model.mustache @@ -0,0 +1,4 @@ +@ModuleGen(name = "model", groupPackage = "{{modelPackage}}") +package {{modelPackage}}; + +import io.vertx.codegen.annotations.ModuleGen; diff --git a/src/main/resources/handlebars/JavaVertXServer/package-info-service.mustache b/src/main/resources/handlebars/JavaVertXServer/package-info-service.mustache new file mode 100644 index 0000000000..af43bd8038 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/package-info-service.mustache @@ -0,0 +1,4 @@ +@ModuleGen(name = "service", groupPackage = "{{apiPackage}}", useFutures = {{#useFuture}}true{{/useFuture}}{{^useFuture}}false{{/useFuture}}) +package {{apiPackage}}; + +import io.vertx.codegen.annotations.ModuleGen; diff --git a/src/main/resources/handlebars/JavaVertXServer/pojo.mustache b/src/main/resources/handlebars/JavaVertXServer/pojo.mustache new file mode 100644 index 0000000000..930b070c71 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/pojo.mustache @@ -0,0 +1,147 @@ +/** + * {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} + */ +{{#useBeanValidation}}@Valid{{/useBeanValidation}} +{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}} +{{#notNullJacksonAnnotation}}@JsonInclude(JsonInclude.Include.NON_NULL){{/notNullJacksonAnnotation}} +{{#useDataObject}}@DataObject(generateConverter = true, publicConverter = false){{/useDataObject}} + +public class {{classname}} {{#parent}}extends {{{parent}}}{{/parent}} {{#serializableModel}}implements Serializable {{#interfaceModels}}, {{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}}{{/serializableModel}}{{^serializableModel}}{{#interfaceModels}}{{#@first}}implements {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}}{{/@last}}{{/interfaceModels}}{{/serializableModel}} { +{{#serializableModel}} + private static final long serialVersionUID = 1L; + +{{/serializableModel}} + {{#vars}} + {{#baseItems this}} + {{#isEnum}} +{{>enumClass}} + {{/isEnum}} + {{/baseItems}} + {{#jackson}} + {{#vendorExtensions.x-is-discriminator-property}} + @JsonTypeId + {{/vendorExtensions.x-is-discriminator-property}} + {{^vendorExtensions.x-is-discriminator-property}} + @JsonProperty("{{baseName}}") + {{/vendorExtensions.x-is-discriminator-property}} + {{/jackson}} + {{#isContainer}} + {{#useBeanValidation}}@Valid{{/useBeanValidation}} + private {{{datatypeWithEnum}}} {{name}}{{#required}} = {{{defaultValue}}}{{/required}}{{^required}} = null{{/required}}; + {{/isContainer}} + {{^isContainer}} + private {{{datatypeWithEnum}}} {{name}} = {{{defaultValue}}}; + {{/isContainer}} + + {{/vars}} +{{#useDataObject}} + public {{classname}}(JsonObject json) { + {{#parent}}{{#hasVars}}super(json);{{/hasVars}}{{/parent}} + {{classname}}Converter.fromJson(json, this); + } + + public JsonObject toJson() { + JsonObject json = new JsonObject(); + {{classname}}Converter.toJson(this, json); + return json; + } +{{/useDataObject}} + {{#vars}} + public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) { + this.{{name}} = {{name}}; + return this; + } + {{#isListContainer}} + + public {{classname}} add{{nameInCamelCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) { + {{^required}} + if (this.{{name}} == null) { + this.{{name}} = {{{defaultValue}}}; + } + {{/required}} + this.{{name}}.add({{name}}Item); + return this; + } + {{/isListContainer}} + {{#isMapContainer}} + + public {{classname}} put{{nameInCamelCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) { + {{^required}} + if (this.{{name}} == null) { + this.{{name}} = {{{defaultValue}}}; + } + {{/required}} + this.{{name}}.put(key, {{name}}Item); + return this; + } + {{/isMapContainer}} + + /** + {{#description}} + * {{{description}}} + {{/description}} + {{^description}} + * Get {{name}} + {{/description}} + {{#minimum}} + * minimum: {{minimum}} + {{/minimum}} + {{#maximum}} + * maximum: {{maximum}} + {{/maximum}} + * @return {{name}} + **/ + {{#vendorExtensions.extraAnnotation}} + {{{vendorExtensions.extraAnnotation}}} + {{/vendorExtensions.extraAnnotation}} + {{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}} public {{{datatypeWithEnum}}} {{getter}}() { + return {{name}}; + } + + public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { + this.{{name}} = {{name}}; + } + + {{/vars}} + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + }{{#hasVars}} + {{classname}} {{classVarName}} = ({{classname}}) o; + return {{#vars}}Objects.equals(this.{{name}}, {{classVarName}}.{{name}}){{#hasMore}} && + {{/hasMore}}{{/vars}}{{#parent}} && + super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}} + return true;{{/hasVars}} + } + + @Override + public int hashCode() { + return Objects.hash({{#vars}}{{name}}{{#hasMore}}, {{/hasMore}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}}); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class {{classname}} {\n"); + {{#parent}}sb.append(" ").append(toIndentedString(super.toString())).append("\n");{{/parent}} + {{#vars}}sb.append(" {{name}}: ").append(toIndentedString({{name}})).append("\n"); + {{/vars}}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/src/main/resources/handlebars/JavaVertXServer/pom.mustache b/src/main/resources/handlebars/JavaVertXServer/pom.mustache new file mode 100644 index 0000000000..e1127c0993 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/pom.mustache @@ -0,0 +1,156 @@ + + 4.0.0 + + {{groupId}} + {{artifactId}} + {{artifactVersion}} + jar + + {{appName}} + + + UTF-8 + {{#java11}}11{{/java11}}{{^java11}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/java11}} + 5.9.1 + 4.4.1 + 3.8.1 + 3.2.4 + 2.14.2 + 2.12.5 + 2.0.6 + + + + + + io.vertx + vertx-web-openapi + ${vertx.version} + + + io.vertx + vertx-web-api-service + ${vertx.version} + + {{#rxInterface}} + + io.vertx + vertx-rx-java2 + ${vertx.version} + + {{/rxInterface}} + + org.slf4j + slf4j-api + ${slf4j-version} + + + + io.vertx + vertx-codegen + ${vertx.version} + provided + + + + io.vertx + vertx-codegen + ${vertx.version} + processor + + + {{#java8}} + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + {{/java8}} + {{#joda}} + + com.fasterxml.jackson.datatype + jackson-datatype-joda + ${jackson.version} + + {{/joda}} + {{#threetenbp}} + + com.github.joschi.jackson + jackson-datatype-threetenbp + ${joschi.version} + + {{/threetenbp}} + + {{#useBeanValidation}} + + + jakarta.validation + jakarta.validation-api + {{#jakarta}}3.0.2{{/jakarta}}{{^jakarta}}2.0.2{{/jakarta}} + + {{/useBeanValidation}} + {{#notNullJacksonAnnotation}} + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + {{/notNullJacksonAnnotation}} + + + io.vertx + vertx-junit5 + ${vertx.version} + test + + + + org.junit.jupiter + junit-jupiter + ${jupiter.version} + test + + + + + + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin.version} + + + package + + shade + + + + + + io.vertx.core.Launcher + {{rootPackage}}.MainApiVerticle + + + + + ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar + + + + + + + diff --git a/src/main/resources/handlebars/JavaVertXServer/typeInfoAnnotation.mustache b/src/main/resources/handlebars/JavaVertXServer/typeInfoAnnotation.mustache new file mode 100644 index 0000000000..f3ed515976 --- /dev/null +++ b/src/main/resources/handlebars/JavaVertXServer/typeInfoAnnotation.mustache @@ -0,0 +1,14 @@ +{{#jackson}} +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{discriminator.propertyName}}", visible = true ) +@JsonSubTypes({ + {{#if discriminator.mapping}} + {{#each discriminator.mapping}} + @JsonSubTypes.Type(value = {{this}}.class, name = "{{@key}}"), + {{/each}} + {{else}} + {{#children}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{name}}"), + {{/children}} + {{/if}} +}) +{{/jackson}} \ No newline at end of file diff --git a/src/main/resources/handlebars/R/NAMESPACE.mustache b/src/main/resources/handlebars/R/NAMESPACE.mustache new file mode 100644 index 0000000000..0fe95acd6d --- /dev/null +++ b/src/main/resources/handlebars/R/NAMESPACE.mustache @@ -0,0 +1,8 @@ +# Generated by swagger-codegen: https://github.com/swagger-api/swagger-codegen +# Do not edit by hand + +{{#models}} +{{#model}} +export({{{classname}}}) +{{/model}} +{{/models}} diff --git a/src/main/resources/handlebars/R/README.mustache b/src/main/resources/handlebars/R/README.mustache new file mode 100644 index 0000000000..a79bef4480 --- /dev/null +++ b/src/main/resources/handlebars/R/README.mustache @@ -0,0 +1,41 @@ +# R API client for {{packageName}} + +{{#appDescription}} +{{{appDescription}}} +{{/appDescription}} + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI/Swagger spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: {{appVersion}} +- Package version: {{packageVersion}} +{{^hideGenerationTimestamp}} +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} +- Build package: {{generatorClass}} +{{#infoUrl}} +For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +## Installation +You'll need the `devtools` package in order to build the API. +Make sure you have a proper CRAN repository from which you can download packages. + +### Prerequisites +Install the `devtools` package with the following command. +```R +if(!require(devtools)) { install.packages("devtools") } +``` + +### Installation of the API package +Make sure you set the working directory to where the API code is located. +Then execute +```R +library(devtools) +install(".") +``` + +## Author + +{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} +{{/hasMore}}{{/apis}}{{/apiInfo}} diff --git a/src/main/resources/handlebars/R/Rbuildignore.mustache b/src/main/resources/handlebars/R/Rbuildignore.mustache new file mode 100644 index 0000000000..91114bf2f2 --- /dev/null +++ b/src/main/resources/handlebars/R/Rbuildignore.mustache @@ -0,0 +1,2 @@ +^.*\.Rproj$ +^\.Rproj\.user$ diff --git a/src/main/resources/handlebars/R/api.mustache b/src/main/resources/handlebars/R/api.mustache new file mode 100644 index 0000000000..e42fcf1041 --- /dev/null +++ b/src/main/resources/handlebars/R/api.mustache @@ -0,0 +1,115 @@ +{{>partial_header}} +{{#operations}} +#' @title {{baseName}} operations +#' @description {{importPath}} +#' +#' @field path Stores url path of the request. +#' @field apiClient Handles the client-server communication. +#' @field userAgent Set the user agent of the request. +#' +#' @importFrom R6 R6Class +#' +#' @section Methods: +#' \describe{ +{{#operation}} +#' +#' {{operationId}} {{summary}} +#' +{{/operation}} +#' } +#' +#' @export +{{classname}} <- R6::R6Class( + '{{classname}}', + public = list( + userAgent = "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/r{{/httpUserAgent}}", + apiClient = NULL, + initialize = function(apiClient){ + if (!missing(apiClient)) { + self$apiClient <- apiClient + } + else { + self$apiClient <- ApiClient$new() + } + }, + {{#operation}} + {{operationId}} = function({{#allParams}}{{paramName}}, {{/allParams}}...){ + args <- list(...) + queryParams <- list() + headerParams <- character() + + {{#hasHeaderParams}} + {{#headerParams}} + if (!missing(`{{paramName}}`)) { + headerParams['{{baseName}}'] <- `{{paramName}}` + } + + {{/headerParams}} + {{/hasHeaderParams}} + {{#hasQueryParams}} + {{#queryParams}} + if (!missing(`{{paramName}}`)) { + queryParams['{{baseName}}'] <- {{paramName}} + } + + {{/queryParams}} + {{/hasQueryParams}} + {{#hasFormParams}} + body <- list( + {{#formParams}} + {{^isFile}} + "{{baseName}}" = {{paramName}}{{#hasMore}},{{/hasMore}} + {{/isFile}} + {{#isFile}} + "{{baseName}}" = httr::upload_file({{paramName}}){{#hasMore}},{{/hasMore}} + {{/isFile}} + {{/formParams}} + ) + + {{/hasFormParams}} + {{#hasBodyParam}} + {{#bodyParams}} + if (!missing(`{{paramName}}`)) { + body <- `{{paramName}}`$toJSONString() + } else { + body <- NULL + } + + {{/bodyParams}} + {{/hasBodyParam}} + urlPath <- "{{path}}" + {{#hasPathParams}} + {{#pathParams}} + if (!missing(`{{paramName}}`)) { + urlPath <- gsub(paste0("\\{", "{{baseName}}", "\\}"), `{{paramName}}`, urlPath) + } + + {{/pathParams}} + {{/hasPathParams}} + resp <- self$apiClient$callApi(url = paste0(self$apiClient$basePath, urlPath), + method = "{{httpMethod}}", + queryParams = queryParams, + headerParams = headerParams, + body = body, + ...) + + if (httr::status_code(resp) >= 200 && httr::status_code(resp) <= 299) { + {{#returnType}} + returnObject <- {{returnType}}$new() + result <- returnObject$fromJSON(httr::content(resp, "text", encoding = "UTF-8")) + Response$new(returnObject, resp) + {{/returnType}} + {{^returnType}} + # void response, no need to return anything + {{/returnType}} + } else if (httr::status_code(resp) >= 400 && httr::status_code(resp) <= 499) { + Response$new("API client error", resp) + } else if (httr::status_code(resp) >= 500 && httr::status_code(resp) <= 599) { + Response$new("API server error", resp) + } + + }{{#hasMore}},{{/hasMore}} + {{/operation}} + ) +) +{{/operations}} diff --git a/src/main/resources/handlebars/R/api_client.mustache b/src/main/resources/handlebars/R/api_client.mustache new file mode 100644 index 0000000000..49e22e1c5c --- /dev/null +++ b/src/main/resources/handlebars/R/api_client.mustache @@ -0,0 +1,64 @@ +{{>partial_header}} + +#' ApiClient Class +#' +#' Generic API client for Swagger client library builds. +#' Swagger generic API client. This client handles the client- +#' server communication, and is invariant across implementations. Specifics of +#' the methods and models for each application are generated from the Swagger +#' templates. +#' +#' NOTE: This class is auto generated by the swagger code generator program. +#' Ref: https://github.com/swagger-api/swagger-codegen +#' Do not edit the class manually. +#' +#' @export +ApiClient <- R6::R6Class( + 'ApiClient', + public = list( + basePath = "{{{basePath}}}", + configuration = NULL, + userAgent = NULL, + defaultHeaders = NULL, + initialize = function(basePath, configuration, defaultHeaders){ + if (!missing(basePath)) { + self$basePath <- basePath + } + + if (!missing(configuration)) { + self$configuration <- configuration + } + + if (!missing(defaultHeaders)) { + self$defaultHeaders <- defaultHeaders + } + + self$`userAgent` <- '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/r{{/httpUserAgent}}' + }, + callApi = function(url, method, queryParams, headerParams, body, ...){ + headers <- httr::add_headers(headerParams) + + if (method == "GET") { + httr::GET(url, queryParams, headers, ...) + } + else if (method == "POST") { + httr::POST(url, queryParams, headers, body = body, ...) + } + else if (method == "PUT") { + httr::PUT(url, queryParams, headers, body = body, ...) + } + else if (method == "PATCH") { + httr::PATCH(url, queryParams, headers, body = body, ...) + } + else if (method == "HEAD") { + httr::HEAD(url, queryParams, headers, ...) + } + else if (method == "DELETE") { + httr::DELETE(url, queryParams, headers, ...) + } + else { + stop("http method must be `GET`, `HEAD`, `OPTIONS`, `POST`, `PATCH`, `PUT` or `DELETE`.") + } + } + ) +) \ No newline at end of file diff --git a/src/main/resources/handlebars/R/api_doc.mustache b/src/main/resources/handlebars/R/api_doc.mustache new file mode 100644 index 0000000000..229eccb663 --- /dev/null +++ b/src/main/resources/handlebars/R/api_doc.mustache @@ -0,0 +1,50 @@ +# {{invokerPackage}}\{{classname}}{{#description}} +{{description}}{{/description}} + +All URIs are relative to *{{basePath}}* + +Method | HTTP request | Description +------------- | ------------- | ------------- +{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} +{{/operation}}{{/operations}} + +{{#operations}} +{{#operation}} +# **{{{operationId}}}** +> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#authMethods}}ctx, {{/authMethods}}{{#allParams}}{{#required}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/allParams}}{{#hasOptionalParams}}optional{{/hasOptionalParams}}) +{{{summary}}}{{#notes}} + +{{{notes}}}{{/notes}} + +### Required Parameters +{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#@last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | -------------{{#authMethods}} + **ctx** | **context.Context** | context containing the authentication | nil if no authentication{{/authMethods}}{{/@last}}{{/allParams}}{{#allParams}}{{#required}} + **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}{{/required}}{{/allParams}}{{#hasOptionalParams}} + **optional** | **map[string]interface{}** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a map[string]interface{}. +{{#allParams}}{{#@last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | -------------{{/@last}}{{/allParams}}{{#allParams}} + **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}{{/allParams}}{{/hasOptionalParams}} + +### Return type + +{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}} (empty response body){{/returnType}} + +### Authorization + +{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^@last}}, {{/@last}}{{/authMethods}} + +### HTTP request headers + + - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} + - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +{{/operation}} +{{/operations}} diff --git a/src/main/resources/handlebars/R/description.mustache b/src/main/resources/handlebars/R/description.mustache new file mode 100644 index 0000000000..d79645cdaf --- /dev/null +++ b/src/main/resources/handlebars/R/description.mustache @@ -0,0 +1,12 @@ +Package: {{{packageName}}} +Title: R Package Client for {{{appName}}} +Version: {{packageVersion}} +Authors@R: person("Swagger Codegen community", email = "apiteam@swagger.io", role = c("aut", "cre")) +Description: {{{appDescription}}}{{^appDescription}}R Package Client for {{{appName}}}{{/appDescription}} +Depends: R (>= 3.3.3) +Encoding: UTF-8 +License: Unlicense +LazyData: true +Suggests: testthat +Imports: jsonlite, httr, R6 +RoxygenNote: 6.0.1.9000 diff --git a/src/main/resources/handlebars/R/element.mustache b/src/main/resources/handlebars/R/element.mustache new file mode 100644 index 0000000000..c8b6632f72 --- /dev/null +++ b/src/main/resources/handlebars/R/element.mustache @@ -0,0 +1,24 @@ +#' Element Class +#' +#' Element Class +#' @export +Element <- R6::R6Class( + 'Element', + public = list( + id = NULL, + name = NULL, + initialize = function(id,name){ + if (!missing(id)) { + stopifnot(is.numeric(id), length(id) == 1) + self$id <- id + } + if (!missing(name)) { + stopifnot(is.character(name), length(name) == 1) + self$name <- name + } + }, + toJSON = function() { + sprintf('{"id":%d,"name":"%s"}', self$id, self$name) + } + ) +) \ No newline at end of file diff --git a/src/main/resources/mustache/csharp/git_push.sh.mustache b/src/main/resources/handlebars/R/git_push.sh.mustache similarity index 100% rename from src/main/resources/mustache/csharp/git_push.sh.mustache rename to src/main/resources/handlebars/R/git_push.sh.mustache diff --git a/src/main/resources/handlebars/R/gitignore.mustache b/src/main/resources/handlebars/R/gitignore.mustache new file mode 100644 index 0000000000..5d21150e0c --- /dev/null +++ b/src/main/resources/handlebars/R/gitignore.mustache @@ -0,0 +1,35 @@ +# ref: https://github.com/github/gitignore/blob/master/R.gitignore + +# History files +.Rhistory +.Rapp.history + +# Session Data files +.RData + +# Example code in package build process +*-Ex.R + +# Output files from R CMD build +/*.tar.gz + +# Output files from R CMD check +/*.Rcheck/ + +# RStudio files +.Rproj.user/ + +# produced vignettes +vignettes/*.html +vignettes/*.pdf + +# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 +.httr-oauth + +# knitr and R markdown default cache directories +/*_cache/ +/cache/ + +# Temporary files created by R markdown +*.utf8.md +*.knit.md diff --git a/src/main/resources/handlebars/R/model.mustache b/src/main/resources/handlebars/R/model.mustache new file mode 100644 index 0000000000..af5b5cc9ec --- /dev/null +++ b/src/main/resources/handlebars/R/model.mustache @@ -0,0 +1,139 @@ +{{#models}} +{{#model}} +{{>partial_header}} + +#' {{classname}} Class +#' +{{#vars}} +#' @field {{baseName}} {{title}} +{{/vars}} +#' +#' @importFrom R6 R6Class +#' @importFrom jsonlite fromJSON toJSON +#' @export +{{classname}} <- R6::R6Class( + '{{classname}}', + public = list( + {{#vars}} + `{{{baseName}}}` = NULL, + {{/vars}} + initialize = function({{#vars}}`{{baseName}}`{{#hasMore}}, {{/hasMore}}{{/vars}}){ + {{#vars}} + if (!missing(`{{baseName}}`)) { + {{^isListContainer}} + {{#isInteger}} + stopifnot(is.numeric(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isInteger}} + {{#isLong}} + stopifnot(is.numeric(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isLong}} + {{#isFloat}} + stopifnot(is.numeric(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isFloat}} + {{#isDouble}} + stopifnot(is.numeric(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isDouble}} + {{#isString}} + stopifnot(is.character(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isString}} + {{#isDate}} + stopifnot(is.character(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isDate}} + {{#isDateTime}} + stopifnot(is.character(`{{baseName}}`), length(`{{baseName}}`) == 1) + {{/isDateTime}} + {{^isPrimitiveType}} + stopifnot(R6::is.R6(`{{baseName}}`)) + {{/isPrimitiveType}} + {{/isListContainer}} + {{#isListContainer}} + {{#isPrimitiveType}} + stopifnot(is.list(`{{baseName}}`), length(`{{baseName}}`) != 0) + lapply(`{{baseName}}`, function(x) stopifnot(is.character(x))) + {{/isPrimitiveType}} + {{^isPrimitiveType}} + stopifnot(is.list(`{{baseName}}`), length(`{{baseName}}`) != 0) + lapply(`{{baseName}}`, function(x) stopifnot(R6::is.R6(x))) + {{/isPrimitiveType}} + {{/isListContainer}} + self$`{{baseName}}` <- `{{baseName}}` + } + {{/vars}} + }, + toJSON = function() { + {{classname}}Object <- list() + {{#vars}} + if (!is.null(self$`{{baseName}}`)) { + {{classname}}Object[['{{baseName}}']] <- {{#isListContainer}}{{#isPrimitiveType}}self$`{{baseName}}`{{/isPrimitiveType}}{{^isPrimitiveType}}lapply(self$`{{baseName}}`, function(x) x$toJSON()){{/isPrimitiveType}}{{/isListContainer}}{{^isListContainer}}self$`{{baseName}}`{{^isPrimitiveType}}$toJSON(){{/isPrimitiveType}}{{/isListContainer}} + } + {{/vars}} + + {{classname}}Object + }, + fromJSON = function({{classname}}Json) { + {{classname}}Object <- jsonlite::fromJSON({{classname}}Json) + {{#vars}} + if (!is.null({{classname}}Object$`{{baseName}}`)) { + {{#isPrimitiveType}} + self$`{{baseName}}` <- {{classname}}Object$`{{baseName}}` + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{#isListContainer}} + self$`{{baseName}}` <- lapply({{classname}}Object$`{{baseName}}`, function(x) { + {{baseName}}Object <- {{datatype}}$new() + {{baseName}}Object$fromJSON(jsonlite::toJSON(x, auto_unbox = TRUE)) + {{baseName}}Object + }) + {{/isListContainer}} + {{^isListContainer}} + {{baseName}}Object <- {{datatype}}$new() + {{baseName}}Object$fromJSON(jsonlite::toJSON({{classname}}Object${{baseName}}, auto_unbox = TRUE)) + self$`{{baseName}}` <- {{baseName}}Object + {{/isListContainer}} + {{/isPrimitiveType}} + } + {{/vars}} + }, + toJSONString = function() { + sprintf( + '{ + {{#vars}} + "{{baseName}}": {{#isListContainer}}[{{/isListContainer}}{{#isPrimitiveType}}{{#isNumeric}}%d{{/isNumeric}}{{^isNumeric}}%s{{/isNumeric}}{{/isPrimitiveType}}{{^isPrimitiveType}}%s{{/isPrimitiveType}}{{#isListContainer}}]{{/isListContainer}}{{#hasMore}},{{/hasMore}} + {{/vars}} + }', + {{#vars}} + {{#isListContainer}} + {{#isPrimitiveType}} + lapply(self$`{{baseName}}`, function(x) paste(paste0('"', x, '"'), sep=",")){{#hasMore}},{{/hasMore}} + {{/isPrimitiveType}} + {{^isPrimitiveType}} + lapply(self$`{{baseName}}`, function(x) paste(x$toJSON(), sep=",")){{#hasMore}},{{/hasMore}} + {{/isPrimitiveType}} + {{/isListContainer}} + {{^isListContainer}} + self$`{{baseName}}`{{^isPrimitiveType}}$toJSON(){{/isPrimitiveType}}{{#hasMore}},{{/hasMore}} + {{/isListContainer}} + {{/vars}} + ) + }, + fromJSONString = function({{classname}}Json) { + {{classname}}Object <- jsonlite::fromJSON({{classname}}Json) + {{#vars}} + {{#isPrimitiveType}} + self$`{{baseName}}` <- {{classname}}Object$`{{baseName}}` + {{/isPrimitiveType}} + {{^isPrimitiveType}} + {{#isListContainer}} + self$`{{baseName}}` <- lapply({{classname}}Object$`{{baseName}}`, function(x) {{datatype}}$new()$fromJSON(jsonlite::toJSON(x, auto_unbox = TRUE))) + {{/isListContainer}} + {{^isListContainer}} + {{datatype}}Object <- {{datatype}}$new() + self$`{{baseName}}` <- {{datatype}}Object$fromJSON(jsonlite::toJSON({{classname}}Object${{baseName}}, auto_unbox = TRUE)) + {{/isListContainer}} + {{/isPrimitiveType}} + {{/vars}} + } + ) +) +{{/model}} +{{/models}} diff --git a/src/main/resources/handlebars/R/model_doc.mustache b/src/main/resources/handlebars/R/model_doc.mustache new file mode 100644 index 0000000000..25537b2c5e --- /dev/null +++ b/src/main/resources/handlebars/R/model_doc.mustache @@ -0,0 +1,11 @@ +{{#models}}{{#model}}# {{classname}} + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{{datatype}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{{datatype}}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}} +{{/vars}} + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + +{{/model}}{{/models}} diff --git a/src/main/resources/handlebars/R/partial_header.mustache b/src/main/resources/handlebars/R/partial_header.mustache new file mode 100644 index 0000000000..7e8a2e0a27 --- /dev/null +++ b/src/main/resources/handlebars/R/partial_header.mustache @@ -0,0 +1,11 @@ +{{#appName}} +# {{{appName}}} +# +{{/appName}} +{{#appDescription}} +# {{{appDescription}}} +# +{{/appDescription}} +# {{#version}}OpenAPI spec version: {{{version}}}{{/version}} +# {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} +# Generated by: https://github.com/swagger-api/swagger-codegen.git diff --git a/src/main/resources/handlebars/R/response.mustache b/src/main/resources/handlebars/R/response.mustache new file mode 100644 index 0000000000..42873beb4e --- /dev/null +++ b/src/main/resources/handlebars/R/response.mustache @@ -0,0 +1,15 @@ +#' Response Class +#' +#' Response Class +#' @export +Response <- R6::R6Class( + 'Response', + public = list( + content = NULL, + response = NULL, + initialize = function(content, response){ + self$content <- content + self$response <- response + } + ) +) \ No newline at end of file diff --git a/src/main/resources/handlebars/aspnetcore/2.1/Dockerfile.mustache b/src/main/resources/handlebars/aspnetcore/2.1/Dockerfile.mustache new file mode 100644 index 0000000000..aaee7ee659 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/2.1/Dockerfile.mustache @@ -0,0 +1,18 @@ +FROM mcr.microsoft.com/dotnet/core/sdk:{{aspNetCoreVersion}} AS build-env +WORKDIR /app + +ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 + +# copy csproj and restore as distinct layers +COPY *.csproj ./ +RUN dotnet restore + +# copy everything else and build +COPY . ./ +RUN dotnet publish -c Release -o out + +# build runtime image +FROM mcr.microsoft.com/dotnet/core/aspnet:{{aspNetCoreVersion}} +WORKDIR /app +COPY --from=build-env /app/out . +ENTRYPOINT ["dotnet", "{{packageName}}.dll"] diff --git a/src/main/resources/handlebars/aspnetcore/2.1/Program.mustache b/src/main/resources/handlebars/aspnetcore/2.1/Program.mustache new file mode 100644 index 0000000000..21a504c8aa --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/2.1/Program.mustache @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore; + +namespace {{packageName}} +{ + ///

+ /// Program + /// + public class Program + { + /// + /// Main + /// + /// + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + /// + /// Create the web host builder. + /// + /// + /// IWebHostBuilder + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(){{^serverUrl}};{{/serverUrl}} + {{#serverUrl}} + .UseUrls("{{serverUrl}}"); + {{/serverUrl}} + } +} diff --git a/src/main/resources/handlebars/aspnetcore/2.1/Project.csproj.mustache b/src/main/resources/handlebars/aspnetcore/2.1/Project.csproj.mustache new file mode 100644 index 0000000000..7b98af6684 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/2.1/Project.csproj.mustache @@ -0,0 +1,19 @@ + + + {{packageName}} + {{packageName}} + netcoreapp{{aspNetCoreVersion}} + true + true + {{packageName}} + {{packageName}} + + + + + + + + + + diff --git a/src/main/resources/handlebars/aspnetcore/2.1/controller.mustache b/src/main/resources/handlebars/aspnetcore/2.1/controller.mustache new file mode 100644 index 0000000000..09067f856c --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/2.1/controller.mustache @@ -0,0 +1,73 @@ +{{>partial_header}} +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using Swashbuckle.AspNetCore.SwaggerGen; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using {{packageName}}.Attributes; +{{#hasAuthMethods}}using {{packageName}}.Security;{{/hasAuthMethods}} +using Microsoft.AspNetCore.Authorization; +using {{modelPackage}}; + +namespace {{packageName}}.Controllers +{ {{#operations}} + /// + /// {{description}} + /// {{#description}} + [Description("{{description}}")]{{/description}} + [ApiController] + public class {{classname}}Controller : ControllerBase{{#interfaceController}}, I{{classname}}Controller{{/interfaceController}} + { {{#operation}} + {{#contents}} + /// + /// {{#summary}}{{summary}}{{/summary}} + /// {{#notes}} + /// {{notes}}{{/notes}}{{#parameters}} + /// {{description}}{{/parameters}}{{#responses}} + /// {{message}}{{/responses}} + [{{httpMethod}}] + [Route("{{{basePathWithoutHost}}}{{{path}}}")] + {{#authMethods}} + {{#@first}} + {{#isBasic}} + [Authorize(AuthenticationSchemes = BasicAuthenticationHandler.SchemeName)] + {{/isBasic}} + {{#isBearer}} + [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + {{/isBearer}} + {{#isApiKey}} + [Authorize(AuthenticationSchemes = ApiKeyAuthenticationHandler.SchemeName)] + {{/isApiKey}} + {{/@first}} + {{/authMethods}} + [ValidateModelState] + [SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}} + [SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}} + public virtual IActionResult {{operationId}}({{#parameters}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) + { {{#responses}} +{{#dataType}} + //TODO: Uncomment the next line to return response {{code}} or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode({{code}}, default({{&dataType}})); +{{/dataType}} +{{^dataType}} + //TODO: Uncomment the next line to return response {{code}} or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode({{code}}); +{{/dataType}}{{/responses}} +{{#returnType}} + string exampleJson = null; + {{#examples}} + exampleJson = "{{{example}}}"; + {{/examples}} + {{#isListCollection}}{{>listReturn}}{{/isListCollection}}{{^isListCollection}}{{#isMapContainer}}{{>mapReturn}}{{/isMapContainer}}{{^isMapContainer}}{{>objectReturn}}{{/isMapContainer}}{{/isListCollection}} + {{!TODO: defaultResponse, examples, auth, consumes, produces, nickname, externalDocs, imports, security}} + //TODO: Change the data returned + return new ObjectResult(example);{{/returnType}}{{^returnType}} + throw new NotImplementedException();{{/returnType}} + } + {{/contents}} + {{/operation}} + } +{{/operations}} +} diff --git a/src/main/resources/handlebars/aspnetcore/3.0/Dockerfile.mustache b/src/main/resources/handlebars/aspnetcore/3.0/Dockerfile.mustache new file mode 100644 index 0000000000..549f8be828 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.0/Dockerfile.mustache @@ -0,0 +1,19 @@ +FROM mcr.microsoft.com/dotnet/core/sdk:{{aspNetCoreVersion}} AS build-env +WORKDIR /app + +ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 + +# copy csproj and restore as distinct layers +COPY *.csproj ./ +RUN dotnet restore + +# copy everything else and build +COPY . ./ +RUN dotnet publish -c Release -o out + +# build runtime image +FROM mcr.microsoft.com/dotnet/core/aspnet:{{aspNetCoreVersion}} +WORKDIR /app +COPY --from=build-env /app/out . + +ENTRYPOINT ["dotnet", "{{packageName}}.dll"] diff --git a/src/main/resources/mustache/aspnetcore/Filters/BasePathFilter.mustache b/src/main/resources/handlebars/aspnetcore/3.0/Filters/BasePathFilter.mustache similarity index 86% rename from src/main/resources/mustache/aspnetcore/Filters/BasePathFilter.mustache rename to src/main/resources/handlebars/aspnetcore/3.0/Filters/BasePathFilter.mustache index bc76e3accc..3d2c3b67c7 100644 --- a/src/main/resources/mustache/aspnetcore/Filters/BasePathFilter.mustache +++ b/src/main/resources/handlebars/aspnetcore/3.0/Filters/BasePathFilter.mustache @@ -2,6 +2,7 @@ using System.Linq; using System.Text.RegularExpressions; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; +using Microsoft.OpenApi.Models; namespace {{packageName}}.Filters { @@ -28,11 +29,11 @@ namespace {{packageName}}.Filters /// /// Apply the filter /// - /// SwaggerDocument + /// OpenApiDocument /// FilterContext - public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { - swaggerDoc.BasePath = this.BasePath; + swaggerDoc.Servers.Add(new OpenApiServer() { Url = this.BasePath }); var pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(this.BasePath)).ToList(); diff --git a/src/main/resources/mustache/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache b/src/main/resources/handlebars/aspnetcore/3.0/Filters/GeneratePathParamsValidationFilter.mustache similarity index 82% rename from src/main/resources/mustache/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache rename to src/main/resources/handlebars/aspnetcore/3.0/Filters/GeneratePathParamsValidationFilter.mustache index d857a4a0f9..1aa62090b2 100644 --- a/src/main/resources/mustache/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache +++ b/src/main/resources/handlebars/aspnetcore/3.0/Filters/GeneratePathParamsValidationFilter.mustache @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using Microsoft.AspNetCore.Mvc.Controllers; -using Swashbuckle.AspNetCore.Swagger; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; namespace {{packageName}}.Filters @@ -16,7 +16,7 @@ namespace {{packageName}}.Filters /// /// Operation /// OperationFilterContext - public void Apply(Operation operation, OperationFilterContext context) + public void Apply(OpenApiOperation operation, OperationFilterContext context) { var pars = context.ApiDescription.ParameterDescriptions; @@ -40,9 +40,9 @@ namespace {{packageName}}.Filters if (regexAttr != null) { string regex = (string)regexAttr.ConstructorArguments[0].Value; - if (swaggerParam is NonBodyParameter) + if (swaggerParam is OpenApiParameter) { - ((NonBodyParameter)swaggerParam).Pattern = regex; + ((OpenApiParameter)swaggerParam).Schema.Pattern = regex; } } @@ -70,10 +70,10 @@ namespace {{packageName}}.Filters maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value; } - if (swaggerParam is NonBodyParameter) + if (swaggerParam is OpenApiParameter) { - ((NonBodyParameter)swaggerParam).MinLength = minLenght; - ((NonBodyParameter)swaggerParam).MaxLength = maxLength; + ((OpenApiParameter)swaggerParam).Schema.MinLength = minLenght; + ((OpenApiParameter)swaggerParam).Schema.MaxLength = maxLength; } // Range [Range] @@ -83,10 +83,10 @@ namespace {{packageName}}.Filters int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value; int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value; - if (swaggerParam is NonBodyParameter) + if (swaggerParam is OpenApiParameter) { - ((NonBodyParameter)swaggerParam).Minimum = rangeMin; - ((NonBodyParameter)swaggerParam).Maximum = rangeMax; + ((OpenApiParameter)swaggerParam).Schema.Minimum = rangeMin; + ((OpenApiParameter)swaggerParam).Schema.Maximum = rangeMax; } } } @@ -94,4 +94,3 @@ namespace {{packageName}}.Filters } } } - diff --git a/src/main/resources/handlebars/aspnetcore/3.0/Program.mustache b/src/main/resources/handlebars/aspnetcore/3.0/Program.mustache new file mode 100644 index 0000000000..49b1837ce6 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.0/Program.mustache @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore; + +namespace {{packageName}} +{ + /// + /// Program + /// + public class Program + { + /// + /// Main + /// + /// + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + /// + /// Create the web host builder. + /// + /// + /// IWebHostBuilder + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/src/main/resources/handlebars/aspnetcore/3.0/Project.csproj.mustache b/src/main/resources/handlebars/aspnetcore/3.0/Project.csproj.mustache new file mode 100644 index 0000000000..c841ad7c41 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.0/Project.csproj.mustache @@ -0,0 +1,20 @@ + + + {{packageName}} + {{packageName}} + netcoreapp{{aspNetCoreVersion}} + true + true + {{packageName}} + {{packageName}} + + + + + + + + + + + diff --git a/src/main/resources/handlebars/aspnetcore/3.0/Startup.mustache b/src/main/resources/handlebars/aspnetcore/3.0/Startup.mustache new file mode 100644 index 0000000000..988178fc7d --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.0/Startup.mustache @@ -0,0 +1,154 @@ +{{>partial_header}} +using System; +using System.IO; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using Swashbuckle.AspNetCore.Swagger; +using Swashbuckle.AspNetCore.SwaggerGen; +using {{packageName}}.Filters; +{{#hasAuthMethods}}using {{packageName}}.Security;{{/hasAuthMethods}} + +namespace {{packageName}} +{ + /// + /// Startup + /// + public class Startup + { + private readonly IWebHostEnvironment _hostingEnv; + + private IConfiguration Configuration { get; } + + /// + /// Constructor + /// + /// + /// + public Startup(IWebHostEnvironment env, IConfiguration configuration) + { + _hostingEnv = env; + Configuration = configuration; + } + + /// + /// This method gets called by the runtime. Use this method to add services to the container. + /// + /// + public void ConfigureServices(IServiceCollection services) + { + // Add framework services. + services + .AddMvc(options => + { + options.InputFormatters.RemoveType(); + options.OutputFormatters.RemoveType(); + }) + .AddNewtonsoftJson(opts => + { + opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + opts.SerializerSettings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); + }) + .AddXmlSerializerFormatters(); + + {{#authMethods}} + {{#isBasic}} + services.AddAuthentication(BasicAuthenticationHandler.SchemeName) + .AddScheme(BasicAuthenticationHandler.SchemeName, null); + + {{/isBasic}} + {{#isBearer}} + services.AddAuthentication(BearerAuthenticationHandler.SchemeName) + .AddScheme(BearerAuthenticationHandler.SchemeName, null); + + {{/isBearer}} + {{#isApiKey}} + services.AddAuthentication(ApiKeyAuthenticationHandler.SchemeName) + .AddScheme(ApiKeyAuthenticationHandler.SchemeName, null); + + {{/isApiKey}} + {{/authMethods}} + + services + .AddSwaggerGen(c => + { + c.SwaggerDoc("{{#version}}{{{version}}}{{/version}}{{^version}}v1{{/version}}", new OpenApiInfo + { + Version = "{{#version}}{{{version}}}{{/version}}{{^version}}v1{{/version}}", + Title = "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}}", + Description = "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}} (ASP.NET Core {{aspNetCoreVersion}})", + Contact = new OpenApiContact() + { + Name = "{{#infoName}}{{{infoName}}}{{/infoName}}{{^infoName}}Swagger Codegen Contributors{{/infoName}}", + Url = new Uri("{{#infoUrl}}{{{infoUrl}}}{{/infoUrl}}{{^infoUrl}}https://github.com/swagger-api/swagger-codegen{{/infoUrl}}"), + Email = "{{#infoEmail}}{{{infoEmail}}}{{/infoEmail}}" + }, + TermsOfService = new Uri("{{#termsOfService}}{{{termsOfService}}}{{/termsOfService}}") + }); + c.CustomSchemaIds(type => type.FullName); + c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml"); + {{#basePathWithoutHost}} + // Sets the basePath property in the Swagger document generated + c.DocumentFilter("{{{basePathWithoutHost}}}"); + {{/basePathWithoutHost}} + + // Include DataAnnotation attributes on Controller Action parameters as Swagger validation rules (e.g required, pattern, ..) + // Use [ValidateModelState] on Actions to actually validate it in C# as well! + c.OperationFilter(); + }); + } + + /// + /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + /// + /// + /// + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) + { + app.UseRouting(); + + //TODO: Uncomment this if you need wwwroot folder + // app.UseStaticFiles(); + + app.UseAuthorization(); + + app.UseSwagger(); + app.UseSwaggerUI(c => + { + //TODO: Either use the SwaggerGen generated Swagger contract (generated from C# classes) + c.SwaggerEndpoint("/swagger/{{#version}}{{{version}}}{{/version}}{{^version}}v1{{/version}}/swagger.json", "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}}"); + + //TODO: Or alternatively use the original Swagger contract that's included in the static files + // c.SwaggerEndpoint("/swagger-original.json", "{{#appName}}{{{appName}}}{{/appName}}{{^appName}}{{packageName}}{{/appName}} Original"); + }); + + //TODO: Use Https Redirection + // app.UseHttpsRedirection(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + //TODO: Enable production exception handling (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling) + app.UseExceptionHandler("/Error"); + + app.UseHsts(); + } + } + } +} diff --git a/src/main/resources/handlebars/aspnetcore/3.0/controller.mustache b/src/main/resources/handlebars/aspnetcore/3.0/controller.mustache new file mode 100644 index 0000000000..09067f856c --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.0/controller.mustache @@ -0,0 +1,73 @@ +{{>partial_header}} +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using Swashbuckle.AspNetCore.SwaggerGen; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using {{packageName}}.Attributes; +{{#hasAuthMethods}}using {{packageName}}.Security;{{/hasAuthMethods}} +using Microsoft.AspNetCore.Authorization; +using {{modelPackage}}; + +namespace {{packageName}}.Controllers +{ {{#operations}} + /// + /// {{description}} + /// {{#description}} + [Description("{{description}}")]{{/description}} + [ApiController] + public class {{classname}}Controller : ControllerBase{{#interfaceController}}, I{{classname}}Controller{{/interfaceController}} + { {{#operation}} + {{#contents}} + /// + /// {{#summary}}{{summary}}{{/summary}} + /// {{#notes}} + /// {{notes}}{{/notes}}{{#parameters}} + /// {{description}}{{/parameters}}{{#responses}} + /// {{message}}{{/responses}} + [{{httpMethod}}] + [Route("{{{basePathWithoutHost}}}{{{path}}}")] + {{#authMethods}} + {{#@first}} + {{#isBasic}} + [Authorize(AuthenticationSchemes = BasicAuthenticationHandler.SchemeName)] + {{/isBasic}} + {{#isBearer}} + [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + {{/isBearer}} + {{#isApiKey}} + [Authorize(AuthenticationSchemes = ApiKeyAuthenticationHandler.SchemeName)] + {{/isApiKey}} + {{/@first}} + {{/authMethods}} + [ValidateModelState] + [SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}} + [SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}} + public virtual IActionResult {{operationId}}({{#parameters}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) + { {{#responses}} +{{#dataType}} + //TODO: Uncomment the next line to return response {{code}} or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode({{code}}, default({{&dataType}})); +{{/dataType}} +{{^dataType}} + //TODO: Uncomment the next line to return response {{code}} or use other options such as return this.NotFound(), return this.BadRequest(..), ... + // return StatusCode({{code}}); +{{/dataType}}{{/responses}} +{{#returnType}} + string exampleJson = null; + {{#examples}} + exampleJson = "{{{example}}}"; + {{/examples}} + {{#isListCollection}}{{>listReturn}}{{/isListCollection}}{{^isListCollection}}{{#isMapContainer}}{{>mapReturn}}{{/isMapContainer}}{{^isMapContainer}}{{>objectReturn}}{{/isMapContainer}}{{/isListCollection}} + {{!TODO: defaultResponse, examples, auth, consumes, produces, nickname, externalDocs, imports, security}} + //TODO: Change the data returned + return new ObjectResult(example);{{/returnType}}{{^returnType}} + throw new NotImplementedException();{{/returnType}} + } + {{/contents}} + {{/operation}} + } +{{/operations}} +} diff --git a/src/main/resources/handlebars/aspnetcore/3.1/Project.csproj.mustache b/src/main/resources/handlebars/aspnetcore/3.1/Project.csproj.mustache new file mode 100644 index 0000000000..dd9e0686df --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.1/Project.csproj.mustache @@ -0,0 +1,21 @@ + + + {{packageName}} + {{packageName}} + {{targetFramework}} + true + true + {{packageName}} + {{packageName}} + + + ` + + + + + + + + + diff --git a/src/main/resources/handlebars/aspnetcore/3.1/Properties/launchSettings.json b/src/main/resources/handlebars/aspnetcore/3.1/Properties/launchSettings.json new file mode 100644 index 0000000000..5bb6f82994 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/3.1/Properties/launchSettings.json @@ -0,0 +1,36 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:50352/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger/", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "web": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "publishAllPorts": true, + "useSSL": true + } + } +} \ No newline at end of file diff --git a/src/main/resources/handlebars/aspnetcore/Dockerfile.mustache b/src/main/resources/handlebars/aspnetcore/Dockerfile.mustache index e9d80c5283..409a70c691 100644 --- a/src/main/resources/handlebars/aspnetcore/Dockerfile.mustache +++ b/src/main/resources/handlebars/aspnetcore/Dockerfile.mustache @@ -1,4 +1,4 @@ -FROM microsoft/aspnetcore-build:2.0 AS build-env +FROM microsoft/aspnetcore-build:{{aspNetCoreVersion}} AS build-env WORKDIR /app ENV DOTNET_CLI_TELEMETRY_OPTOUT 1 @@ -12,7 +12,7 @@ COPY . ./ RUN dotnet publish -c Release -o out # build runtime image -FROM microsoft/aspnetcore:2.0 +FROM microsoft/aspnetcore:{{aspNetCoreVersion}} WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", "{{packageName}}.dll"] diff --git a/src/main/resources/handlebars/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache b/src/main/resources/handlebars/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache index d857a4a0f9..3d1b4d9466 100644 --- a/src/main/resources/handlebars/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache +++ b/src/main/resources/handlebars/aspnetcore/Filters/GeneratePathParamsValidationFilter.mustache @@ -24,69 +24,72 @@ namespace {{packageName}}.Filters { var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name); - var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes; - - if (attributes != null && attributes.Count() > 0 && swaggerParam != null) + if (par.ParameterDescriptor != null && par.ParameterDescriptor is ControllerParameterDescriptor && ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo != null) { - // Required - [Required] - var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute)); - if (requiredAttr != null) - { - swaggerParam.Required = true; - } + var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes; - // Regex Pattern [RegularExpression] - var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute)); - if (regexAttr != null) + if (attributes != null && attributes.Count() > 0 && swaggerParam != null) { - string regex = (string)regexAttr.ConstructorArguments[0].Value; - if (swaggerParam is NonBodyParameter) + // Required - [Required] + var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute)); + if (requiredAttr != null) { - ((NonBodyParameter)swaggerParam).Pattern = regex; + swaggerParam.Required = true; } - } - // String Length [StringLength] - int? minLenght = null, maxLength = null; - var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute)); - if (stringLengthAttr != null) - { - if (stringLengthAttr.NamedArguments.Count == 1) + // Regex Pattern [RegularExpression] + var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute)); + if (regexAttr != null) { - minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value; + string regex = (string)regexAttr.ConstructorArguments[0].Value; + if (swaggerParam is NonBodyParameter) + { + ((NonBodyParameter)swaggerParam).Pattern = regex; + } } - maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value; - } - var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute)); - if (minLengthAttr != null) - { - minLenght = (int)minLengthAttr.ConstructorArguments[0].Value; - } - - var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute)); - if (maxLengthAttr != null) - { - maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value; - } + // String Length [StringLength] + int? minLenght = null, maxLength = null; + var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute)); + if (stringLengthAttr != null) + { + if (stringLengthAttr.NamedArguments.Count == 1) + { + minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value; + } + maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value; + } - if (swaggerParam is NonBodyParameter) - { - ((NonBodyParameter)swaggerParam).MinLength = minLenght; - ((NonBodyParameter)swaggerParam).MaxLength = maxLength; - } + var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute)); + if (minLengthAttr != null) + { + minLenght = (int)minLengthAttr.ConstructorArguments[0].Value; + } - // Range [Range] - var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute)); - if (rangeAttr != null) - { - int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value; - int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value; + var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute)); + if (maxLengthAttr != null) + { + maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value; + } if (swaggerParam is NonBodyParameter) { - ((NonBodyParameter)swaggerParam).Minimum = rangeMin; - ((NonBodyParameter)swaggerParam).Maximum = rangeMax; + ((NonBodyParameter)swaggerParam).MinLength = minLenght; + ((NonBodyParameter)swaggerParam).MaxLength = maxLength; + } + + // Range [Range] + var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute)); + if (rangeAttr != null) + { + int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value; + int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value; + + if (swaggerParam is NonBodyParameter) + { + ((NonBodyParameter)swaggerParam).Minimum = rangeMin; + ((NonBodyParameter)swaggerParam).Maximum = rangeMax; + } } } } diff --git a/src/main/resources/handlebars/aspnetcore/NuGet.Config b/src/main/resources/handlebars/aspnetcore/NuGet.Config index 01f3d1f203..5db080cb7d 100644 --- a/src/main/resources/handlebars/aspnetcore/NuGet.Config +++ b/src/main/resources/handlebars/aspnetcore/NuGet.Config @@ -3,7 +3,6 @@ - diff --git a/src/main/resources/handlebars/aspnetcore/Program.mustache b/src/main/resources/handlebars/aspnetcore/Program.mustache index 52fdd13d05..9fd700c038 100644 --- a/src/main/resources/handlebars/aspnetcore/Program.mustache +++ b/src/main/resources/handlebars/aspnetcore/Program.mustache @@ -31,6 +31,9 @@ namespace {{packageName}} public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() + {{#serverUrl}} + .UseUrls("{{serverUrl}}") + {{/serverUrl}} .Build(); } } diff --git a/src/main/resources/handlebars/aspnetcore/Security/ApiKeyAuthenticationHandler.mustache b/src/main/resources/handlebars/aspnetcore/Security/ApiKeyAuthenticationHandler.mustache new file mode 100644 index 0000000000..667ba71958 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/Security/ApiKeyAuthenticationHandler.mustache @@ -0,0 +1,50 @@ +using System; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace {{packageName}}.Security +{ + /// + /// class to handle api_key security. + /// + public class ApiKeyAuthenticationHandler : AuthenticationHandler + { + /// + /// scheme name for authentication handler. + /// + public const string SchemeName = "ApiKey"; + + public ApiKeyAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { + } + + /// + /// verify that require api key header exist and handle authorization. + /// + protected override async Task HandleAuthenticateAsync() + { + if (!Request.Headers.ContainsKey("api_key")) + { + return AuthenticateResult.Fail("Missing Authorization Header"); + } + + // do magic here! + + var claims = new[] { + new Claim(ClaimTypes.NameIdentifier, "changeme"), + new Claim(ClaimTypes.Name, "changeme"), + }; + var identity = new ClaimsIdentity(claims, Scheme.Name); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + } +} diff --git a/src/main/resources/handlebars/aspnetcore/Security/BasicAuthenticationHandler.mustache b/src/main/resources/handlebars/aspnetcore/Security/BasicAuthenticationHandler.mustache new file mode 100644 index 0000000000..cf9faaf024 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/Security/BasicAuthenticationHandler.mustache @@ -0,0 +1,60 @@ +using System; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace {{packageName}}.Security +{ + /// + /// class to handle basic authentication. + /// + public class BasicAuthenticationHandler : AuthenticationHandler + { + /// + /// scheme name for authentication handler. + /// + public const string SchemeName = "Basic"; + + public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { + } + + /// + /// verify that require authorization header exists and handle decode data. + /// + protected override async Task HandleAuthenticateAsync() + { + if (!Request.Headers.ContainsKey("Authorization")) + { + return AuthenticateResult.Fail("Missing Authorization Header"); + } + try + { + var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); + var credentialBytes = Convert.FromBase64String(authHeader.Parameter); + var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':'); + var username = credentials[0]; + var password = credentials[1]; + } + catch + { + return AuthenticateResult.Fail("Invalid Authorization Header"); + } + + var claims = new[] { + new Claim(ClaimTypes.NameIdentifier, "changeme"), + new Claim(ClaimTypes.Name, "changeme"), + }; + var identity = new ClaimsIdentity(claims, Scheme.Name); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + } +} diff --git a/src/main/resources/handlebars/aspnetcore/Security/BearerAuthenticationHandler.mustache b/src/main/resources/handlebars/aspnetcore/Security/BearerAuthenticationHandler.mustache new file mode 100644 index 0000000000..903ef2852c --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/Security/BearerAuthenticationHandler.mustache @@ -0,0 +1,58 @@ +using System; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace {{packageName}}.Security +{ + /// + /// class to handle bearer authentication. + /// + public class BearerAuthenticationHandler : AuthenticationHandler + { + /// + /// scheme name for authentication handler. + /// + public const string SchemeName = "Bearer"; + + public BearerAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + { + } + + /// + /// verify that require authorization header exists. + /// + protected override async Task HandleAuthenticateAsync() + { + if (!Request.Headers.ContainsKey("Authorization")) + { + return AuthenticateResult.Fail("Missing Authorization Header"); + } + try + { + var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); + + /// TODO handle token. + } + catch + { + return AuthenticateResult.Fail("Invalid Authorization Header"); + } + + var claims = new[] { + new Claim(ClaimTypes.NameIdentifier, "changeme"), + new Claim(ClaimTypes.Name, "changeme"), + }; + var identity = new ClaimsIdentity(claims, Scheme.Name); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + } +} diff --git a/src/main/resources/handlebars/aspnetcore/Solution.mustache b/src/main/resources/handlebars/aspnetcore/Solution.mustache index 0384ccec6b..9cbf502124 100644 --- a/src/main/resources/handlebars/aspnetcore/Solution.mustache +++ b/src/main/resources/handlebars/aspnetcore/Solution.mustache @@ -1,21 +1,22 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26114.2 +VisualStudioVersion = 15.0.27428.2043 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "{{packageName}}", "src{{backslash}}{{packageName}}{{backslash}}{{packageName}}.csproj", "{{packageGuid}}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "{{packageName}}", "{{sourceFolder}}{{backslash}}{{packageName}}{{backslash}}{{packageName}}.csproj", "{{packageGuid}}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {{packageGuid}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {{packageGuid}}.Debug|Any CPU.Build.0 = Debug|Any CPU - {{packageGuid}}.Release|Any CPU.ActiveCfg = Release|Any CPU - {{packageGuid}}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {{packageGuid}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {{packageGuid}}.Debug|Any CPU.Build.0 = Debug|Any CPU + {{packageGuid}}.Release|Any CPU.ActiveCfg = Release|Any CPU + {{packageGuid}}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection EndGlobal diff --git a/src/main/resources/handlebars/aspnetcore/Startup.mustache b/src/main/resources/handlebars/aspnetcore/Startup.mustache index 5b95562dcd..1a85143081 100644 --- a/src/main/resources/handlebars/aspnetcore/Startup.mustache +++ b/src/main/resources/handlebars/aspnetcore/Startup.mustache @@ -11,6 +11,9 @@ using Newtonsoft.Json.Serialization; using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.SwaggerGen; using {{packageName}}.Filters; +{{#hasAuthMethods}}using {{packageName}}.Security;{{/hasAuthMethods}} + +using Microsoft.AspNetCore.Authentication; namespace {{packageName}} { @@ -49,7 +52,26 @@ namespace {{packageName}} opts.SerializerSettings.Converters.Add(new StringEnumConverter { CamelCaseText = true }); - }); + }) + .AddXmlSerializerFormatters(); + + {{#authMethods}} + {{#isBasic}} + services.AddAuthentication(BasicAuthenticationHandler.SchemeName) + .AddScheme(BasicAuthenticationHandler.SchemeName, null); + + {{/isBasic}} + {{#isBearer}} + services.AddAuthentication(BearerAuthenticationHandler.SchemeName) + .AddScheme(BearerAuthenticationHandler.SchemeName, null); + + {{/isBearer}} + {{#isApiKey}} + services.AddAuthentication(ApiKeyAuthenticationHandler.SchemeName) + .AddScheme(ApiKeyAuthenticationHandler.SchemeName, null); + + {{/isApiKey}} + {{/authMethods}} services .AddSwaggerGen(c => diff --git a/src/main/resources/handlebars/aspnetcore/controller.mustache b/src/main/resources/handlebars/aspnetcore/controller.mustache index 6455e99251..c476ef0ca8 100644 --- a/src/main/resources/handlebars/aspnetcore/controller.mustache +++ b/src/main/resources/handlebars/aspnetcore/controller.mustache @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.WebUtilities; @@ -13,6 +14,7 @@ using Swashbuckle.AspNetCore.SwaggerGen; using Newtonsoft.Json; using System.ComponentModel.DataAnnotations; using {{packageName}}.Attributes; +{{#hasAuthMethods}}using {{packageName}}.Security;{{/hasAuthMethods}} using {{packageName}}.Models; namespace {{packageName}}.Controllers @@ -21,7 +23,7 @@ namespace {{packageName}}.Controllers /// {{description}} /// {{#description}} [Description("{{description}}")]{{/description}} - public class {{classname}}Controller : Controller + public class {{classname}}Controller : Controller{{#interfaceController}}, I{{classname}}Controller{{/interfaceController}} { {{#operation}} {{#contents}} /// @@ -32,6 +34,19 @@ namespace {{packageName}}.Controllers /// {{message}}{{/responses}} [{{httpMethod}}] [Route("{{{basePathWithoutHost}}}{{{path}}}")] + {{#authMethods}} + {{#@first}} + {{#isBasic}} + [Authorize(AuthenticationSchemes = BasicAuthenticationHandler.SchemeName)] + {{/isBasic}} + {{#isBearer}} + [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + {{/isBearer}} + {{#isApiKey}} + [Authorize(AuthenticationSchemes = ApiKeyAuthenticationHandler.SchemeName)] + {{/isApiKey}} + {{/@first}} + {{/authMethods}} [ValidateModelState] [SwaggerOperation("{{operationId}}")]{{#responses}}{{#dataType}} [SwaggerResponse(statusCode: {{code}}, type: typeof({{&dataType}}), description: "{{message}}")]{{/dataType}}{{^dataType}}{{/dataType}}{{/responses}} diff --git a/src/main/resources/handlebars/aspnetcore/enumClass.mustache b/src/main/resources/handlebars/aspnetcore/enumClass.mustache index 4800f1cbfb..70aaf39070 100644 --- a/src/main/resources/handlebars/aspnetcore/enumClass.mustache +++ b/src/main/resources/handlebars/aspnetcore/enumClass.mustache @@ -10,9 +10,9 @@ { {{#allowableValues}}{{#enumVars}} /// - /// Enum {{name}} for {{{value}}} + /// Enum {{name}} for {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}} /// - {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}} - {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{@index}}{{/isString}}{{^@last}}, + {{#isString}}[EnumMember(Value = {{#value}}"{{{value}}}"{{/value}}{{^value}}null{{/value}})]{{/isString}} + {{name}}{{^isString}} = {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}{{/isString}}{{#isString}} = {{@index}}{{/isString}}{{^@last}}, {{/@last}}{{/enumVars}}{{/allowableValues}} } diff --git a/src/main/resources/handlebars/aspnetcore/icontroller.mustache b/src/main/resources/handlebars/aspnetcore/icontroller.mustache new file mode 100644 index 0000000000..2314f70954 --- /dev/null +++ b/src/main/resources/handlebars/aspnetcore/icontroller.mustache @@ -0,0 +1,29 @@ +{{>partial_header}} +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using {{packageName}}.Models; + +namespace {{packageName}}.Controllers +{ {{#operations}} + /// + /// {{description}} + /// {{#description}} + [Description("{{description}}")]{{/description}} + public interface I{{classname}}Controller + { {{#operation}} + {{#contents}} + /// + /// {{#summary}}{{summary}}{{/summary}} + /// + {{#notes}}/// {{notes}}{{/notes}}{{#parameters}} + /// {{description}}{{/parameters}}{{#responses}} + /// {{message}}{{/responses}} + IActionResult {{operationId}}({{#parameters}}{{>pathParam}}{{>queryParam}}{{>bodyParam}}{{>formParam}}{{>headerParam}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); + {{/contents}} + {{/operation}} + } +{{/operations}} +} diff --git a/src/main/resources/handlebars/aspnetcore/model.mustache b/src/main/resources/handlebars/aspnetcore/model.mustache index 00521d0a5f..3769617c7b 100644 --- a/src/main/resources/handlebars/aspnetcore/model.mustache +++ b/src/main/resources/handlebars/aspnetcore/model.mustache @@ -13,13 +13,15 @@ using Newtonsoft.Json; {{#models}} {{#model}} namespace {{packageName}}.Models -{ {{#isEnum}}{{>enumClass}}{{/isEnum}}{{^isEnum}} +{ + {{^isComposedModel}} + {{#isEnum}}{{>enumClass}}{{/isEnum}}{{^isEnum}} /// /// {{description}} /// [DataContract] - public partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}}IEquatable<{{classname}}> - { {{#vars}}{{#isEnum}}{{>enumClass}}{{/isEnum}}{{#items.isEnum}}{{#items}}{{>enumClass}}{{/items}}{{/items.isEnum}} + public partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}}IEquatable<{{classname}}>{{#interfaceModels}}{{#@first}}, {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}} + { {{#vars}}{{#isEnum}}{{^isContainer}}{{>enumClass}}{{/isContainer}}{{/isEnum}}{{#items.isEnum}}{{#items}}{{^isContainer}}{{>enumClass}}{{/isContainer}}{{/items}}{{/items.isEnum}} /// /// {{^description}}Gets or Sets {{{name}}}{{/description}}{{#description}}{{description}}{{/description}} /// @@ -28,7 +30,12 @@ namespace {{packageName}}.Models {{/description}} {{#required}} [Required] - {{/required}} + {{/required}}{{#pattern}} + [RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}} + [StringLength({{maxLength}}, MinimumLength={{minLength}})]{{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} + [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} + [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}} + [Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}} [DataMember(Name="{{baseName}}")] {{#isEnum}} public {{{datatypeWithEnum}}}{{#isEnum}}{{^isContainer}}?{{/isContainer}}{{/isEnum}} {{name}} { get; set; } @@ -134,6 +141,20 @@ namespace {{packageName}}.Models #endregion Operators } {{/isEnum}} +{{/isComposedModel}} +{{#isComposedModel}} + /// + /// {{description}} + /// + public interface {{{classname}}} + { + {{#vendorExtensions}} + {{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); + {{/x-discriminator-type-getter}} + {{/vendorExtensions}} + } +{{/isComposedModel}} {{/model}} {{/models}} } diff --git a/src/main/resources/handlebars/codegen/pom.mustache b/src/main/resources/handlebars/codegen/pom.mustache index d45b5bc5fd..81f23d1d37 100644 --- a/src/main/resources/handlebars/codegen/pom.mustache +++ b/src/main/resources/handlebars/codegen/pom.mustache @@ -123,7 +123,7 @@ {{swaggerCodegenVersion}} {{swaggerCodegenGeneratorsVersion}} 1.0.0 - 4.8.1 + 4.13.1 3.0.0 diff --git a/src/main/resources/handlebars/csharp-dotnet2/README.mustache b/src/main/resources/handlebars/csharp-dotnet2/README.mustache index e6eda4cb99..1849d988f0 100644 --- a/src/main/resources/handlebars/csharp-dotnet2/README.mustache +++ b/src/main/resources/handlebars/csharp-dotnet2/README.mustache @@ -141,8 +141,8 @@ Authentication schemes defined for the API: - **Flow**: {{flow}} - **Authorization URL**: {{authorizationUrl}} - **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} +{{#each scopes}} - {{@key}}: {{this}} +{{/each}} {{/isOAuth}} {{/authMethods}} diff --git a/src/main/resources/handlebars/csharp-dotnet2/api.mustache b/src/main/resources/handlebars/csharp-dotnet2/api.mustache index ff0445d6d9..41b3b035bd 100644 --- a/src/main/resources/handlebars/csharp-dotnet2/api.mustache +++ b/src/main/resources/handlebars/csharp-dotnet2/api.mustache @@ -107,11 +107,15 @@ namespace {{apiPackage}} {{/queryParams}} {{#headerParams}} if ({{paramName}} != null) headerParams.Add("{{baseName}}", ApiClient.ParameterToString({{paramName}})); // header parameter {{/headerParams}} - {{#formParams}}if ({{paramName}} != null) {{#isFile}}fileParams.Add("{{baseName}}", ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isFile}}{{^isFile}}formParams.Add("{{baseName}}", ApiClient.ParameterToString({{paramName}})); // form parameter{{/isFile}} + {{#isForm}} + {{#formParams}}if ({{paramName}} != null) {{#isBinary}}fileParams.Add("{{baseName}}", ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isBinary}}{{^isBinary}}formParams.Add("{{baseName}}", ApiClient.ParameterToString({{paramName}})); // form parameter{{/isBinary}} {{/formParams}} + {{/isForm}} + {{^isForm}} {{#bodyParam}}postBody = ApiClient.Serialize({{paramName}}); // http body (model) parameter {{/bodyParam}} - + {{/isForm}} + // authentication setting, if any String[] authSettings = new String[] { {{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}} }; diff --git a/src/main/resources/handlebars/csharp-dotnet2/api_doc.mustache b/src/main/resources/handlebars/csharp-dotnet2/api_doc.mustache index 3e51f10b5c..c8625885ba 100644 --- a/src/main/resources/handlebars/csharp-dotnet2/api_doc.mustache +++ b/src/main/resources/handlebars/csharp-dotnet2/api_doc.mustache @@ -77,7 +77,7 @@ namespace Example {{^parameters}}This endpoint does not need any parameter.{{/parameters}}{{#parameters}}{{#@last}} Name | Type | Description | Notes ------------- | ------------- | ------------- | -------------{{/@last}}{{/parameters}} -{{#parameters}} **{{paramName}}** | {{#isFile}}**{{{dataType}}}**{{/isFile}}{{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{{dataType}}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} +{{#parameters}} **{{paramName}}** | {{#isBinary}}**{{{dataType}}}**{{/isBinary}}{{#isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isBinary}}[**{{{dataType}}}**]({{baseType}}.md){{/isBinary}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} {{/parameters}} ### Return type diff --git a/src/main/resources/handlebars/csharp-dotnet2/compile-mono.sh.mustache b/src/main/resources/handlebars/csharp-dotnet2/compile-mono.sh.mustache index 2287344892..cbf5af813e 100644 --- a/src/main/resources/handlebars/csharp-dotnet2/compile-mono.sh.mustache +++ b/src/main/resources/handlebars/csharp-dotnet2/compile-mono.sh.mustache @@ -1,4 +1,4 @@ -wget -nc https://dist.nuget.org/win-x86-commandline/latest/nuget.exe; +curl --location --request GET 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' --output './nuget.exe' mozroots --import --sync mono nuget.exe install vendor/packages.config -o vendor; mkdir -p bin; diff --git a/src/main/resources/handlebars/csharp-dotnet2/csproj.mustache b/src/main/resources/handlebars/csharp-dotnet2/csproj.mustache new file mode 100644 index 0000000000..7894c816a8 --- /dev/null +++ b/src/main/resources/handlebars/csharp-dotnet2/csproj.mustache @@ -0,0 +1,23 @@ + + + + netstandard2.0 + {{clientPackage}} + + + + + {{packageName}} + {{packageVersion}} + {{packageAuthors}} + {{packageCompany}} + {{packageTitle}} + {{packageDescription}} + {{packageCopyright}} + + + + + + + \ No newline at end of file diff --git a/src/main/resources/handlebars/csharp/ApiClient.mustache b/src/main/resources/handlebars/csharp/ApiClient.mustache index 6e2a4aa258..6bd4a9d7f3 100644 --- a/src/main/resources/handlebars/csharp/ApiClient.mustache +++ b/src/main/resources/handlebars/csharp/ApiClient.mustache @@ -275,6 +275,11 @@ namespace {{packageName}}.Client return FileParameter.Create(name, ReadAsBytes(stream), "no_file_name_provided"); } + public FileParameter ParameterToFile(string name, byte[] stream) + { + return FileParameter.Create(name, stream, "no_file_name_provided"); + } + /// /// If parameter is DateTime, output in a formatted string (default ISO 8601), customizable with Configuration.DateTime. /// If parameter is a list, join the list with ",". diff --git a/src/main/resources/handlebars/csharp/Configuration.mustache b/src/main/resources/handlebars/csharp/Configuration.mustache index 9e4cf95b55..99ba69f219 100644 --- a/src/main/resources/handlebars/csharp/Configuration.mustache +++ b/src/main/resources/handlebars/csharp/Configuration.mustache @@ -113,7 +113,6 @@ namespace {{packageName}}.Client ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary(); ApiKeyPrefix = new {{^net35}}Concurrent{{/net35}}Dictionary(); - // Setting Timeout has side effects (forces ApiClient creation). Timeout = 100000; } @@ -236,15 +235,49 @@ namespace {{packageName}}.Client /// public virtual IDictionary DefaultHeader { get; set; } + private int _timeout = 100000; /// /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds. /// public virtual int Timeout { - {{#netStandard}}get { return (int)ApiClient.RestClient.Timeout.GetValueOrDefault(TimeSpan.FromSeconds(0)).TotalMilliseconds; } - set { ApiClient.RestClient.Timeout = TimeSpan.FromMilliseconds(value); }{{/netStandard}}{{^netStandard}} - get { return ApiClient.RestClient.Timeout; } - set { ApiClient.RestClient.Timeout = value; }{{/netStandard}} + {{#netStandard}}get + { + if (_apiClient == null) + { + return _timeout; + } else + { + return (int)ApiClient.RestClient.Timeout.GetValueOrDefault(TimeSpan.FromSeconds(0)).TotalMilliseconds; + } + } + set + { + _timeout = value; + if (_apiClient != null) + { + ApiClient.RestClient.Timeout = TimeSpan.FromMilliseconds(_timeout); + } + }{{/netStandard}}{{^netStandard}} + get + { + if (_apiClient == null) + { + return _timeout; + } + else + { + return ApiClient.RestClient.Timeout; + } + } + set + { + _timeout = value; + if (_apiClient != null) + { + ApiClient.RestClient.Timeout = _timeout; + } + }{{/netStandard}} } /// diff --git a/src/main/resources/handlebars/csharp/README.mustache b/src/main/resources/handlebars/csharp/README.mustache index 8cc4619a86..e7745565d8 100644 --- a/src/main/resources/handlebars/csharp/README.mustache +++ b/src/main/resources/handlebars/csharp/README.mustache @@ -199,8 +199,8 @@ Authentication schemes defined for the API: - **Flow**: {{flow}} - **Authorization URL**: {{authorizationUrl}} - **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} +{{#each scopes}} - {{@key}}: {{this}} +{{/each}} {{/isOAuth}} {{/authMethods}} diff --git a/src/main/resources/handlebars/csharp/api.mustache b/src/main/resources/handlebars/csharp/api.mustache index 970267cba0..123180a529 100644 --- a/src/main/resources/handlebars/csharp/api.mustache +++ b/src/main/resources/handlebars/csharp/api.mustache @@ -254,7 +254,7 @@ namespace {{packageName}}.{{apiPackage}} {{/headerParams}} {{#isForm}} {{#formParams}} - if ({{paramName}} != null) {{#isFile}}localVarFileParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isFile}}{{^isFile}}localVarFormParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToString({{paramName}})); // form parameter{{/isFile}} + if ({{paramName}} != null) {{#isBinary}}localVarFileParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isBinary}}{{^isBinary}}localVarFormParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToString({{paramName}})); // form parameter{{/isBinary}} {{/formParams}} {{/isForm}} {{^isForm}} @@ -292,6 +292,13 @@ namespace {{packageName}}.{{apiPackage}} localVarHeaderParams["Authorization"] = "Basic " + ApiClient.Base64Encode(this.Configuration.Username + ":" + this.Configuration.Password); } {{/isBasic}} + {{#isBearer}} + // bearer required + if (!String.IsNullOrEmpty(this.Configuration.AccessToken)) + { + localVarHeaderParams["Authorization"] = "Bearer " + this.Configuration.AccessToken; + } + {{/isBearer}} {{#isOAuth}} // oauth required if (!String.IsNullOrEmpty(this.Configuration.AccessToken)) @@ -393,7 +400,7 @@ namespace {{packageName}}.{{apiPackage}} {{/headerParams}} {{#isForm}} {{#formParams}} - if ({{paramName}} != null) {{#isFile}}localVarFileParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isFile}}{{^isFile}}localVarFormParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToString({{paramName}})); // form parameter{{/isFile}} + if ({{paramName}} != null) {{#isBinary}}localVarFileParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToFile("{{baseName}}", {{paramName}}));{{/isBinary}}{{^isBinary}}localVarFormParams.Add("{{baseName}}", this.Configuration.ApiClient.ParameterToString({{paramName}})); // form parameter{{/isBinary}} {{/formParams}} {{/isForm}} {{^isForm}} @@ -431,6 +438,13 @@ namespace {{packageName}}.{{apiPackage}} localVarHeaderParams["Authorization"] = "Basic " + ApiClient.Base64Encode(this.Configuration.Username + ":" + this.Configuration.Password); } {{/isBasic}} + {{#isBearer}} + // bearer required + if (!String.IsNullOrEmpty(this.Configuration.AccessToken)) + { + localVarHeaderParams["Authorization"] = "Bearer " + this.Configuration.AccessToken; + } + {{/isBearer}} {{#isOAuth}} // oauth required if (!String.IsNullOrEmpty(this.Configuration.AccessToken)) diff --git a/src/main/resources/handlebars/csharp/api_doc.mustache b/src/main/resources/handlebars/csharp/api_doc.mustache index 4fe2a2c4b9..4ed1ca0fdb 100644 --- a/src/main/resources/handlebars/csharp/api_doc.mustache +++ b/src/main/resources/handlebars/csharp/api_doc.mustache @@ -85,7 +85,7 @@ namespace Example {{^parameters}}This endpoint does not need any parameter.{{/parameters}}{{#parameters}}{{#@last}} Name | Type | Description | Notes ------------- | ------------- | ------------- | -------------{{/@last}}{{/parameters}} -{{#parameters}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{#isContainer}}{{baseType}}{{/isContainer}}{{^isContainer}}{{dataType}}{{/isContainer}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} +{{#parameters}} **{{paramName}}** | {{#isBinary}}**{{dataType}}**{{/isBinary}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isBinary}}[**{{dataType}}**]({{#isContainer}}{{baseType}}{{/isContainer}}{{^isContainer}}{{dataType}}{{/isContainer}}.md){{/isBinary}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} {{/parameters}} ### Return type diff --git a/src/main/resources/handlebars/csharp/enumClass.mustache b/src/main/resources/handlebars/csharp/enumClass.mustache index e4f01f5cd7..6376df7590 100644 --- a/src/main/resources/handlebars/csharp/enumClass.mustache +++ b/src/main/resources/handlebars/csharp/enumClass.mustache @@ -9,9 +9,9 @@ { {{#allowableValues}}{{#enumVars}} /// - /// Enum {{name}} for {{{value}}} + /// Enum {{name}} for {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}} /// - [EnumMember(Value = {{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}})] - {{name}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{@index}}{{/isInteger}}{{^@last}}, + [EnumMember(Value = {{#value}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isFloat}}"{{/isFloat}}{{#isDouble}}"{{/isDouble}}{{{value}}}{{#isLong}}"{{/isLong}}{{#isInteger}}"{{/isInteger}}{{#isDouble}}"{{/isDouble}}{{#isFloat}}"{{/isFloat}}{{/value}}{{^value}}null{{/value}})] + {{name}} {{#value}}{{#isLong}} = {{{value}}}{{/isLong}}{{#isInteger}} = {{{value}}}{{/isInteger}}{{^isInteger}} = {{@index}}{{/isInteger}}{{/value}}{{^value}}null{{/value}}{{^@last}}, {{/@last}}{{/enumVars}}{{/allowableValues}} } diff --git a/src/main/resources/handlebars/csharp/interface.mustache b/src/main/resources/handlebars/csharp/interface.mustache new file mode 100644 index 0000000000..9158acb850 --- /dev/null +++ b/src/main/resources/handlebars/csharp/interface.mustache @@ -0,0 +1,12 @@ +/// +/// {{#description}}{{.}}{{/description}}{{^description}}{{classname}}{{/description}} +/// +public interface {{{classname}}} +{ + +{{#vendorExtensions}} +{{#x-discriminator-type-getter}} + {{x-discriminator-type}} {{x-discriminator-type-getter}}(); +{{/x-discriminator-type-getter}} +{{/vendorExtensions}} +} diff --git a/src/main/resources/handlebars/csharp/model.mustache b/src/main/resources/handlebars/csharp/model.mustache index 9f49989303..7d562abbe7 100644 --- a/src/main/resources/handlebars/csharp/model.mustache +++ b/src/main/resources/handlebars/csharp/model.mustache @@ -1,4 +1,5 @@ {{>partial_header}} +{{^x-is-composed-model}} using System; using System.Linq; using System.IO; @@ -27,12 +28,17 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; {{/netStandard}} using SwaggerDateConverter = {{packageName}}.Client.SwaggerDateConverter; - +{{/x-is-composed-model}} {{#models}} {{#model}} namespace {{packageName}}.{{modelPackage}} { +{{#isComposedModel}} + {{>interface}} +{{/isComposedModel}} +{{^isComposedModel}} {{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{>modelGeneric}}{{/isEnum}} +{{/isComposedModel}} {{/model}} {{/models}} } diff --git a/src/main/resources/handlebars/csharp/modelEnum.mustache b/src/main/resources/handlebars/csharp/modelEnum.mustache index 2993849ecf..1dfb03cd35 100644 --- a/src/main/resources/handlebars/csharp/modelEnum.mustache +++ b/src/main/resources/handlebars/csharp/modelEnum.mustache @@ -11,9 +11,9 @@ { {{#allowableValues}}{{#enumVars}} /// - /// Enum {{name}} for value: {{{value}}} + /// Enum {{name}} for value: {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}} /// - {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}} - {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{@index}}{{/isString}}{{^@last}}, + {{#isString}}[EnumMember(Value = {{#value}}"{{{value}}}"{{/value}}{{^value}}null{{/value}})]{{/isString}} + {{name}}{{^isString}} = {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}{{/isString}}{{#isString}} = {{@index_1}}{{/isString}}{{^@last}}, {{/@last}}{{/enumVars}}{{/allowableValues}} }{{! NOTE: This model's enumVars is modified to look like CodegenProperty}} diff --git a/src/main/resources/handlebars/csharp/modelGeneric.mustache b/src/main/resources/handlebars/csharp/modelGeneric.mustache index 0d98ecaf61..6168a7ccb9 100644 --- a/src/main/resources/handlebars/csharp/modelGeneric.mustache +++ b/src/main/resources/handlebars/csharp/modelGeneric.mustache @@ -9,7 +9,7 @@ {{#generatePropertyChanged}} [ImplementPropertyChanged] {{/generatePropertyChanged}} - {{>visibility}} partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}>{{^netStandard}}{{#validatable}}, IValidatableObject{{/validatable}}{{/netStandard}} + {{>visibility}} partial class {{classname}} : {{#parent}}{{{parent}}}, {{/parent}} IEquatable<{{classname}}>{{^netStandard}}{{#validatable}}, IValidatableObject{{/validatable}}{{/netStandard}}{{#interfaceModels}}{{#@first}}, {{/@first}}{{classname}}{{^@last}}, {{/@last}}{{#@last}} {{/@last}}{{/interfaceModels}} { {{#vars}} {{#items.isEnum}} @@ -248,7 +248,9 @@ this.{{name}} = {{#lambda.camelcase_param}}{{name}}{{/lambda.camelcase_param}}; {{/discriminator}} {{#parent}} {{^isArrayModel}} + {{#discriminator}} foreach(var x in BaseValidate(validationContext)) yield return x; + {{/discriminator}} {{/isArrayModel}} {{/parent}} {{#vars}} diff --git a/src/main/resources/handlebars/csharp/modelInnerEnum.mustache b/src/main/resources/handlebars/csharp/modelInnerEnum.mustache index 2d8626b54e..6a3fabb10e 100644 --- a/src/main/resources/handlebars/csharp/modelInnerEnum.mustache +++ b/src/main/resources/handlebars/csharp/modelInnerEnum.mustache @@ -12,10 +12,10 @@ { {{#allowableValues}}{{#enumVars}} /// - /// Enum {{name}} for value: {{{value}}} + /// Enum {{name}} for value: {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}} /// - {{#isString}}[EnumMember(Value = "{{{value}}}")]{{/isString}} - {{name}}{{^isString}} = {{{value}}}{{/isString}}{{#isString}} = {{@index}}{{/isString}}{{^@last}}, + {{#isString}}[EnumMember(Value = {{#value}}"{{{value}}}"{{/value}}{{^value}}null{{/value}})]{{/isString}} + {{name}}{{^isString}} = {{#value}}{{{value}}}{{/value}}{{^value}}null{{/value}}{{/isString}}{{#isString}} = {{@index_1}}{{/isString}}{{^@last}}, {{/@last}}{{/enumVars}}{{/allowableValues}} } {{/isContainer}} diff --git a/src/main/resources/handlebars/csharp/nuspec.mustache b/src/main/resources/handlebars/csharp/nuspec.mustache index e061877340..0585152685 100644 --- a/src/main/resources/handlebars/csharp/nuspec.mustache +++ b/src/main/resources/handlebars/csharp/nuspec.mustache @@ -30,7 +30,7 @@ - + {{#generatePropertyChanged}} diff --git a/src/main/resources/handlebars/dart/README.mustache b/src/main/resources/handlebars/dart/README.mustache new file mode 100644 index 0000000000..3d087cb680 --- /dev/null +++ b/src/main/resources/handlebars/dart/README.mustache @@ -0,0 +1,132 @@ +# {{pubName}} +{{#appDescription}} +{{{appDescription}}} +{{/appDescription}} + +This Dart package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: + +- API version: {{appVersion}} +{{#artifactVersion}} +- Package version: {{artifactVersion}} +{{/artifactVersion}} +{{^hideGenerationTimestamp}} +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} +- Build package: {{generatorClass}} +{{#infoUrl}} +For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +## Requirements + +Dart 1.20.0 or later OR Flutter 0.0.20 or later + +## Installation & Usage + +### Github +If this Dart package is published to Github, please include the following in pubspec.yaml +``` +name: {{pubName}} +version: {{pubVersion}} +description: {{pubDescription}} +dependencies: + {{pubName}}: + git: https://github.com/{{gitUserId}}/{{gitRepoId}}.git + version: 'any' +``` + +### Local +To use the package in your local drive, please include the following in pubspec.yaml +``` +dependencies: + {{pubName}}: + path: /path/to/{{pubName}} +``` + +## Tests + +TODO + +## Getting Started + +Please follow the [installation procedure](#installation--usage) and then run the following: + +```dart +import 'package:{{pubName}}/api.dart'; +{{#apiInfo}}{{#apis}}{{#@first}}{{#operations}}{{#operation}}{{#@first}} +{{#hasAuthMethods}} +{{#authMethods}} +{{#isBasic}} +// TODO Configure HTTP basic authorization: {{{name}}} +//{{pubName}}.api.Configuration.username = 'YOUR_USERNAME'; +//{{pubName}}.api.Configuration.password = 'YOUR_PASSWORD'; +{{/isBasic}} +{{#isApiKey}} +// TODO Configure API key authorization: {{{name}}} +//{{pubName}}.api.Configuration.apiKey{'{{{keyParamName}}}'} = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//{{pubName}}.api.Configuration.apiKeyPrefix{'{{{keyParamName}}}'} = "Bearer"; +{{/isApiKey}} +{{#isOAuth}} +// TODO Configure OAuth2 access token for authorization: {{{name}}} +//{{pubName}}.api.Configuration.accessToken = 'YOUR_ACCESS_TOKEN'; +{{/isOAuth}} +{{/authMethods}} +{{/hasAuthMethods}} + +var api_instance = new {{classname}}(); +{{#allParams}} +var {{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}new {{dataType}}(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; // {{{dataType}}} | {{{description}}} +{{/allParams}} + +try { + {{#returnType}}var result = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); + {{#returnType}} + print(result); + {{/returnType}} +} catch (e) { + print("Exception when calling {{classname}}->{{operationId}}: $e\n"); +} +{{/@first}}{{/operation}}{{/operations}}{{/@first}}{{/apis}}{{/apiInfo}} +``` + +## Documentation for API Endpoints + +All URIs are relative to *{{basePath}}* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}/{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} +{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} + +## Documentation For Models + +{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}/{{{classname}}}.md) +{{/model}}{{/models}} + +## Documentation For Authorization + +{{^authMethods}} All endpoints do not require authorization. +{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}} +{{#authMethods}}## {{{name}}} + +{{#isApiKey}}- **Type**: API key +- **API key parameter name**: {{{keyParamName}}} +- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} +{{/isApiKey}} +{{#isBasic}}- **Type**: HTTP basic authentication +{{/isBasic}} +{{#isOAuth}}- **Type**: OAuth +- **Flow**: {{{flow}}} +- **Authorization URL**: {{{authorizationUrl}}} +- **Scopes**: {{^scopes}}N/A{{/scopes}} +{{#each scopes}} - **{{{@key}}}**: {{{this}}} +{{/each}} +{{/isOAuth}} + +{{/authMethods}} + +## Author + +{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} +{{/hasMore}}{{/apis}}{{/apiInfo}} diff --git a/src/main/resources/handlebars/dart/analysis_options.mustache b/src/main/resources/handlebars/dart/analysis_options.mustache new file mode 100644 index 0000000000..518eb901a6 --- /dev/null +++ b/src/main/resources/handlebars/dart/analysis_options.mustache @@ -0,0 +1,2 @@ +analyzer: + strong-mode: true \ No newline at end of file diff --git a/src/main/resources/handlebars/dart/api.mustache b/src/main/resources/handlebars/dart/api.mustache new file mode 100644 index 0000000000..cf33546505 --- /dev/null +++ b/src/main/resources/handlebars/dart/api.mustache @@ -0,0 +1,112 @@ +part of {{pubName}}.api; + +{{#operations}} + + +class {{classname}} { + final ApiClient apiClient; + + {{classname}}([ApiClient apiClient]) : apiClient = apiClient ?? defaultApiClient; + + {{#operation}} + {{#contents}} + {{#@first}} + /// {{summary}} + /// + /// {{notes}} + {{#isDeprecated}} + @deprecated + {{/isDeprecated}} + {{#returnType}}Future<{{{returnType}}}> {{/returnType}}{{^returnType}}Future {{/returnType}}{{nickname}}({{#parameters}}{{#required}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/parameters}}{{#hasOptionalParams}}{ {{#parameters}}{{^required}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/parameters}} }{{/hasOptionalParams}}) async { + Object postBody = {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}null{{/bodyParam}}; + + // verify required params are set + {{#parameters}} + {{#required}} + if({{paramName}} == null) { + throw new ApiException(400, "Missing required param: {{paramName}}"); + } + {{/required}} + {{/parameters}} + + // create path and map variables + String path = "{{{path}}}".replaceAll("{format}","json"){{#pathParams}}.replaceAll("{" + "{{baseName}}" + "}", {{{paramName}}}.toString()){{/pathParams}}; + + // query params + List queryParams = []; + Map headerParams = {}; + Map formParams = {}; + {{#queryParams}} + {{^required}} + if({{paramName}} != null) { + {{/required}} + queryParams.addAll(_convertParametersForCollectionFormat("{{collectionFormat}}", "{{baseName}}", {{paramName}})); + {{^required}} + } + {{/required}} + {{/queryParams}} + {{#headerParams}}headerParams["{{baseName}}"] = {{paramName}}; + {{/headerParams}} + + List contentTypes = [{{#consumes}}"{{{mediaType}}}"{{#hasMore}},{{/hasMore}}{{/consumes}}]; + + String contentType = contentTypes.length > 0 ? contentTypes[0] : "application/json"; + List authNames = [{{#authMethods}}"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}}]; + + if(contentType.startsWith("multipart/form-data")) { + bool hasFields = false; + MultipartRequest mp = new MultipartRequest(null, null); + {{#formParams}}{{#notFile}} + if ({{paramName}} != null) { + hasFields = true; + mp.fields['{{baseName}}'] = parameterToString({{paramName}}); + } + {{/notFile}}{{#isFile}} + if ({{paramName}} != null) { + hasFields = true; + mp.fields['{{baseName}}'] = {{paramName}}.field; + mp.files.add({{paramName}}); + } + {{/isFile}}{{/formParams}} + if(hasFields) + postBody = mp; + } + else { + {{#formParams}}{{#notFile}}if ({{paramName}} != null) + formParams['{{baseName}}'] = parameterToString({{paramName}});{{/notFile}} + {{/formParams}} + } + + var response = await apiClient.invokeAPI(path, + '{{httpMethod}}', + queryParams, + postBody, + headerParams, + formParams, + contentType, + authNames); + + if(response.statusCode >= 400) { + throw new ApiException(response.statusCode, response.body); + } else if(response.body != null) { + return + {{#isListContainer}} + {{#returnType}}(apiClient.deserialize(response.body, '{{{returnType}}}') as List).map((item) => item as {{returnBaseType}}).toList();{{/returnType}} + {{/isListContainer}} + {{^isListContainer}} + {{#isMapContainer}} + {{#returnType}}new {{{returnType}}}.from(apiClient.deserialize(response.body, '{{{returnType}}}')) {{/returnType}}; + {{/isMapContainer}} + {{^isMapContainer}} + {{#returnType}}apiClient.deserialize(response.body, '{{{returnType}}}') as {{{returnType}}} {{/returnType}}; + {{/isMapContainer}} + {{/isListContainer}} + } else { + return {{#returnType}}null{{/returnType}}; + } + } + {{/@first}} + {{/contents}} + {{/operation}} +} +{{/operations}} diff --git a/src/main/resources/handlebars/dart/api_client.mustache b/src/main/resources/handlebars/dart/api_client.mustache new file mode 100644 index 0000000000..f20af46c7b --- /dev/null +++ b/src/main/resources/handlebars/dart/api_client.mustache @@ -0,0 +1,160 @@ +part of {{pubName}}.api; + +class QueryParam { + String name; + String value; + + QueryParam(this.name, this.value); +} + +class ApiClient { + + String basePath; + var client = new {{#browserClient}}Browser{{/browserClient}}Client(); + + Map _defaultHeaderMap = {}; + Map _authentications = {}; + + final _RegList = new RegExp(r'^List<(.*)>$'); + final _RegMap = new RegExp(r'^Map$'); + + ApiClient({this.basePath: "{{{basePath}}}"}) { + // Setup authentications (key: authentication name, value: authentication).{{#authMethods}}{{#isBasic}} + _authentications['{{name}}'] = new HttpBasicAuth();{{/isBasic}}{{#isApiKey}} + _authentications['{{name}}'] = new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}");{{/isApiKey}}{{#isOAuth}} + _authentications['{{name}}'] = new OAuth();{{/isOAuth}}{{/authMethods}} + } + + void addDefaultHeader(String key, String value) { + _defaultHeaderMap[key] = value; + } + + dynamic _deserialize(dynamic value, String targetType) { + try { + switch (targetType) { + case 'String': + return '$value'; + case 'int': + return value is int ? value : int.parse('$value'); + case 'bool': + return value is bool ? value : '$value'.toLowerCase() == 'true'; + case 'double': + return value is double ? value : double.parse('$value'); + {{#models}} + {{#model}} + case '{{classname}}': + {{#isEnum}} + return new {{classname}}.fromJson(value); + {{/isEnum}} + {{^isEnum}} + return new {{classname}}.fromJson(value); + {{/isEnum}} + {{/model}} + {{/models}} + default: + { + Match match; + if (value is List && + (match = _RegList.firstMatch(targetType)) != null) { + var newTargetType = match[1]; + return value.map((v) => _deserialize(v, newTargetType)).toList(); + } else if (value is Map && + (match = _RegMap.firstMatch(targetType)) != null) { + var newTargetType = match[1]; + return new Map.fromIterables(value.keys, + value.values.map((v) => _deserialize(v, newTargetType))); + } + } + } + } catch (e, stack) { + throw new ApiException.withInner(500, 'Exception during deserialization.', e, stack); + } + throw new ApiException(500, 'Could not find a suitable class for deserialization'); + } + + dynamic deserialize(String jsonVal, String targetType) { + // Remove all spaces. Necessary for reg expressions as well. + targetType = targetType.replaceAll(' ', ''); + + if (targetType == 'String') return jsonVal; + + var decodedJson = json.decode(jsonVal); + return _deserialize(decodedJson, targetType); + } + + String serialize(Object obj) { + String serialized = ''; + if (obj == null) { + serialized = ''; + } else { + serialized = json.encode(obj); + } + return serialized; + } + + // We don't use a Map for queryParams. + // If collectionFormat is 'multi' a key might appear multiple times. + Future invokeAPI(String path, + String method, + Iterable queryParams, + Object body, + Map headerParams, + Map formParams, + String contentType, + List authNames) async { + + _updateParamsForAuth(authNames, queryParams, headerParams); + + var ps = queryParams.where((p) => p.value != null).map((p) => '${Uri.encodeComponent(p.name)}=${Uri.encodeComponent(p.value)}'); + String queryString = ps.isNotEmpty ? + '?' + ps.join('&') : + ''; + + String url = basePath + path + queryString; + + headerParams.addAll(_defaultHeaderMap); + headerParams['Content-Type'] = contentType; + + if(body is MultipartRequest) { + var request = new MultipartRequest(method, Uri.parse(url)); + request.fields.addAll(body.fields); + request.files.addAll(body.files); + request.headers.addAll(body.headers); + request.headers.addAll(headerParams); + var response = await client.send(request); + return Response.fromStream(response); + } else { + var msgBody = contentType == "application/x-www-form-urlencoded" ? formParams : serialize(body); + switch(method) { + case "POST": + return client.post(url, headers: headerParams, body: msgBody); + case "PUT": + return client.put(url, headers: headerParams, body: msgBody); + case "DELETE": + return client.delete(url, headers: headerParams); + case "PATCH": + return client.patch(url, headers: headerParams, body: msgBody); + default: + return client.get(url, headers: headerParams); + } + } + } + + /// Update query and header parameters based on authentication settings. + /// @param authNames The authentications to apply + void _updateParamsForAuth(List authNames, List queryParams, Map headerParams) { + authNames.forEach((authName) { + Authentication auth = _authentications[authName]; + if (auth == null) throw new ArgumentError("Authentication undefined: " + authName); + auth.applyToParams(queryParams, headerParams); + }); + } + + void setAccessToken(String accessToken) { + _authentications.forEach((key, auth) { + if (auth is OAuth) { + auth.setAccessToken(accessToken); + } + }); + } +} diff --git a/src/main/resources/handlebars/dart/api_doc.mustache b/src/main/resources/handlebars/dart/api_doc.mustache new file mode 100644 index 0000000000..c2bf404775 --- /dev/null +++ b/src/main/resources/handlebars/dart/api_doc.mustache @@ -0,0 +1,86 @@ +# {{pubName}}.api.{{classname}}{{#description}} +{{description}}{{/description}} + +## Load the API package +```dart +import 'package:{{pubName}}/api.dart'; +``` + +All URIs are relative to *{{basePath}}* + +Method | HTTP request | Description +------------- | ------------- | ------------- +{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} +{{/operation}}{{/operations}} + +{{#operations}} +{{#operation}} +# **{{{operationId}}}** +> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) + +{{{summary}}}{{#notes}} + +{{{notes}}}{{/notes}} + +### Example +```dart +import 'package:{{pubName}}/api.dart'; +{{#hasAuthMethods}} +{{#authMethods}} +{{#isBasic}} +// TODO Configure HTTP basic authorization: {{{name}}} +//{{pubName}}.api.Configuration.username = 'YOUR_USERNAME'; +//{{pubName}}.api.Configuration.password = 'YOUR_PASSWORD'; +{{/isBasic}} +{{#isApiKey}} +// TODO Configure API key authorization: {{{name}}} +//{{pubName}}.api.Configuration.apiKey{'{{{keyParamName}}}'} = 'YOUR_API_KEY'; +// uncomment below to setup prefix (e.g. Bearer) for API key, if needed +//{{pubName}}.api.Configuration.apiKeyPrefix{'{{{keyParamName}}}'} = "Bearer"; +{{/isApiKey}} +{{#isOAuth}} +// TODO Configure OAuth2 access token for authorization: {{{name}}} +//{{pubName}}.api.Configuration.accessToken = 'YOUR_ACCESS_TOKEN'; +{{/isOAuth}} +{{/authMethods}} +{{/hasAuthMethods}} + +var api_instance = new {{classname}}(); +{{#allParams}} +var {{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}new {{dataType}}(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; // {{{dataType}}} | {{{description}}} +{{/allParams}} + +try { + {{#returnType}}var result = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); + {{#returnType}} + print(result); + {{/returnType}} +} catch (e) { + print("Exception when calling {{classname}}->{{operationId}}: $e\n"); +} +``` + +### Parameters +{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#@last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | -------------{{/@last}}{{/allParams}} +{{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} +{{/allParams}} + +### Return type + +{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}} + +### Authorization + +{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^@last}}, {{/@last}}{{/authMethods}} + +### HTTP request headers + + - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} + - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +{{/operation}} +{{/operations}} diff --git a/src/main/resources/handlebars/dart/api_exception.mustache b/src/main/resources/handlebars/dart/api_exception.mustache new file mode 100644 index 0000000000..b86af8d954 --- /dev/null +++ b/src/main/resources/handlebars/dart/api_exception.mustache @@ -0,0 +1,23 @@ +part of {{pubName}}.api; + +class ApiException implements Exception { + int code = 0; + String message = null; + Exception innerException = null; + StackTrace stackTrace = null; + + ApiException(this.code, this.message); + + ApiException.withInner(this.code, this.message, this.innerException, this.stackTrace); + + String toString() { + if (message == null) return "ApiException"; + + if (innerException == null) { + return "ApiException $code: $message"; + } + + return "ApiException $code: $message (Inner exception: ${innerException})\n\n" + + stackTrace.toString(); + } +} diff --git a/src/main/resources/handlebars/dart/api_helper.mustache b/src/main/resources/handlebars/dart/api_helper.mustache new file mode 100644 index 0000000000..ead4b041b9 --- /dev/null +++ b/src/main/resources/handlebars/dart/api_helper.mustache @@ -0,0 +1,52 @@ +part of {{pubName}}.api; + +const _delimiters = const {'csv': ',', 'ssv': ' ', 'tsv': '\t', 'pipes': '|'}; + +// port from Java version +Iterable _convertParametersForCollectionFormat( + String collectionFormat, String name, dynamic value) { + var params = []; + + // preconditions + if (name == null || name.isEmpty || value == null) return params; + + if (value is! List) { + params.add(new QueryParam(name, parameterToString(value))); + return params; + } + + List values = value as List; + + // get the collection format + collectionFormat = (collectionFormat == null || collectionFormat.isEmpty) + ? "csv" + : collectionFormat; // default: csv + + if (collectionFormat == "multi") { + return values.map((v) => new QueryParam(name, parameterToString(v))); + } + + String delimiter = _delimiters[collectionFormat] ?? ","; + + params.add(new QueryParam(name, values.map((v) => parameterToString(v)).join(delimiter))); + return params; +} + +/// Format the given parameter object into string. +String parameterToString(dynamic value) { + if (value == null) { + return ''; + } else if (value is DateTime) { + return value.toUtc().toIso8601String(); + {{#models}} + {{#model}} + {{#isEnum}} + } else if (value is {{classname}}) { + return {{classname}}.encode(value).toString(); + {{/isEnum}} + {{/model}} + {{/models}} + } else { + return value.toString(); + } +} diff --git a/src/main/resources/handlebars/dart/api_test.mustache b/src/main/resources/handlebars/dart/api_test.mustache new file mode 100644 index 0000000000..6d552c7e3d --- /dev/null +++ b/src/main/resources/handlebars/dart/api_test.mustache @@ -0,0 +1,28 @@ +import 'package:{{pubName}}/api.dart'; +import 'package:test/test.dart'; + +{{#operations}} + +/// tests for {{classname}} +void main() { + var instance = new {{classname}}(); + + group('tests for {{classname}}', () { + {{#operation}} + {{#summary}} + // {{{.}}} + // + {{/summary}} + {{#notes}} + // {{{.}}} + // + {{/notes}} + //{{#returnType}}Future<{{{returnType}}}> {{/returnType}}{{^returnType}}Future {{/returnType}}{{operationId}}({{#allParams}}{{#required}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/allParams}}{{#hasOptionalParams}}{ {{#allParams}}{{^required}}{{{dataType}}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/allParams}} }{{/hasOptionalParams}}) async + test('test {{operationId}}', () async { + // TODO + }); + + {{/operation}} + }); +} +{{/operations}} diff --git a/src/main/resources/handlebars/dart/apilib.mustache b/src/main/resources/handlebars/dart/apilib.mustache new file mode 100644 index 0000000000..818f878c61 --- /dev/null +++ b/src/main/resources/handlebars/dart/apilib.mustache @@ -0,0 +1,21 @@ +library {{pubName}}.api; + +import 'dart:async'; +import 'dart:convert';{{#browserClient}} +import 'package:http/browser_client.dart';{{/browserClient}} +import 'package:http/http.dart'; + +part 'api_client.dart'; +part 'api_helper.dart'; +part 'api_exception.dart'; +part 'auth/authentication.dart'; +part 'auth/api_key_auth.dart'; +part 'auth/oauth.dart'; +part 'auth/http_basic_auth.dart'; + +{{#apiInfo}}{{#apis}}part 'api/{{classFilename}}.dart'; +{{/apis}}{{/apiInfo}} +{{#models}}{{#model}}part 'model/{{classFilename}}.dart'; +{{/model}}{{/models}} + +ApiClient defaultApiClient = new ApiClient(); diff --git a/src/main/resources/handlebars/dart/auth/api_key_auth.mustache b/src/main/resources/handlebars/dart/auth/api_key_auth.mustache new file mode 100644 index 0000000000..86bde8a90f --- /dev/null +++ b/src/main/resources/handlebars/dart/auth/api_key_auth.mustache @@ -0,0 +1,27 @@ +part of {{pubName}}.api; + +class ApiKeyAuth implements Authentication { + + final String location; + final String paramName; + String apiKey; + String apiKeyPrefix; + + ApiKeyAuth(this.location, this.paramName); + + @override + void applyToParams(List queryParams, Map headerParams) { + String value; + if (apiKeyPrefix != null) { + value = '$apiKeyPrefix $apiKey'; + } else { + value = apiKey; + } + + if (location == 'query' && value != null) { + queryParams.add(new QueryParam(paramName, value)); + } else if (location == 'header' && value != null) { + headerParams[paramName] = value; + } + } +} diff --git a/src/main/resources/handlebars/dart/auth/authentication.mustache b/src/main/resources/handlebars/dart/auth/authentication.mustache new file mode 100644 index 0000000000..00bbbf0974 --- /dev/null +++ b/src/main/resources/handlebars/dart/auth/authentication.mustache @@ -0,0 +1,7 @@ +part of {{pubName}}.api; + +abstract class Authentication { + + /// Apply authentication settings to header and query params. + void applyToParams(List queryParams, Map headerParams); +} diff --git a/src/main/resources/handlebars/dart/auth/http_basic_auth.mustache b/src/main/resources/handlebars/dart/auth/http_basic_auth.mustache new file mode 100644 index 0000000000..bbb177421d --- /dev/null +++ b/src/main/resources/handlebars/dart/auth/http_basic_auth.mustache @@ -0,0 +1,13 @@ +part of {{pubName}}.api; + +class HttpBasicAuth implements Authentication { + + String username; + String password; + + @override + void applyToParams(List queryParams, Map headerParams) { + String str = (username == null ? "" : username) + ":" + (password == null ? "" : password); + headerParams["Authorization"] = "Basic " + base64.encode(utf8.encode(str)); + } +} diff --git a/src/main/resources/handlebars/dart/auth/oauth.mustache b/src/main/resources/handlebars/dart/auth/oauth.mustache new file mode 100644 index 0000000000..5b96ecc9d7 --- /dev/null +++ b/src/main/resources/handlebars/dart/auth/oauth.mustache @@ -0,0 +1,19 @@ +part of {{pubName}}.api; + +class OAuth implements Authentication { + String accessToken; + + OAuth({this.accessToken}) { + } + + @override + void applyToParams(List queryParams, Map headerParams) { + if (accessToken != null) { + headerParams["Authorization"] = "Bearer " + accessToken; + } + } + + void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } +} diff --git a/src/main/resources/handlebars/dart/class.mustache b/src/main/resources/handlebars/dart/class.mustache new file mode 100644 index 0000000000..2cec7c1f45 --- /dev/null +++ b/src/main/resources/handlebars/dart/class.mustache @@ -0,0 +1,52 @@ +class {{classname}} { + {{#vars}}{{#description}}/* {{{description}}} */{{/description}} + {{^isEnum}} + {{{datatype}}} {{name}} = {{{defaultValue}}}; + {{/isEnum}} + {{#isEnum}} + {{{datatype}}} {{name}} = null; + {{/isEnum}} + {{#allowableValues}} + {{#min}} // range from {{min}} to {{max}}{{/min}}//{{^min}}enum {{name}}Enum { {{#values}} {{.}}, {{/values}} };{{/min}} + {{/allowableValues}} + {{/vars}} + + {{classname}}(); + + @override + String toString() { + return '{{classname}}[{{#vars}}{{name}}=${{name}}, {{/vars}}]'; + } + + {{classname}}.fromJson(Map json) { + if (json == null) return; + {{#vars}} + {{#isDateTime}} + {{name}} = json['{{baseName}}'] == null ? null : DateTime.parse(json['{{baseName}}']); + {{/isDateTime}} + {{^isDateTime}} + {{name}} = {{#complexType}}{{#isListContainer}}{{complexType}}.listFromJson(json['{{baseName}}']){{/isListContainer}}{{^isListContainer}}{{#isMapContainer}}{{complexType}}.mapFromJson(json['{{baseName}}']){{/isMapContainer}}{{^isMapContainer}}new {{complexType}}.fromJson(json['{{baseName}}']){{/isMapContainer}}{{/isListContainer}}{{/complexType}}{{^complexType}}{{#isListContainer}}(json['{{baseName}}'] as List).map((item) => item as {{items.datatype}}).toList(){{/isListContainer}}{{^isListContainer}}json['{{baseName}}']{{/isListContainer}}{{/complexType}}; + {{/isDateTime}} + {{/vars}} + } + + Map toJson() { + return { + {{#vars}} + {{#isDateTime}}'{{baseName}}': {{name}} == null ? '' : {{name}}.toUtc().toIso8601String(){{^@last}},{{/@last}}{{/isDateTime}}{{^isDateTime}}'{{baseName}}': {{name}}{{^@last}},{{/@last}}{{/isDateTime}} + {{/vars}} + }; + } + + static List<{{classname}}> listFromJson(List json) { + return json == null ? new List<{{classname}}>() : json.map((value) => new {{classname}}.fromJson(value)).toList(); + } + + static Map mapFromJson(Map> json) { + var map = new Map(); + if (json != null && json.length > 0) { + json.forEach((String key, Map value) => map[key] = new {{classname}}.fromJson(value)); + } + return map; + } +} diff --git a/src/main/resources/handlebars/dart/enum.mustache b/src/main/resources/handlebars/dart/enum.mustache new file mode 100644 index 0000000000..8dcbfd0dc8 --- /dev/null +++ b/src/main/resources/handlebars/dart/enum.mustache @@ -0,0 +1,30 @@ +class {{classname}} { + /// The underlying value of this enum member. + {{dataType}} value; + + {{classname}}._internal(this.value); + + {{#allowableValues}} + {{#enumVars}} + {{#description}} + /// {{description}} + {{/description}} + static {{classname}} {{name}} = {{classname}}._internal({{{value}}}); + {{/enumVars}} + {{/allowableValues}} + + {{classname}}.fromJson(dynamic data) { + switch (data) { + {{#allowableValues}} + {{#enumVars}} + case {{{value}}}: value = data; break; + {{/enumVars}} + {{/allowableValues}} + default: throw('Unknown enum value to decode: $data'); + } + } + + static dynamic encode({{classname}} data) { + return data.value; + } +} \ No newline at end of file diff --git a/src/main/resources/handlebars/dart/git_push.sh.mustache b/src/main/resources/handlebars/dart/git_push.sh.mustache new file mode 100644 index 0000000000..3e868678e8 --- /dev/null +++ b/src/main/resources/handlebars/dart/git_push.sh.mustache @@ -0,0 +1,51 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="{{{gitUserId}}}" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="{{{gitRepoId}}}" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="{{{releaseNote}}}" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' diff --git a/src/main/resources/handlebars/dart/gitignore.mustache b/src/main/resources/handlebars/dart/gitignore.mustache new file mode 100644 index 0000000000..8b7331fd82 --- /dev/null +++ b/src/main/resources/handlebars/dart/gitignore.mustache @@ -0,0 +1,27 @@ +# See https://www.dartlang.org/tools/private-files.html + +# Files and directories created by pub +.buildlog +.packages +.project +.pub/ +build/ +**/packages/ + +# Files created by dart2js +# (Most Dart developers will use pub build to compile Dart, use/modify these +# rules if you intend to use dart2js directly +# Convention is to use extension '.dart.js' for Dart compiled to Javascript to +# differentiate from explicit Javascript files) +*.dart.js +*.part.js +*.js.deps +*.js.map +*.info.json + +# Directory created by dartdoc +doc/api/ + +# Don't commit pubspec lock file +# (Library packages only! Remove pattern if developing an application package) +pubspec.lock diff --git a/src/main/resources/handlebars/dart/model.mustache b/src/main/resources/handlebars/dart/model.mustache new file mode 100644 index 0000000000..1fa14e179a --- /dev/null +++ b/src/main/resources/handlebars/dart/model.mustache @@ -0,0 +1,7 @@ +part of {{pubName}}.api; + +{{#models}} +{{#model}} +{{#isEnum}}{{>enum}}{{/isEnum}}{{^isEnum}}{{>class}}{{/isEnum}} +{{/model}} +{{/models}} diff --git a/src/main/resources/handlebars/dart/object_doc.mustache b/src/main/resources/handlebars/dart/object_doc.mustache new file mode 100644 index 0000000000..9ad4463997 --- /dev/null +++ b/src/main/resources/handlebars/dart/object_doc.mustache @@ -0,0 +1,16 @@ +{{#models}}{{#model}}# {{pubName}}.model.{{classname}} + +## Load the model package +```dart +import 'package:{{pubName}}/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} +{{/vars}} + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + +{{/model}}{{/models}} diff --git a/src/main/resources/handlebars/dart/pubspec.mustache b/src/main/resources/handlebars/dart/pubspec.mustache new file mode 100644 index 0000000000..997448a9be --- /dev/null +++ b/src/main/resources/handlebars/dart/pubspec.mustache @@ -0,0 +1,7 @@ +name: {{pubName}} +version: {{pubVersion}} +description: {{pubDescription}} +dependencies: + http: '>=0.11.1 <0.13.0' +dev_dependencies: + test: ^1.3.0 diff --git a/src/main/resources/handlebars/go-server/Dockerfile b/src/main/resources/handlebars/go-server/Dockerfile new file mode 100644 index 0000000000..36e3f7ce2a --- /dev/null +++ b/src/main/resources/handlebars/go-server/Dockerfile @@ -0,0 +1,14 @@ +FROM golang:1.10 AS build +WORKDIR /go/src +COPY go ./go +COPY main.go . + +ENV CGO_ENABLED=0 +RUN go get -d -v ./... + +RUN go build -a -installsuffix cgo -o swagger . + +FROM scratch AS runtime +COPY --from=build /go/src/swagger ./ +EXPOSE 8080/tcp +ENTRYPOINT ["./swagger"] diff --git a/src/main/resources/handlebars/go-server/README.mustache b/src/main/resources/handlebars/go-server/README.mustache new file mode 100644 index 0000000000..89019f8e21 --- /dev/null +++ b/src/main/resources/handlebars/go-server/README.mustache @@ -0,0 +1,30 @@ +# Go API Server for {{packageName}} + +{{#appDescription}} +{{{appDescription}}} +{{/appDescription}} + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: {{appVersion}}{{^hideGenerationTimestamp}} +- Build date: {{generatedDate}}{{/hideGenerationTimestamp}} +{{#infoUrl}} +For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/src/main/resources/handlebars/go-server/controller-api.mustache b/src/main/resources/handlebars/go-server/controller-api.mustache new file mode 100644 index 0000000000..528e71fa21 --- /dev/null +++ b/src/main/resources/handlebars/go-server/controller-api.mustache @@ -0,0 +1,12 @@ +{{>partial_header}} +package {{packageName}} + +{{#operations}} +import ( + "net/http" +){{#operation}} + +func {{nickname}}(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +}{{/operation}}{{/operations}} diff --git a/src/main/resources/handlebars/go-server/logger.mustache b/src/main/resources/handlebars/go-server/logger.mustache new file mode 100644 index 0000000000..aa0d894d83 --- /dev/null +++ b/src/main/resources/handlebars/go-server/logger.mustache @@ -0,0 +1,24 @@ +{{>partial_header}} +package {{packageName}} + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/src/main/resources/handlebars/go-server/main.mustache b/src/main/resources/handlebars/go-server/main.mustache new file mode 100644 index 0000000000..28eb8861b1 --- /dev/null +++ b/src/main/resources/handlebars/go-server/main.mustache @@ -0,0 +1,24 @@ +{{>partial_header}} +package main + +import ( + "log" + "net/http" + + // WARNING! + // Change this to a fully-qualified import path + // once you place this file into your project. + // For example, + // + // sw "github.com/myname/myrepo/{{apiPath}}" + // + sw "./{{apiPath}}" +) + +func main() { + log.Printf("Server started") + + router := sw.NewRouter() + + log.Fatal(http.ListenAndServe(":{{serverPort}}", router)) +} diff --git a/src/main/resources/handlebars/go-server/model.mustache b/src/main/resources/handlebars/go-server/model.mustache new file mode 100644 index 0000000000..bda83d8388 --- /dev/null +++ b/src/main/resources/handlebars/go-server/model.mustache @@ -0,0 +1,31 @@ +{{>partial_header}} +package {{packageName}} +{{#models}}{{#imports}} +import ({{/imports}}{{#imports}} + "{{import}}"{{/imports}}{{#imports}} +) +{{/imports}}{{#model}}{{#isEnum}}{{#description}}// {{{classname}}} : {{{description}}}{{/description}} +type {{{name}}} {{^format}}{{dataType}}{{/format}}{{#format}}{{{format}}}{{/format}} + +// List of {{{name}}} +const ( + {{#allowableValues}} + {{#enumVars}} + {{name}} {{{classname}}} = "{{{value}}}" + {{/enumVars}} + {{/allowableValues}} +){{/isEnum}}{{^isEnum}}{{#description}} +// {{{description}}}{{/description}} +type {{classname}} struct { +{{#isComposedModel}} + {{#interfaceModels}} + {{classname}} + {{/interfaceModels}} +{{/isComposedModel}} +{{^isComposedModel}} +{{#vars}}{{#description}} + // {{{description}}}{{/description}} + {{name}} {{^isEnum}}{{^isPrimitiveType}}{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{/isPrimitiveType}}{{/isEnum}}{{{datatype}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"` +{{/vars}} +{{/isComposedModel}} +}{{/isEnum}}{{/model}}{{/models}} diff --git a/src/main/resources/handlebars/go-server/partial_header.mustache b/src/main/resources/handlebars/go-server/partial_header.mustache new file mode 100644 index 0000000000..d24dfec369 --- /dev/null +++ b/src/main/resources/handlebars/go-server/partial_header.mustache @@ -0,0 +1,17 @@ +/* + {{#appName}} + * {{{appName}}} + * + {{/appName}} + {{#appDescription}} + * {{{appDescription}}} + * + {{/appDescription}} + {{#version}} + * API version: {{{version}}} + {{/version}} + {{#infoEmail}} + * Contact: {{{infoEmail}}} + {{/infoEmail}} + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ diff --git a/src/main/resources/handlebars/go-server/routers.mustache b/src/main/resources/handlebars/go-server/routers.mustache new file mode 100644 index 0000000000..e3f5bdf345 --- /dev/null +++ b/src/main/resources/handlebars/go-server/routers.mustache @@ -0,0 +1,56 @@ +{{>partial_header}} +package {{packageName}} + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "{{{basePathWithoutHost}}}/", + Index, + },{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} + + Route{ + "{{operationId}}", + strings.ToUpper("{{httpMethod}}"), + "{{{basePathWithoutHost}}}{{{path}}}", + {{operationId}}, + },{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} +} diff --git a/src/main/resources/mustache/JavaInflector/swagger.mustache b/src/main/resources/handlebars/go-server/swagger.mustache similarity index 100% rename from src/main/resources/mustache/JavaInflector/swagger.mustache rename to src/main/resources/handlebars/go-server/swagger.mustache diff --git a/src/main/resources/handlebars/go/.travis.yml b/src/main/resources/handlebars/go/.travis.yml new file mode 100644 index 0000000000..f5cb2ce9a5 --- /dev/null +++ b/src/main/resources/handlebars/go/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/src/main/resources/handlebars/go/README.mustache b/src/main/resources/handlebars/go/README.mustache new file mode 100644 index 0000000000..5e6f10b5fa --- /dev/null +++ b/src/main/resources/handlebars/go/README.mustache @@ -0,0 +1,96 @@ +# Go API client for {{packageName}} + +{{#appDescription}} +{{{appDescription}}} +{{/appDescription}} + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: {{appVersion}} +- Package version: {{packageVersion}} +{{^hideGenerationTimestamp}} +- Build date: {{generatedDate}} +{{/hideGenerationTimestamp}} +- Build package: {{generatorClass}} +{{#infoUrl}} +For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) +{{/infoUrl}} + +## Installation +Put the package under your project folder and add the following in import: +```golang +import "./{{packageName}}" +``` + +## Documentation for API Endpoints + +All URIs are relative to *{{basePath}}* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} +{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} + +## Documentation For Models + +{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) +{{/model}}{{/models}} + +## Documentation For Authorization +{{^authMethods}} Endpoints do not require authorization. +{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}} +{{#authMethods}} +## {{{name}}} +{{#isApiKey}}- **Type**: API key + +Example +```golang +auth := context.WithValue(context.Background(), sw.ContextAPIKey, sw.APIKey{ + Key: "APIKEY", + Prefix: "Bearer", // Omit if not necessary. +}) +r, err := client.Service.Operation(auth, args) +``` +{{/isApiKey}} +{{#isBasic}}- **Type**: HTTP basic authentication + +Example +```golang +auth := context.WithValue(context.Background(), sw.ContextBasicAuth, sw.BasicAuth{ + UserName: "username", + Password: "password", +}) +r, err := client.Service.Operation(auth, args) +``` +{{/isBasic}} +{{#isOAuth}}- **Type**: OAuth +- **Flow**: {{{flow}}} +- **Authorization URL**: {{{authorizationUrl}}} +- **Scopes**: {{^scopes}}N/A{{/scopes}} +{{#each scopes}} - **{{@key}}**: {{this}} +{{/each}} + +Example +```golang +auth := context.WithValue(context.Background(), sw.ContextAccessToken, "ACCESSTOKENSTRING") +r, err := client.Service.Operation(auth, args) +``` + +Or via OAuth2 module to automatically refresh tokens and perform user authentication. +```golang +import "golang.org/x/oauth2" + +/* Perform OAuth2 round trip request and obtain a token */ + +tokenSource := oauth2cfg.TokenSource(createContext(httpClient), &token) +auth := context.WithValue(oauth2.NoContext, sw.ContextOAuth2, tokenSource) +r, err := client.Service.Operation(auth, args) +``` +{{/isOAuth}} +{{/authMethods}} + +## Author + +{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} +{{/hasMore}}{{/apis}}{{/apiInfo}} diff --git a/src/main/resources/handlebars/go/api.mustache b/src/main/resources/handlebars/go/api.mustache new file mode 100644 index 0000000000..0b571ee575 --- /dev/null +++ b/src/main/resources/handlebars/go/api.mustache @@ -0,0 +1,278 @@ + +{{>partial_header}} +package {{packageName}} + +{{#operations}} +import ( + "context" + "io/ioutil" + "net/http" + "net/url" + "strings" +{{#imports}} "{{import}}" +{{/imports}} +) + +// Linger please +var ( + _ context.Context +) + +type {{classname}}Service service +{{#operation}} +{{#contents}} +{{#@first}} +/* +{{{classname}}}Service{{#summary}} {{.}}{{/summary}}{{#notes}} +{{notes}}{{/notes}} + * @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). +{{#parameters}}{{#required}} * @param {{paramName}}{{#description}} {{.}}{{/description}} +{{/required}}{{/parameters}}{{#hasOptionalParams}} * @param optional nil or *{{{classname}}}{{{nickname}}}Opts - Optional Parameters: +{{#parameters}}{{^required}} * @param "{{vendorExtensions.x-exportParamName}}" ({{#isPrimitiveType}}optional.{{vendorExtensions.x-optionalDataType}}{{/isPrimitiveType}}{{^isPrimitiveType}}optional.Interface of {{dataType}}{{/isPrimitiveType}}) - {{#description}} {{.}}{{/description}} +{{/required}}{{/parameters}}{{/hasOptionalParams}} +{{#returnType}}@return {{{returnType}}}{{/returnType}} +*/ +{{#hasOptionalParams}} + +type {{{classname}}}{{{nickname}}}Opts struct { +{{#parameters}} +{{^required}} +{{#isPrimitiveType}} +{{#isFile}} + {{vendorExtensions.x-exportParamName}} optional.Interface +{{/isFile}} +{{^isFile}} + {{vendorExtensions.x-exportParamName}} optional.{{vendorExtensions.x-optionalDataType}} +{{/isFile}} +{{/isPrimitiveType}} +{{^isPrimitiveType}} + {{vendorExtensions.x-exportParamName}} optional.Interface +{{/isPrimitiveType}} +{{/required}} +{{/parameters}} +} + +{{/hasOptionalParams}} +func (a *{{{classname}}}Service) {{{nickname}}}(ctx context.Context{{#hasParams}}, {{/hasParams}}{{#parameters}}{{#required}}{{paramName}} {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/parameters}}{{#hasOptionalParams}}localVarOptionals *{{{classname}}}{{{nickname}}}Opts{{/hasOptionalParams}}) ({{#returnType}}{{{returnType}}}, {{/returnType}}*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("{{httpMethod}}") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + {{#returnType}}localVarReturnValue {{{returnType}}}{{/returnType}} + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "{{{path}}}"{{#pathParams}} + localVarPath = strings.Replace(localVarPath, "{"+"{{baseName}}"+"}", fmt.Sprintf("%v", {{paramName}}), -1){{/pathParams}} + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + {{#parameters}} + {{#required}} + {{#minItems}} + if len({{paramName}}) < {{minItems}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have at least {{minItems}} elements") + } + {{/minItems}} + {{#maxItems}} + if len({{paramName}}) > {{maxItems}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have less than {{maxItems}} elements") + } + {{/maxItems}} + {{#minLength}} + if strlen({{paramName}}) < {{minLength}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have at least {{minLength}} elements") + } + {{/minLength}} + {{#maxLength}} + if strlen({{paramName}}) > {{maxLength}} { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must have less than {{maxLength}} elements") + } + {{/maxLength}} + {{#minimum}} + {{#isString}} + {{paramName}}Txt, err := atoi({{paramName}}) + if {{paramName}}Txt < {{minimum}} { + {{/isString}} + {{^isString}} + if {{paramName}} < {{minimum}} { + {{/isString}} + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must be greater than {{minimum}}") + } + {{/minimum}} + {{#maximum}} + {{#isString}} + {{paramName}}Txt, err := atoi({{paramName}}) + if {{paramName}}Txt > {{maximum}} { + {{/isString}} + {{^isString}} + if {{paramName}} > {{maximum}} { + {{/isString}} + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} must be less than {{maximum}}") + } + {{/maximum}} + {{/required}} + {{/parameters}} + + {{#hasQueryParams}} + {{#queryParams}} + {{#required}} + localVarQueryParams.Add("{{baseName}}", parameterToString({{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}")) + {{/required}} + {{^required}} + if localVarOptionals != nil && localVarOptionals.{{vendorExtensions.x-exportParamName}}.IsSet() { + localVarQueryParams.Add("{{baseName}}", parameterToString(localVarOptionals.{{vendorExtensions.x-exportParamName}}.Value(), "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}")) + } + {{/required}} + {{/queryParams}} + {{/hasQueryParams}} + // to determine the Content-Type header +{{=<% %>=}} + localVarHttpContentTypes := []string{<%#consumes%>"<%&mediaType%>"<%^@last%>, <%/@last%><%/consumes%>} +<%={{ }}=%> + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header +{{=<% %>=}} + localVarHttpHeaderAccepts := []string{<%#produces%>"<%&mediaType%>"<%^@last%>, <%/@last%><%/produces%>} +<%={{ }}=%> + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } +{{#hasHeaderParams}} +{{#headerParams}} + {{#required}} + localVarHeaderParams["{{baseName}}"] = parameterToString({{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}") + {{/required}} + {{^required}} + if localVarOptionals != nil && localVarOptionals.{{vendorExtensions.x-exportParamName}}.IsSet() { + localVarHeaderParams["{{baseName}}"] = parameterToString(localVarOptionals.{{vendorExtensions.x-exportParamName}}.Value(), "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}") + } + {{/required}} +{{/headerParams}} +{{/hasHeaderParams}} +{{#hasFormParams}} +{{#formParams}} +{{#isFile}} +{{#required}} + localVarFile := {{paramName}} +{{/required}} +{{^required}} + var localVarFile {{dataType}} + if localVarOptionals != nil && localVarOptionals.{{vendorExtensions.x-exportParamName}}.IsSet() { + localVarFileOk := false + localVarFile, localVarFileOk = localVarOptionals.{{vendorExtensions.x-exportParamName}}.Value().({{dataType}}) + if !localVarFileOk { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, reportError("{{paramName}} should be {{dataType}}") + } + } +{{/required}} + if localVarFile != nil { + fbs, _ := ioutil.ReadAll(localVarFile) + localVarFileBytes = fbs + localVarFileName = localVarFile.Name() + localVarFile.Close() + } +{{/isFile}} +{{^isFile}} +{{#required}} + localVarFormParams.Add("{{baseName}}", parameterToString({{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}")) +{{/required}} +{{^required}} + if localVarOptionals != nil && localVarOptionals.{{vendorExtensions.x-exportParamName}}.IsSet() { + localVarFormParams.Add("{{baseName}}", parameterToString(localVarOptionals.{{vendorExtensions.x-exportParamName}}.Value(), "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}")) + } +{{/required}} +{{/isFile}} +{{/formParams}} +{{/hasFormParams}} +{{#hasBodyParam}} +{{#bodyParams}} // body params +{{#required}} + localVarPostBody = &{{paramName}} +{{/required}} +{{^required}} + if localVarOptionals != nil && localVarOptionals.{{vendorExtensions.x-exportParamName}}.IsSet() { + {{#isPrimitiveType}}localVarPostBody = &localVarOptionals.{{vendorExtensions.x-exportParamName}}.Value(){{/isPrimitiveType}} + {{^isPrimitiveType}}localVarOptional{{vendorExtensions.x-exportParamName}}:= localVarOptionals.{{vendorExtensions.x-exportParamName}}.Value() + localVarPostBody = &localVarOptional{{vendorExtensions.x-exportParamName}}{{/isPrimitiveType}} + } +{{/required}} +{{/bodyParams}} +{{/hasBodyParam}} +{{#authMethods}} +{{#isApiKey}} + if ctx != nil { + // API Key Authentication + if auth, ok := ctx.Value(ContextAPIKey).(APIKey); ok { + var key string + if auth.Prefix != "" { + key = auth.Prefix + " " + auth.Key + } else { + key = auth.Key + } + {{#isKeyInHeader}}localVarHeaderParams["{{keyParamName}}"] = key{{/isKeyInHeader}} + {{#isKeyInQuery}}localVarQueryParams.Add("{{keyParamName}}", key){{/isKeyInQuery}} + } + } +{{/isApiKey}} +{{/authMethods}} + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHttpResponse.Body) + localVarHttpResponse.Body.Close() + if err != nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, err + } + + {{#returnType}} + if localVarHttpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err == nil { + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, err + } + } + {{/returnType}} + + if localVarHttpResponse.StatusCode >= 300 { + newErr := GenericSwaggerError{ + body: localVarBody, + error: localVarHttpResponse.Status, + } + {{#responses}}{{#dataType}} + if localVarHttpResponse.StatusCode == {{{code}}} { + var v {{{dataType}}} + err = a.client.decode(&v, localVarBody, localVarHttpResponse.Header.Get("Content-Type")); + if err != nil { + newErr.error = err.Error() + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, newErr + } + newErr.model = v + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, newErr + } + {{/dataType}}{{/responses}} + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, newErr + } + + return {{#returnType}}localVarReturnValue, {{/returnType}}localVarHttpResponse, nil +} +{{/@first}}{{/contents}}{{/operation}}{{/operations}} \ No newline at end of file diff --git a/src/main/resources/handlebars/go/api_doc.mustache b/src/main/resources/handlebars/go/api_doc.mustache new file mode 100644 index 0000000000..d4af105aae --- /dev/null +++ b/src/main/resources/handlebars/go/api_doc.mustache @@ -0,0 +1,50 @@ +# {{invokerPackage}}\{{classname}}{{#description}} +{{description}}{{/description}} + +All URIs are relative to *{{basePath}}* + +Method | HTTP request | Description +------------- | ------------- | ------------- +{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} +{{/operation}}{{/operations}} + +{{#operations}} +{{#operation}} +# **{{{operationId}}}** +> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}(ctx, {{#allParams}}{{#required}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/required}}{{/allParams}}{{#hasOptionalParams}}optional{{/hasOptionalParams}}) +{{{summary}}}{{#notes}} + +{{{notes}}}{{/notes}} + +### Required Parameters +{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#@last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc.{{/@last}}{{/allParams}}{{#allParams}}{{#required}} + **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}{{/required}}{{/allParams}}{{#hasOptionalParams}} + **optional** | ***{{{classname}}}{{{nickname}}}Opts** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a pointer to a {{{classname}}}{{{nickname}}}Opts struct +{{#allParams}}{{#@last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | -------------{{/@last}}{{/allParams}}{{#allParams}} +{{^required}} **{{paramName}}** | {{#isFile}}**optional.Interface of {{dataType}}**{{/isFile}}{{#isPrimitiveType}}**optional.{{vendorExtensions.x-optionalDataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**optional.Interface of {{dataType}}**]({{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} | {{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}}{{/required}}{{/allParams}}{{/hasOptionalParams}} + +### Return type + +{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}} (empty response body){{/returnType}} + +### Authorization + +{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^@last}}, {{/@last}}{{/authMethods}} + +### HTTP request headers + + - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} + - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +{{/operation}} +{{/operations}} diff --git a/src/main/resources/handlebars/go/client.mustache b/src/main/resources/handlebars/go/client.mustache new file mode 100644 index 0000000000..900e3f5ad1 --- /dev/null +++ b/src/main/resources/handlebars/go/client.mustache @@ -0,0 +1,478 @@ +{{>partial_header}} +package {{packageName}} + +import ( + "bytes" + "context" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the {{appName}} API v{{version}} +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services +{{#apiInfo}} +{{#apis}} +{{#operations}} + + {{classname}} *{{classname}}Service +{{/operations}} +{{/apis}} +{{/apiInfo}} +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + +{{#apiInfo}} + // API Services +{{#apis}} +{{#operations}} + c.{{classname}} = (*{{classname}}Service)(&c.common) +{{/operations}} +{{/apis}} +{{/apiInfo}} + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 { + if body != nil { + return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.") + } + body = &bytes.Buffer{} + body.WriteString(formParams.Encode()) + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { + if strings.Contains(contentType, "application/xml") { + if err = xml.Unmarshal(b, v); err != nil { + return err + } + return nil + } else if strings.Contains(contentType, "application/json") { + if err = json.Unmarshal(b, v); err != nil { + return err + } + return nil + } + return errors.New("undefined response type") +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if s, ok := body.(*string); ok { + _, err = bodyBuf.WriteString(*s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} + +// GenericSwaggerError Provides access to the body, error and model on returned errors. +type GenericSwaggerError struct { + body []byte + error string + model interface{} +} + +// Error returns non-empty string if there was an error. +func (e GenericSwaggerError) Error() string { + return e.error +} + +// Body returns the raw bytes of the response +func (e GenericSwaggerError) Body() []byte { + return e.body +} + +// Model returns the unpacked model of the error +func (e GenericSwaggerError) Model() interface{} { + return e.model +} diff --git a/src/main/resources/handlebars/go/configuration.mustache b/src/main/resources/handlebars/go/configuration.mustache new file mode 100644 index 0000000000..1b583e5427 --- /dev/null +++ b/src/main/resources/handlebars/go/configuration.mustache @@ -0,0 +1,64 @@ +{{>partial_header}} +package {{packageName}} + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "{{{basePath}}}", + DefaultHeader: make(map[string]string), + UserAgent: "{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/go{{/httpUserAgent}}", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/src/main/resources/mustache/Java/git_push.sh.mustache b/src/main/resources/handlebars/go/git_push.sh.mustache similarity index 100% rename from src/main/resources/mustache/Java/git_push.sh.mustache rename to src/main/resources/handlebars/go/git_push.sh.mustache diff --git a/src/main/resources/handlebars/go/gitignore.mustache b/src/main/resources/handlebars/go/gitignore.mustache new file mode 100644 index 0000000000..daf913b1b3 --- /dev/null +++ b/src/main/resources/handlebars/go/gitignore.mustache @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/src/main/resources/handlebars/go/model.mustache b/src/main/resources/handlebars/go/model.mustache new file mode 100644 index 0000000000..4296649d7f --- /dev/null +++ b/src/main/resources/handlebars/go/model.mustache @@ -0,0 +1,43 @@ +{{>partial_header}} +package {{packageName}} +{{#models}} +{{#imports}} +{{#@first}} +import ( +{{/@first}} + "{{import}}" +{{#@last}} +) +{{/@last}} +{{/imports}} +{{#model}}{{#isEnum}}{{#description}}// {{{classname}}} : {{{description}}}{{/description}} +type {{{classname}}} {{^format}}{{dataType}}{{/format}}{{#format}}{{{format}}}{{/format}} + +// List of {{{name}}} +const ( + {{#allowableValues}} + {{#enumVars}} + {{^@first}} + {{/@first}} + {{name}}_{{{classname}}} {{{classname}}} = "{{{value}}}" + {{/enumVars}} + {{/allowableValues}} +){{/isEnum}}{{^isEnum}}{{#description}} +// {{{description}}}{{/description}} +type {{classname}} struct { +{{#isComposedModel}} + {{#interfaceModels}} + {{classname}} + {{/interfaceModels}} +{{/isComposedModel}} +{{^isComposedModel}} +{{#vars}} +{{^@first}} +{{/@first}} +{{#description}} + // {{{description}}} +{{/description}} + {{name}} {{^isEnum}}{{^isPrimitiveType}}{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{/isPrimitiveType}}{{/isEnum}}{{{datatype}}} `json:"{{baseName}}{{^required}},omitempty{{/required}}"{{#withXml}} xml:"{{baseName}}"{{/withXml}}` +{{/vars}} +{{/isComposedModel}} +}{{/isEnum}}{{/model}}{{/models}} diff --git a/src/main/resources/handlebars/go/model_doc.mustache b/src/main/resources/handlebars/go/model_doc.mustache new file mode 100644 index 0000000000..25537b2c5e --- /dev/null +++ b/src/main/resources/handlebars/go/model_doc.mustache @@ -0,0 +1,11 @@ +{{#models}}{{#model}}# {{classname}} + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{{datatype}}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{^isContainer}}{{^isDateTime}}*{{/isDateTime}}{{/isContainer}}{{{datatype}}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}} +{{/vars}} + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + +{{/model}}{{/models}} diff --git a/src/main/resources/handlebars/go/partial_header.mustache b/src/main/resources/handlebars/go/partial_header.mustache new file mode 100644 index 0000000000..d24dfec369 --- /dev/null +++ b/src/main/resources/handlebars/go/partial_header.mustache @@ -0,0 +1,17 @@ +/* + {{#appName}} + * {{{appName}}} + * + {{/appName}} + {{#appDescription}} + * {{{appDescription}}} + * + {{/appDescription}} + {{#version}} + * API version: {{{version}}} + {{/version}} + {{#infoEmail}} + * Contact: {{{infoEmail}}} + {{/infoEmail}} + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ diff --git a/src/main/resources/handlebars/go/response.mustache b/src/main/resources/handlebars/go/response.mustache new file mode 100644 index 0000000000..a2617ea068 --- /dev/null +++ b/src/main/resources/handlebars/go/response.mustache @@ -0,0 +1,35 @@ +{{>partial_header}} +package {{packageName}} + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/src/main/resources/mustache/nodejs/swagger.mustache b/src/main/resources/handlebars/go/swagger.mustache similarity index 100% rename from src/main/resources/mustache/nodejs/swagger.mustache rename to src/main/resources/handlebars/go/swagger.mustache diff --git a/src/main/resources/handlebars/htmlDocs/index.mustache b/src/main/resources/handlebars/htmlDocs/index.mustache index 3130275287..6d2c20019f 100644 --- a/src/main/resources/handlebars/htmlDocs/index.mustache +++ b/src/main/resources/handlebars/htmlDocs/index.mustache @@ -52,9 +52,9 @@
Up
{{httpMethod}} {{path}}
-
{{summary}} ({{nickname}})
+
{{{summary}}} ({{nickname}})
{{! notes is operation.description. So why rename it and make it super confusing???? }} -
{{notes}}
+
{{{notes}}}
{{#hasPathParams}}

Path parameters

@@ -174,7 +174,50 @@ {{#example}}
example: {{example}}
{{/example}} + {{#vendorExtensions.oneOf-model}} +
oneOf: + {{#vendorExtensions.x-model-names}} + {{this}}    + {{/vendorExtensions.x-model-names}} +
+ {{/vendorExtensions.oneOf-model}} + {{#vendorExtensions.anyOf-model}} +
anyOf: + {{#vendorExtensions.x-model-names}} + {{this}}    + {{/vendorExtensions.x-model-names}} +
+ {{/vendorExtensions.anyOf-model}} + {{#items}} + {{#vendorExtensions.oneOf-model}} +
items oneOf: + {{#vendorExtensions.x-model-names}} + {{this}}    + {{/vendorExtensions.x-model-names}} +
+ {{/vendorExtensions.oneOf-model}} + {{#vendorExtensions.anyOf-model}} +
items anyOf: + {{#vendorExtensions.x-model-names}} + {{this}}    + {{/vendorExtensions.x-model-names}} +
+ {{/vendorExtensions.anyOf-model}} + {{/items}} {{/vars}} + {{#docNoObjects}} + {{#isEnum}} +
Enum:
+ {{#allowableValues}} + {{#values}} +
{{{this}}}
+ {{/values}} + {{/allowableValues}} + {{/isEnum}} + {{#arrayModelType}} + + {{/arrayModelType}} + {{/docNoObjects}} {{/model}} diff --git a/src/main/resources/handlebars/htmlDocs2/index.mustache b/src/main/resources/handlebars/htmlDocs2/index.mustache index 0ba2e970ea..fca92bbe49 100644 --- a/src/main/resources/handlebars/htmlDocs2/index.mustache +++ b/src/main/resources/handlebars/htmlDocs2/index.mustache @@ -114,7 +114,12 @@ var defs = {} {{#models}} {{#model}} - defs.{{name}} = {{{modelJson}}}; + {{#isComposedModel}} + defs["{{name}}"] = {}; + {{/isComposedModel}} + {{^isComposedModel}} + defs["{{name}}"] = {{{modelJson}}}; + {{/isComposedModel}} {{/model}} {{/models}} @@ -206,7 +211,11 @@
-
curl -X {{vendorExtensions.x-codegen-httpMethodUpperCase}}{{#authMethods}}{{#is this 'api-key'}}{{#is this 'key-in-header'}} -H "{{keyParamName}}: [[apiKey]]"{{/is}}{{/is}}{{#is this 'basic'}}{{#has this 'produces'}} -H "Accept: {{#produces}}{{{mediaType}}}{{#hasMore}},{{/hasMore}}{{/produces}}"{{/has}}{{#has this 'consumes'}} -H "Content-Type: {{#consumes}}{{{mediaType}}}{{#hasMore}},{{/hasMore}}{{/consumes}}"{{/has}} -H "Authorization: Basic [[basicHash]]"{{/is}}{{/authMethods}} "{{basePath}}{{path}}{{#hasQueryParams}}?{{#queryParams}}{{^@first}}&{{/@first}}{{baseName}}={{vendorExtensions.x-eg}}{{/queryParams}}{{/hasQueryParams}}"
+
curl -X {{vendorExtensions.x-codegen-httpMethodUpperCase}}{{#authMethods}}\
+{{#isApiKey}}{{#isKeyInHeader}}-H "{{keyParamName}}: [[apiKey]]"{{/isKeyInHeader}}{{/isApiKey}}{{^isBasicBearer}}{{#isBasic}} -H "Authorization: Basic [[basicHash]]"{{/isBasic}}{{/isBasicBearer}}{{#isBearer}} -H "Authorization: Bearer [[accessToken]]"{{/isBearer}}{{/authMethods}}{{#hasProduces}}\
+-H "Accept: {{#produces}}{{{mediaType}}}{{#hasMore}},{{/hasMore}}{{/produces}}"{{/hasProduces}}{{#hasConsumes}}\
+-H "Content-Type: {{#consumes}}{{{mediaType}}}{{#hasMore}},{{/hasMore}}{{/consumes}}"{{/hasConsumes}}\
+"{{basePath}}{{path}}{{#hasQueryParams}}?{{#queryParams}}{{^@first}}&{{/@first}}{{baseName}}={{vendorExtensions.x-eg}}{{/queryParams}}{{/hasQueryParams}}"
{{>sample_java}}
@@ -326,7 +335,7 @@ {{#examples}}
  • - Response Example + Response Example
  • {{/examples}} {{/schema}} @@ -343,7 +352,7 @@
    - - - - - -
    -
    -
    - -
    -
    -
    -
    -

    {{{appName}}}

    -
    -
    -
    - -
    - {{#apiInfo}} - {{#apis}} - {{#operations}} -
    -

    {{baseName}}

    - {{#operation}} - {{#contents}} - {{#-first}} -
    -
    -
    -

    {{nickname}}

    -

    {{summary}}

    -
    -
    -
    -

    -

    {{notes}}

    -

    -
    -
    {{path}}
    -

    -

    Usage and SDK Samples

    -

    - - -
    -
    -
    curl -X {{vendorExtensions.x-codegen-httpMethodUpperCase}}{{#authMethods}}{{#isApiKey}}{{#isKeyInHeader}} -H "{{keyParamName}}: [[apiKey]]"{{/isKeyInHeader}}{{/isApiKey}}{{#isBasic}}{{#hasProduces}} -H "Accept: {{#produces}}{{{mediaType}}}{{#hasMore}},{{/hasMore}}{{/produces}}"{{/hasProduces}}{{#hasConsumes}} -H "Content-Type: {{#consumes}}{{{mediaType}}}{{#hasMore}},{{/hasMore}}{{/consumes}}"{{/hasConsumes}} -H "Authorization: Basic [[basicHash]]"{{/isBasic}}{{/authMethods}} "{{basePath}}{{path}}{{#hasQueryParams}}?{{#queryParams}}{{^-first}}&{{/-first}}{{baseName}}={{vendorExtensions.x-eg}}{{/queryParams}}{{/hasQueryParams}}"
    -
    -
    -
    {{>sample_java}}
    -
    - -
    -
    {{>sample_android}}
    -
    - -
    -
    {{>sample_objc}}
    -
    - -
    -
    {{>sample_js}}
    -
    - - -
    -
    {{>sample_csharp}}
    -
    - -
    -
    {{>sample_php}}
    -
    - -
    -
    {{>sample_perl}}
    -
    - -
    -
    {{>sample_python}}
    -
    -
    - -

    Parameters

    - - {{#hasPathParams}} -
    Path parameters
    - - - - - - {{#pathParams}} - {{>param}} - {{/pathParams}} -
    NameDescription
    - {{/hasPathParams}} - - {{#hasHeaderParams}} -
    Header parameters
    - - - - - - {{#headerParams}} - {{>param}} - {{/headerParams}} -
    NameDescription
    - {{/hasHeaderParams}} - - {{#hasBodyParam}} -
    Body parameters
    - - - - - - {{#bodyParams}} - {{>paramB}} - {{/bodyParams}} -
    NameDescription
    - {{/hasBodyParam}} - - {{#hasFormParams}} -
    Form parameters
    - - - - - - {{#formParams}} - {{>param}} - {{/formParams}} -
    NameDescription
    - {{/hasFormParams}} - - {{#hasQueryParams}} -
    Query parameters
    - - - - - - {{#queryParams}} - {{>param}} - {{/queryParams}} -
    NameDescription
    - {{/hasQueryParams}} - -

    Responses

    - {{#responses}} -

    Status: {{code}} - {{message}}

    - - - -
    - {{#schema}} -
    -
    - -
    - -
    - {{#examples}} -
    -
    {{example}}
    -
    - {{/examples}} - {{/schema}} - {{#hasHeaders}} -
    - - - - - - - - {{#headers}} - - - - - - - {{/headers}} -
    NameTypeFormatDescription
    {{#name}}{{name}}{{/name}}{{#datatype}}{{datatype}}{{/datatype}}{{#dataFormat}}{{dataFormat}}{{/dataFormat}}{{#description}}{{description}}{{/description}}
    -
    - {{/hasHeaders}} -
    - - {{/responses}} -
    -
    -
    - {{/-first}} - {{/contents}} - {{/operation}} -
    - {{/operations}} - {{/apis}} - {{/apiInfo}} -
    - -{{^hideGenerationTimestamp}}
    -
    - Generated {{generatedDate}} -
    -
    -{{/hideGenerationTimestamp}}
    -
    -
    - {{>js_jsonformatter}} - {{>js_jsonschemaview}} - {{>js_json_schema_ref_parser}} - {{>js_json_stringify_safe}} - {{>js_webfontloader}} - - - - diff --git a/src/main/resources/mustache/htmlDocs2/js_bootstrap.mustache b/src/main/resources/mustache/htmlDocs2/js_bootstrap.mustache deleted file mode 100644 index 66770d8b78..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_bootstrap.mustache +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_jquery.mustache b/src/main/resources/mustache/htmlDocs2/js_jquery.mustache deleted file mode 100644 index 7e1f8503ef..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_jquery.mustache +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_json_schema_ref_parser.mustache b/src/main/resources/mustache/htmlDocs2/js_json_schema_ref_parser.mustache deleted file mode 100644 index c78b1ba989..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_json_schema_ref_parser.mustache +++ /dev/null @@ -1,388 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_json_stringify_safe.mustache b/src/main/resources/mustache/htmlDocs2/js_json_stringify_safe.mustache deleted file mode 100644 index 732823d76d..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_json_stringify_safe.mustache +++ /dev/null @@ -1,27 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_jsonformatter.mustache b/src/main/resources/mustache/htmlDocs2/js_jsonformatter.mustache deleted file mode 100644 index 3936dc8514..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_jsonformatter.mustache +++ /dev/null @@ -1,963 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_jsonschemaview.mustache b/src/main/resources/mustache/htmlDocs2/js_jsonschemaview.mustache deleted file mode 100644 index c93e403eaf..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_jsonschemaview.mustache +++ /dev/null @@ -1,313 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_prettify.mustache b/src/main/resources/mustache/htmlDocs2/js_prettify.mustache deleted file mode 100644 index 74e8a7b337..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_prettify.mustache +++ /dev/null @@ -1,32 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/js_webfontloader.mustache b/src/main/resources/mustache/htmlDocs2/js_webfontloader.mustache deleted file mode 100644 index 5c0716cd1f..0000000000 --- a/src/main/resources/mustache/htmlDocs2/js_webfontloader.mustache +++ /dev/null @@ -1,19 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/marked.mustache b/src/main/resources/mustache/htmlDocs2/marked.mustache deleted file mode 100644 index 8117cccfb9..0000000000 --- a/src/main/resources/mustache/htmlDocs2/marked.mustache +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/src/main/resources/mustache/htmlDocs2/param.mustache b/src/main/resources/mustache/htmlDocs2/param.mustache deleted file mode 100644 index 960a046bfd..0000000000 --- a/src/main/resources/mustache/htmlDocs2/param.mustache +++ /dev/null @@ -1,40 +0,0 @@ -{{baseName}}{{^required}}{{/required}}{{#required}}*{{/required}} - - - -
    -
    -
    - - {{dataType}} - - {{#dataFormat}} - - ({{dataFormat}}) - - {{/dataFormat}} - - {{#description}} -
    - {{description}} -
    - {{/description}} -
    - {{#isEnum}} - {{#vendorExtensions.x-eumFormatted}} -
    - - Enum: {{{vendorExtensions.x-eumFormatted}}} - -
    - {{/vendorExtensions.x-eumFormatted}} - {{/isEnum}} - {{#required}} -
    - Required -
    - {{/required}} -
    -
    - - diff --git a/src/main/resources/mustache/htmlDocs2/paramB.mustache b/src/main/resources/mustache/htmlDocs2/paramB.mustache deleted file mode 100644 index 906201885d..0000000000 --- a/src/main/resources/mustache/htmlDocs2/paramB.mustache +++ /dev/null @@ -1,27 +0,0 @@ -{{paramName}} {{^required}}{{/required}}{{#required}}*{{/required}} - - - - -
    - - diff --git a/src/main/resources/mustache/htmlDocs2/sample_android.mustache b/src/main/resources/mustache/htmlDocs2/sample_android.mustache deleted file mode 100644 index a20b0e310e..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_android.mustache +++ /dev/null @@ -1,18 +0,0 @@ -import {{{invokerPackage}}}.api.{{{classname}}}; - -public class {{{classname}}}Example { - - public static void main(String[] args) { - {{{classname}}} apiInstance = new {{{classname}}}(); - {{#parameters}} - {{{dataType}}} {{{paramName}}} = {{{example}}}; // {{{dataType}}} | {{{unescapedDescription}}} - {{/parameters}} - try { - {{#returnType}}{{{returnType}}} result = {{/returnType}}apiInstance.{{{operationId}}}({{#parameters}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - System.out.println(result);{{/returnType}} - } catch (ApiException e) { - System.err.println("Exception when calling {{{classname}}}#{{{operationId}}}"); - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/htmlDocs2/sample_csharp.mustache b/src/main/resources/mustache/htmlDocs2/sample_csharp.mustache deleted file mode 100644 index 53d1f72bac..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_csharp.mustache +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Diagnostics; -using {{packageName}}.Api; -using {{packageName}}.Client; -using {{packageName}}.Model; - -namespace Example -{ - public class {{operationId}}Example - { - public void main() - { - {{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} - // Configure HTTP basic authorization: {{{name}}} - Configuration.Default.Username = "YOUR_USERNAME"; - Configuration.Default.Password = "YOUR_PASSWORD";{{/isBasic}}{{#isApiKey}} - // Configure API key authorization: {{{name}}} - Configuration.Default.ApiKey.Add("{{{keyParamName}}}", "YOUR_API_KEY"); - // Uncomment below to setup prefix (e.g. Bearer) for API key, if needed - // Configuration.Default.ApiKeyPrefix.Add("{{{keyParamName}}}", "Bearer");{{/isApiKey}}{{#isOAuth}} - // Configure OAuth2 access token for authorization: {{{name}}} - Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN";{{/isOAuth}}{{/authMethods}} - {{/hasAuthMethods}} - - var apiInstance = new {{classname}}(); - {{#parameters}} - {{#isPrimitiveType}} - var {{paramName}} = {{{example}}}; // {{{dataType}}} | {{{unescapedDescription}}}{{^required}} (optional) {{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} - {{/isPrimitiveType}} - {{^isPrimitiveType}} - var {{paramName}} = new {{{dataType}}}(); // {{{dataType}}} | {{{unescapedDescription}}}{{^required}} (optional) {{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} - {{/isPrimitiveType}} - {{/parameters}} - - try - { - {{#summary}} - // {{{.}}} - {{/summary}} - {{#returnType}}{{{.}}} result = {{/returnType}}apiInstance.{{{operationId}}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - Debug.WriteLine(result);{{/returnType}} - } - catch (Exception e) - { - Debug.Print("Exception when calling {{classname}}.{{operationId}}: " + e.Message ); - } - } - } -} diff --git a/src/main/resources/mustache/htmlDocs2/sample_java.mustache b/src/main/resources/mustache/htmlDocs2/sample_java.mustache deleted file mode 100644 index fabbd27bac..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_java.mustache +++ /dev/null @@ -1,41 +0,0 @@ -import {{{invokerPackage}}}.*; -import {{{invokerPackage}}}.auth.*; -import {{{invokerPackage}}}.model.*; -import {{{invokerPackage}}}.api.{{{classname}}}; - -import java.io.File; -import java.util.*; - -public class {{{classname}}}Example { - - public static void main(String[] args) { - {{#hasAuthMethods}}ApiClient defaultClient = Configuration.getDefaultApiClient(); - {{#authMethods}}{{#isBasic}} - // Configure HTTP basic authorization: {{{name}}} - HttpBasicAuth {{{name}}} = (HttpBasicAuth) defaultClient.getAuthentication("{{{name}}}"); - {{{name}}}.setUsername("YOUR USERNAME"); - {{{name}}}.setPassword("YOUR PASSWORD");{{/isBasic}}{{#isApiKey}} - // Configure API key authorization: {{{name}}} - ApiKeyAuth {{{name}}} = (ApiKeyAuth) defaultClient.getAuthentication("{{{name}}}"); - {{{name}}}.setApiKey("YOUR API KEY"); - // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) - //{{{name}}}.setApiKeyPrefix("Token");{{/isApiKey}}{{#isOAuth}} - // Configure OAuth2 access token for authorization: {{{name}}} - OAuth {{{name}}} = (OAuth) defaultClient.getAuthentication("{{{name}}}"); - {{{name}}}.setAccessToken("YOUR ACCESS TOKEN");{{/isOAuth}} - {{/authMethods}} - {{/hasAuthMethods}} - - {{{classname}}} apiInstance = new {{{classname}}}(); - {{#parameters}} - {{{dataType}}} {{{paramName}}} = {{{example}}}; // {{{dataType}}} | {{{unescapedDescription}}} - {{/parameters}} - try { - {{#returnType}}{{{returnType}}} result = {{/returnType}}apiInstance.{{{operationId}}}({{#parameters}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - System.out.println(result);{{/returnType}} - } catch (ApiException e) { - System.err.println("Exception when calling {{{classname}}}#{{{operationId}}}"); - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/htmlDocs2/sample_js.mustache b/src/main/resources/mustache/htmlDocs2/sample_js.mustache deleted file mode 100644 index fdfaacfe52..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_js.mustache +++ /dev/null @@ -1,43 +0,0 @@ -var {{{jsModuleName}}} = require('{{{jsProjectName}}}'); -{{#hasAuthMethods}} -var defaultClient = {{{jsModuleName}}}.ApiClient.instance; -{{#authMethods}}{{#isBasic}} -// Configure HTTP basic authorization: {{{name}}} -var {{{name}}} = defaultClient.authentications['{{{name}}}']; -{{{name}}}.username = 'YOUR USERNAME' -{{{name}}}.password = 'YOUR PASSWORD'{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: {{{name}}} -var {{{name}}} = defaultClient.authentications['{{{name}}}']; -{{{name}}}.apiKey = "YOUR API KEY" -// Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) -//{{{name}}}.apiKeyPrefix['{{{keyParamName}}}'] = "Token"{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: {{{name}}} -var {{{name}}} = defaultClient.authentications['{{{name}}}']; -{{{name}}}.accessToken = "YOUR ACCESS TOKEN"{{/isOAuth}} -{{/authMethods}} -{{/hasAuthMethods}} - -var api = new {{{jsModuleName}}}.{{{classname}}}(){{#hasParams}} -{{#vendorExtensions.x-codegen-hasRequiredParams}}{{#parameters}}{{#required}} -var {{{paramName}}} = {{{example}}}; // {{=< >=}}{<&dataType>}<={{ }}=> {{{unescapedDescription}}} -{{/required}}{{/parameters}}{{/vendorExtensions.x-codegen-hasRequiredParams}}{{#hasOptionalParams}} -var opts = { {{#parameters}}{{^required}} - '{{{paramName}}}': {{{example}}}{{#vendorExtensions.x-codegen-hasMoreOptional}},{{/vendorExtensions.x-codegen-hasMoreOptional}} // {{=< >=}}{<&dataType>}<={{ }}=> {{{unescapedDescription}}}{{/required}}{{/parameters}} -};{{/hasOptionalParams}}{{/hasParams}} -{{#usePromises}} -api.{{{operationId}}}({{#parameters}}{{#required}}{{{paramName}}}{{#vendorExtensions.x-codegen-hasMoreRequired}}, {{/vendorExtensions.x-codegen-hasMoreRequired}}{{/required}}{{/parameters}}{{#hasOptionalParams}}{{#vendorExtensions.x-codegen-hasRequiredParams}}, {{/vendorExtensions.x-codegen-hasRequiredParams}}opts{{/hasOptionalParams}}).then(function({{#returnType}}data{{/returnType}}) { - {{#returnType}}console.log('API called successfully. Returned data: ' + data);{{/returnType}}{{^returnType}}console.log('API called successfully.');{{/returnType}} -}, function(error) { - console.error(error); -}); - -{{/usePromises}}{{^usePromises}} -var callback = function(error, data, response) { - if (error) { - console.error(error); - } else { - {{#returnType}}console.log('API called successfully. Returned data: ' + data);{{/returnType}}{{^returnType}}console.log('API called successfully.');{{/returnType}} - } -}; -api.{{{operationId}}}({{#parameters}}{{#required}}{{{paramName}}}{{#vendorExtensions.x-codegen-hasMoreRequired}}, {{/vendorExtensions.x-codegen-hasMoreRequired}}{{/required}}{{/parameters}}{{#hasOptionalParams}}{{#vendorExtensions.x-codegen-hasRequiredParams}}, {{/vendorExtensions.x-codegen-hasRequiredParams}}opts{{/hasOptionalParams}}{{#hasParams}}, {{/hasParams}}callback); -{{/usePromises}} diff --git a/src/main/resources/mustache/htmlDocs2/sample_objc.mustache b/src/main/resources/mustache/htmlDocs2/sample_objc.mustache deleted file mode 100644 index 9671760661..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_objc.mustache +++ /dev/null @@ -1,33 +0,0 @@ -{{#hasAuthMethods}} -{{classPrefix}}Configuration *apiConfig = [{{classPrefix}}Configuration sharedConfig]; -{{#authMethods}}{{#isBasic}}// Configure HTTP basic authorization (authentication scheme: {{{name}}}) -[apiConfig setUsername:@"YOUR_USERNAME"]; -[apiConfig setPassword:@"YOUR_PASSWORD"]; -{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: (authentication scheme: {{{name}}}) -[apiConfig setApiKey:@"YOUR_API_KEY" forApiKeyIdentifier:@"{{{keyParamName}}}"]; -// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//[apiConfig setApiKeyPrefix:@"Bearer" forApiKeyIdentifier:@"{{{keyParamName}}}"]; -{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: (authentication scheme: {{{name}}}) -[apiConfig setAccessToken:@"YOUR_ACCESS_TOKEN"]; -{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} -{{#parameters}}{{{dataType}}} *{{paramName}} = {{{example}}}; // {{{unescapedDescription}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} -{{/parameters}} - -{{classname}} *apiInstance = [[{{classname}} alloc] init]; - -{{#summary}}// {{{.}}} -{{/summary}}[apiInstance {{#vendorExtensions.x-objc-operationId}}{{vendorExtensions.x-objc-operationId}}{{/vendorExtensions.x-objc-operationId}}{{^vendorExtensions.x-objc-operationId}}{{nickname}}{{#hasParams}}With{{vendorExtensions.firstParamAltName}}{{/hasParams}}{{^hasParams}}WithCompletionHandler: {{/hasParams}}{{/vendorExtensions.x-objc-operationId}}{{#parameters}}{{#secondaryParam}} - {{paramName}}{{/secondaryParam}}:{{paramName}}{{/parameters}} - {{#hasParams}}completionHandler: {{/hasParams}}^({{#returnBaseType}}{{{returnType}}} output, {{/returnBaseType}}NSError* error) { -{{#returnType}} - if (output) { - NSLog(@"%@", output); - } -{{/returnType}} - if (error) { - NSLog(@"Error: %@", error); - } - }]; diff --git a/src/main/resources/mustache/htmlDocs2/sample_perl.mustache b/src/main/resources/mustache/htmlDocs2/sample_perl.mustache deleted file mode 100644 index c78403bec4..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_perl.mustache +++ /dev/null @@ -1,26 +0,0 @@ -use Data::Dumper; -use {{{perlModuleName}}}::Configuration; -use {{perlModuleName}}::{{classname}}; -{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} -# Configure HTTP basic authorization: {{{name}}} -${{{perlModuleName}}}::Configuration::username = 'YOUR_USERNAME'; -${{{perlModuleName}}}::Configuration::password = 'YOUR_PASSWORD';{{/isBasic}}{{#isApiKey}} -# Configure API key authorization: {{{name}}} -${{{perlModuleName}}}::Configuration::api_key->{'{{{keyParamName}}}'} = 'YOUR_API_KEY'; -# uncomment below to setup prefix (e.g. Bearer) for API key, if needed -#${{{perlModuleName}}}::Configuration::api_key_prefix->{'{{{keyParamName}}}'} = "Bearer";{{/isApiKey}}{{#isOAuth}} -# Configure OAuth2 access token for authorization: {{{name}}} -${{{perlModuleName}}}::Configuration::access_token = 'YOUR_ACCESS_TOKEN';{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} - -my $api_instance = {{perlModuleName}}::{{classname}}->new(); -{{#parameters}}my ${{paramName}} = {{#isListContainer}}[{{/isListContainer}}{{#isBodyParam}}{{{perlModuleName}}}::Object::{{dataType}}->new(){{/isBodyParam}}{{^isBodyParam}}{{{example}}}{{/isBodyParam}}{{#isListContainer}}]{{/isListContainer}}; # {{{dataType}}} | {{{unescapedDescription}}} -{{/parameters}} - -eval { - {{#returnType}}my $result = {{/returnType}}$api_instance->{{{operationId}}}({{#parameters}}{{paramName}} => ${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - print Dumper($result);{{/returnType}} -}; -if ($@) { - warn "Exception when calling {{classname}}->{{operationId}}: $@\n"; -} \ No newline at end of file diff --git a/src/main/resources/mustache/htmlDocs2/sample_php.mustache b/src/main/resources/mustache/htmlDocs2/sample_php.mustache deleted file mode 100644 index 9a1fe99f81..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_php.mustache +++ /dev/null @@ -1,25 +0,0 @@ -<?php -require_once(__DIR__ . '/vendor/autoload.php'); -{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} -// Configure HTTP basic authorization: {{{name}}} -{{phpInvokerPackage}}\Configuration::getDefaultConfiguration()->setUsername('YOUR_USERNAME'); -{{phpInvokerPackage}}\Configuration::getDefaultConfiguration()->setPassword('YOUR_PASSWORD');{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: {{{name}}} -{{phpInvokerPackage}}\Configuration::getDefaultConfiguration()->setApiKey('{{{keyParamName}}}', 'YOUR_API_KEY'); -// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -// {{phpInvokerPackage}}\Configuration::getDefaultConfiguration()->setApiKeyPrefix('{{{keyParamName}}}', 'Bearer');{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: {{{name}}} -{{phpInvokerPackage}}\Configuration::getDefaultConfiguration()->setAccessToken('YOUR_ACCESS_TOKEN');{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} - -$api_instance = new Swagger\Client\Api\{{classname}}(); -{{#parameters}}${{paramName}} = {{{example}}}; // {{{dataType}}} | {{{unescapedDescription}}} -{{/parameters}} - -try { - {{#returnType}}$result = {{/returnType}}$api_instance->{{{operationId}}}({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - print_r($result);{{/returnType}} -} catch (Exception $e) { - echo 'Exception when calling {{classname}}->{{operationId}}: ', $e->getMessage(), PHP_EOL; -} -?> \ No newline at end of file diff --git a/src/main/resources/mustache/htmlDocs2/sample_python.mustache b/src/main/resources/mustache/htmlDocs2/sample_python.mustache deleted file mode 100644 index dbacc7148b..0000000000 --- a/src/main/resources/mustache/htmlDocs2/sample_python.mustache +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import print_statement -import time -import {{{pythonPackageName}}} -from {{{pythonPackageName}}}.rest import ApiException -from pprint import pprint -{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} -# Configure HTTP basic authorization: {{{name}}} -{{{pythonPackageName}}}.configuration.username = 'YOUR_USERNAME' -{{{pythonPackageName}}}.configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}} -# Configure API key authorization: {{{name}}} -{{{pythonPackageName}}}.configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY' -# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -# {{{pythonPackageName}}}.configuration.api_key_prefix['{{{keyParamName}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}} -# Configure OAuth2 access token for authorization: {{{name}}} -{{{pythonPackageName}}}.configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} - -# create an instance of the API class -api_instance = {{{pythonPackageName}}}.{{{classname}}}() -{{#parameters}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{unescapedDescription}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} -{{/parameters}} - -try: -{{#summary}} # {{{.}}} -{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationIdSnakeCase}}}({{#parameters}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}){{#returnType}} - pprint(api_response){{/returnType}} -except ApiException as e: - print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e) \ No newline at end of file diff --git a/src/main/resources/mustache/htmlDocs2/styles.mustache b/src/main/resources/mustache/htmlDocs2/styles.mustache deleted file mode 100644 index b4e8f9b35f..0000000000 --- a/src/main/resources/mustache/htmlDocs2/styles.mustache +++ /dev/null @@ -1,420 +0,0 @@ -/* ------------------------------------------------------------------------------------------ - * Content - * ------------------------------------------------------------------------------------------ */ - -@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro'); -* { - font-family: 'Source Code Pro', sans-serif; -} -body { - min-width: 980px; -} - -body, p, a, div, th, td { - font-family: "Source Sans Pro", sans-serif; - font-weight: 400; - font-size: 16px; - text-shadow: none !important; -} - -td.code { - font-size: 14px; - font-family: "Source Code Pro", monospace; - font-style: normal; - font-weight: 400; -} - -#content { - padding-top: 16px; - z-Index: -1; - margin-left: 270px; -} - -p { - color: #808080; -} - -h1 { - font-family: "Source Sans Pro Semibold", sans-serif; - font-weight: normal; - font-size: 44px; - line-height: 50px; - margin: 0 0 10px 0; - padding: 0; -} - -h2 { - font-family: "Source Sans Pro", sans-serif; - font-weight: normal; - font-size: 24px; - line-height: 40px; - margin: 0 0 20px 0; - padding: 0; -} - -section { - border-top: 1px solid #ebebeb; - padding: 30px 0; -} - -section h1 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 32px; - line-height: 40px; - padding-bottom: 14px; - margin: 0 0 20px 0; - padding: 0; -} - -article { - padding: 14px 0 30px 0; -} - -article h1 { - font-family: "Source Sans Pro Bold", sans-serif; - font-weight: 600; - font-size: 24px; - line-height: 26px; -} - -article h2 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 18px; - line-height: 24px; - margin: 0 0 10px 0; -} - -article h3 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 16px; - line-height: 18px; - margin: 0 0 10px 0; -} - -article h4 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 14px; - line-height: 16px; - margin: 0 0 8px 0; -} - -table { - border-collapse: collapse; - width: 100%; - margin: 0 0 20px 0; -} - -th { - background-color: #f5f5f5; - text-align: left; - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - padding: 4px 8px; - border: #e0e0e0 1px solid; -} - -td { - vertical-align: top; - padding: 2px 8px; - border: #e0e0e0 1px solid; -} - -#generator .content { - color: #b0b0b0; - border-top: 1px solid #ebebeb; - padding: 10px 0; -} - -.label-optional { - float: right; -} - -.open-left { - right: 0; - left: auto; -} - -/* ------------------------------------------------------------------------------------------ - * apidoc - intro - * ------------------------------------------------------------------------------------------ */ - -#apidoc .apidoc { - border-top: 1px solid #ebebeb; - padding: 30px 0; -} - -#apidoc h1 { - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 32px; - line-height: 40px; - padding-bottom: 14px; - margin: 0 0 20px 0; - padding: 0; -} - -#apidoc h2 { - font-family: "Source Sans Pro Bold", sans-serif; - font-weight: 600; - font-size: 22px; - line-height: 26px; - padding-top: 14px; -} - -/* ------------------------------------------------------------------------------------------ - * pre / code - * ------------------------------------------------------------------------------------------ */ -pre { - background-color: #292b36; - color: #ffffff; - padding: 10px; - border-radius: 6px; - position: relative; - margin: 10px 0 20px 0; -} - -code.language-text { - word-wrap: break-word; -} - -pre.language-json { - overflow: auto; -} - -pre.language-html { - margin: 40px 0 20px 0; -} - -pre.language-html:before { - content: attr(data-type); - position: absolute; - top: -30px; - left: 0; - font-family: "Source Sans Pro", sans-serif; - font-weight: 600; - font-size: 15px; - display: inline-block; - padding: 2px 5px; - border-radius: 6px; - text-transform: uppercase; - background-color: #3387CC; - color: #ffffff; -} - -pre.language-html[data-type="get"]:before { - background-color: green; -} - -pre.language-html[data-type="put"]:before { - background-color: #e5c500; -} - -pre.language-html[data-type="post"]:before { - background-color: #4070ec; -} - -pre.language-html[data-type="delete"]:before { - background-color: #ed0039; -} - -pre.language-api .str { - color: #ffffff; -} - -pre.language-api .pln, -pre.language-api .pun { - color: #65B042; -} - -pre code { - display: block; - font-size: 14px; - font-family: "Source Code Pro", monospace; - font-style: normal; - font-weight: 400; -} - -pre code.sample-request-response-json { - white-space: pre-wrap; - max-height: 500px; - overflow: auto; -} - -/* ------------------------------------------------------------------------------------------ - * Sidenav - * ------------------------------------------------------------------------------------------ */ -.sidenav { - width: 228px; - margin: 0; - padding: 20px; - position: fixed; - top: 0; - left: 0; - bottom: 0; - overflow-x: hidden; - overflow-y: auto; - background-color: #f5f5f5; - z-index: 10; -} - -.sidenav > li > a { - display: block; - width: 192px; - margin: 0; - padding: 2px 11px; - border: 0; - border-left: transparent 4px solid; - border-right: transparent 4px solid; - font-family: "Source Sans Pro", sans-serif; - font-weight: 400; - font-size: 14px; -} - -.sidenav > li.nav-header > a { - padding: 5px 15px; - border: 1px solid #e5e5e5; - width: 190px; - font-family: "Source Sans Pro", sans-serif; - font-weight: 700; - font-size: 16px; - background-color: #4c8eca; - color: #fff; -} - -.sidenav > li.nav-header.active > a { - background-color: #4c8eca; - color: #fff; -} - - -00427D - -.sidenav > .active > a { - position: relative; - z-index: 2; -} - -.sidenav > li > a:hover { - background-color: #ffffff; -} - -.sidenav > li.has-modifications a { - border-right: #60d060 4px solid; -} - -.sidenav > li.is-new a { - border-left: #e5e5e5 4px solid; -} - - - -/* ------------------------------------------------------------------------------------------ - * Tabs - * ------------------------------------------------------------------------------------------ */ -ul.nav-tabs { - margin: 0; -} - -/* ------------------------------------------------------------------------------------------ - * Print - * ------------------------------------------------------------------------------------------ */ - -@media print { - - #sidenav, - #version, - #versions, - section .version, - section .versions { - display: none; - } - - #content { - margin-left: 0; - } - - a { - text-decoration: none; - color: inherit; - } - - a:after { - content: " [" attr(href) "] "; - } - - p { - color: #000000 - } - - pre { - background-color: #ffffff; - color: #000000; - padding: 10px; - border: #808080 1px solid; - border-radius: 6px; - position: relative; - margin: 10px 0 20px 0; - } - -} /* /@media print */ - - -.doc-chapter -{ -display:none; -background-color: #eee; -border-radius: 1px; -padding: 10px; -margin-bottom: 20px; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/*! - * json-schema-view-js - * https://github.com/mohsen1/json-schema-view-js#readme - * Version: 0.4.1 - 2015-11-12T17:19:27.615Z - * License: MIT - */.json-schema-view .toggle-handle:after,.json-schema-view.json-schema-view-dark .toggle-handle:after,json-schema-view .toggle-handle:after,json-schema-view[json-schema-view-dark] .toggle-handle:after{content:"\25BC"}.json-schema-view .title,.json-schema-view.json-schema-view-dark .title,json-schema-view .title,json-schema-view[json-schema-view-dark] .title{font-weight:700;cursor:pointer}.json-schema-view,json-schema-view{font-family:monospace;font-size:0;display:table-cell}.json-schema-view>*,json-schema-view>*{font-size:14px}.json-schema-view .toggle-handle,json-schema-view .toggle-handle{cursor:pointer;margin:auto .3em;font-size:10px;display:inline-block;transform-origin:50% 40%;transition:transform 150ms ease-in}.json-schema-view .toggle-handle,.json-schema-view .toggle-handle:hover,json-schema-view .toggle-handle,json-schema-view .toggle-handle:hover{text-decoration:none;color:#333}.json-schema-view .description,json-schema-view .description{color:gray;font-style:italic} - .pattern { - color: blue; - } - .default { - color: black; - } - .required { - color:black; - } - .json-schema-view .title,.json-schema-view .title:hover,json-schema-view .title,json-schema-view .title:hover{text-decoration:none;color:#333}.json-schema-view .brace,.json-schema-view .bracket,.json-schema-view .title,json-schema-view .brace,json-schema-view .bracket,json-schema-view .title{color:#333}.json-schema-view .property,json-schema-view .property{font-size:0;display:table-row}.json-schema-view .property>*,json-schema-view .property>*{font-size:14px;padding:.2em}.json-schema-view .name,json-schema-view .name{color:#00f;display:table-cell;vertical-align:top}.json-schema-view .type,json-schema-view .type{color:green}.json-schema-view .type-any,json-schema-view .type-any{color:#33f}.json-schema-view .required,json-schema-view .required{color:red}.json-schema-view .inner,json-schema-view .inner{padding-left:18px}.json-schema-view.collapsed .description,.json-schema-view.collapsed .property,json-schema-view.collapsed .description,json-schema-view.collapsed .property{display:none}.json-schema-view.collapsed .closeing.brace,json-schema-view.collapsed .closeing.brace{display:inline-block}.json-schema-view.collapsed .toggle-handle,json-schema-view.collapsed .toggle-handle{transform:rotate(-90deg)}.json-schema-view.json-schema-view-dark,json-schema-view[json-schema-view-dark]{font-family:monospace;font-size:0;display:table-cell}.json-schema-view.json-schema-view-dark>*,json-schema-view[json-schema-view-dark]>*{font-size:14px}.json-schema-view.json-schema-view-dark .toggle-handle,json-schema-view[json-schema-view-dark] .toggle-handle{cursor:pointer;margin:auto .3em;font-size:10px;display:inline-block;transform-origin:50% 40%;transition:transform 150ms ease-in}.json-schema-view.json-schema-view-dark .toggle-handle,.json-schema-view.json-schema-view-dark .toggle-handle:hover,json-schema-view[json-schema-view-dark] .toggle-handle,json-schema-view[json-schema-view-dark] .toggle-handle:hover{text-decoration:none;color:#eee}.json-schema-view.json-schema-view-dark .description,json-schema-view[json-schema-view-dark] .description{color:gray;font-style:italic}.json-schema-view.json-schema-view-dark .title,.json-schema-view.json-schema-view-dark .title:hover,json-schema-view[json-schema-view-dark] .title,json-schema-view[json-schema-view-dark] .title:hover{text-decoration:none;color:#eee}.json-schema-view.json-schema-view-dark .brace,.json-schema-view.json-schema-view-dark .bracket,.json-schema-view.json-schema-view-dark .title,json-schema-view[json-schema-view-dark] .brace,json-schema-view[json-schema-view-dark] .bracket,json-schema-view[json-schema-view-dark] .title{color:#eee}.json-schema-view.json-schema-view-dark .property,json-schema-view[json-schema-view-dark] .property{font-size:0;display:table-row}.json-schema-view.json-schema-view-dark .property>*,json-schema-view[json-schema-view-dark] .property>*{font-size:14px;padding:.2em}.json-schema-view.json-schema-view-dark .name,json-schema-view[json-schema-view-dark] .name{color:#add8e6;display:table-cell;vertical-align:top}.json-schema-view.json-schema-view-dark .type,json-schema-view[json-schema-view-dark] .type{color:#90ee90}.json-schema-view.json-schema-view-dark .type-any,json-schema-view[json-schema-view-dark] .type-any{color:#d4ebf2}.json-schema-view.json-schema-view-dark .required,json-schema-view[json-schema-view-dark] .required{color:#fe0000}.json-schema-view.json-schema-view-dark .inner,json-schema-view[json-schema-view-dark] .inner{padding-left:18px}.json-schema-view.json-schema-view-dark.collapsed .description,.json-schema-view.json-schema-view-dark.collapsed .property,json-schema-view[json-schema-view-dark].collapsed .description,json-schema-view[json-schema-view-dark].collapsed .property{display:none}.json-schema-view.json-schema-view-dark.collapsed .closeing.brace,json-schema-view[json-schema-view-dark].collapsed .closeing.brace{display:inline-block}.json-schema-view.json-schema-view-dark.collapsed .toggle-handle,json-schema-view[json-schema-view-dark].collapsed .toggle-handle{transform:rotate(-90deg)} diff --git a/src/main/resources/mustache/kotlin-client/README.mustache b/src/main/resources/mustache/kotlin-client/README.mustache deleted file mode 100644 index 7a10bab6c1..0000000000 --- a/src/main/resources/mustache/kotlin-client/README.mustache +++ /dev/null @@ -1,85 +0,0 @@ -# {{packageName}} - Kotlin client library for {{appName}} - -## Requires - -* Kotlin 1.1.2 -* Gradle 3.3 - -## Build - -First, create the gradle wrapper script: - -``` -gradle wrapper -``` - -Then, run: - -``` -./gradlew check assemble -``` - -This runs all tests and packages the library. - -## Features/Implementation Notes - -* Supports JSON inputs/outputs, File inputs, and Form inputs. -* Supports collection formats for query parameters: csv, tsv, ssv, pipes. -* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in Swagger definitions. -* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets. - -{{#generateApiDocs}} - -## Documentation for API Endpoints - -All URIs are relative to *{{{basePath}}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} -{{/generateApiDocs}} - -{{#generateModelDocs}} - -## Documentation for Models - -{{#modelPackage}} -{{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) -{{/model}}{{/models}} -{{/modelPackage}} -{{^modelPackage}} -No model defined in this package -{{/modelPackage}} -{{/generateModelDocs}} - -{{! TODO: optional documentation for authorization? }} -## Documentation for Authorization - -{{^authMethods}} -All endpoints do not require authorization. -{{/authMethods}} -{{#authMethods}} -{{#last}} -Authentication schemes defined for the API: -{{/last}} -{{/authMethods}} -{{#authMethods}} - -### {{name}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{keyParamName}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{flow}} -- **Authorization URL**: {{authorizationUrl}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/api.mustache b/src/main/resources/mustache/kotlin-client/api.mustache deleted file mode 100644 index 85d40b6478..0000000000 --- a/src/main/resources/mustache/kotlin-client/api.mustache +++ /dev/null @@ -1,52 +0,0 @@ -{{>licenseInfo}} -package {{apiPackage}} - -{{#imports}}import {{import}} -{{/imports}} - -import {{packageName}}.infrastructure.* -{{#threetenbp}} -import org.threeten.bp.LocalDateTime -{{/threetenbp}} - -{{#operations}} -class {{classname}}(basePath: kotlin.String = "{{{basePath}}}") : ApiClient(basePath) { - - {{#operation}} - {{#contents}} - /** - * {{summary}} - * {{notes}} - {{#parameters}}* @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}}* @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} - */{{#returnType}} - @Suppress("UNCHECKED_CAST"){{/returnType}} - fun {{operationId}}({{#parameters}}{{paramName}}: {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) : {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}} { - val localVariableBody: kotlin.Any? = {{#hasBodyParam}}{{#bodyParams}}{{paramName}}{{/bodyParams}}{{/hasBodyParam}}{{^hasBodyParam}}{{^hasFormParams}}null{{/hasFormParams}}{{#hasFormParams}}mapOf({{#formParams}}"{{{baseName}}}" to "${{paramName}}"{{#hasMore}}, {{/hasMore}}{{/formParams}}){{/hasFormParams}}{{/hasBodyParam}} - val localVariableQuery: MultiValueMap = {{^hasQueryParams}}mapOf(){{/hasQueryParams}}{{#hasQueryParams}}mapOf({{#queryParams}}"{{baseName}}" to {{#isContainer}}toMultiValue({{paramName}}.toList(), "{{collectionFormat}}"){{/isContainer}}{{^isContainer}}listOf("${{paramName}}"){{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/queryParams}}){{/hasQueryParams}} - val localVariableHeaders: kotlin.collections.Map = mapOf({{#hasFormParams}}"Content-Type" to "multipart/form-data"{{/hasFormParams}}{{^hasHeaderParams}}){{/hasHeaderParams}}{{#hasHeaderParams}}{{#hasFormParams}}, {{/hasFormParams}}{{#headerParams}}"{{baseName}}" to {{#isContainer}}{{paramName}}.joinToString(separator = collectionDelimiter("{{collectionFormat}}"){{/isContainer}}{{^isContainer}}{{paramName}}{{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/headerParams}}){{/hasHeaderParams}} - val localVariableConfig = RequestConfig( - RequestMethod.{{httpMethod}}, - "{{path}}"{{#pathParams}}.replace("{"+"{{baseName}}"+"}", "${{paramName}}"){{/pathParams}}, - query = localVariableQuery, - headers = localVariableHeaders - ) - val response = request<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Any?{{/returnType}}>( - localVariableConfig, - localVariableBody - ) - - return when (response.responseType) { - ResponseType.Success -> {{#returnType}}(response as Success<*>).data as {{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}} - ResponseType.Informational -> TODO() - ResponseType.Redirection -> TODO() - ResponseType.ClientError -> throw ClientException((response as ClientError<*>).body as? String ?: "Client error") - ResponseType.ServerError -> throw ServerException((response as ServerError<*>).message ?: "Server error") - else -> throw kotlin.IllegalStateException("Undefined ResponseType.") - } - } - - {{/contents}} - {{/operation}} -} -{{/operations}} diff --git a/src/main/resources/mustache/kotlin-client/api_doc.mustache b/src/main/resources/mustache/kotlin-client/api_doc.mustache deleted file mode 100644 index 05e5e43968..0000000000 --- a/src/main/resources/mustache/kotlin-client/api_doc.mustache +++ /dev/null @@ -1,67 +0,0 @@ -# {{classname}}{{#description}} -{{description}}{{/description}} - -All URIs are relative to *{{basePath}}* - -Method | HTTP request | Description -------------- | ------------- | ------------- -{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}} - -{{#operations}} -{{#operation}} -{{#contents}} - -# **{{operationId}}** -> {{#returnType}}{{returnType}} {{/returnType}}{{operationId}}({{#parameters}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - -{{summary}}{{#notes}} - -{{notes}}{{/notes}} - -### Example -```kotlin -// Import classes: -//import {{{packageName}}}.infrastructure.* -//{{#hasModel}}import {{modelPackage}}.*;{{/hasModel}} - -{{! TODO: Auth method documentation examples}} -val apiInstance = {{{classname}}}() -{{#parameters}} -val {{{paramName}}} : {{{dataType}}} = {{{example}}} // {{{dataType}}} | {{{description}}} -{{/parameters}} -try { - {{#returnType}}val result : {{{returnType}}} = {{/returnType}}apiInstance.{{{operationId}}}({{#parameters}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}){{#returnType}} - println(result){{/returnType}} -} catch (e: ClientException) { - println("4xx response calling {{{classname}}}#{{{operationId}}}") - e.printStackTrace() -} catch (e: ServerException) { - println("5xx response calling {{{classname}}}#{{{operationId}}}") - e.printStackTrace() -} -``` - -### Parameters -{{^parameters}}This endpoint does not need any parameter.{{/parameters}}{{#parameters}}{{#-last}} -Name | Type | Description | Notes -------------- | ------------- | ------------- | -------------{{/-last}}{{/parameters}} -{{#parameters}} **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}{{#generateModelDocs}}[**{{dataType}}**]({{baseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{dataType}}**{{/generateModelDocs}}{{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}} -{{/parameters}} - -### Return type - -{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#generateModelDocs}}[**{{returnType}}**]({{returnBaseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{returnType}}**{{/generateModelDocs}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}} - -### Authorization - -{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}} - -### HTTP request headers - - - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} - - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} - -{{/contents}} -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/kotlin-client/build.gradle.mustache b/src/main/resources/mustache/kotlin-client/build.gradle.mustache deleted file mode 100644 index 7d02942c6d..0000000000 --- a/src/main/resources/mustache/kotlin-client/build.gradle.mustache +++ /dev/null @@ -1,33 +0,0 @@ -group '{{groupId}}' -version '{{artifactVersion}}' - -task wrapper(type: Wrapper) { - gradleVersion = '3.3' - distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" -} - -buildscript { - ext.kotlin_version = '1.1.2' - - repositories { - mavenCentral() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -apply plugin: 'kotlin' - -repositories { - mavenCentral() -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" - compile "com.squareup.moshi:moshi-kotlin:1.5.0" - compile "com.squareup.moshi:moshi-adapters:1.5.0" - compile "com.squareup.okhttp3:okhttp:3.8.0" - compile "org.threeten:threetenbp:1.3.6" - testCompile "io.kotlintest:kotlintest:2.0.2" -} diff --git a/src/main/resources/mustache/kotlin-client/class_doc.mustache b/src/main/resources/mustache/kotlin-client/class_doc.mustache deleted file mode 100644 index 45e1994273..0000000000 --- a/src/main/resources/mustache/kotlin-client/class_doc.mustache +++ /dev/null @@ -1,15 +0,0 @@ -# {{classname}} - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -{{#vars}}**{{name}}** | {{#isEnum}}[**inline**](#{{datatypeWithEnum}}){{/isEnum}}{{^isEnum}}{{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}}{{/isEnum}} | {{description}} | {{^required}} [optional]{{/required}}{{#readOnly}} [readonly]{{/readOnly}} -{{/vars}} -{{#vars}}{{#isEnum}} - -{{!NOTE: see java's resources "pojo_doc.mustache" once enums are fully implemented}} -## Enum: {{baseName}} -Name | Value ----- | -----{{#allowableValues}} -{{name}} | {{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}} -{{/isEnum}}{{/vars}} diff --git a/src/main/resources/mustache/kotlin-client/data_class.mustache b/src/main/resources/mustache/kotlin-client/data_class.mustache deleted file mode 100644 index 66cc4ac838..0000000000 --- a/src/main/resources/mustache/kotlin-client/data_class.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{#hasEnums}} -import com.squareup.moshi.Json -{{/hasEnums}} -/** - * {{{description}}} -{{#vars}} - * @param {{name}} {{{description}}} -{{/vars}} - */ -data class {{classname}} ( -{{#requiredVars}} -{{>data_class_req_var}}{{^-last}}, -{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}}, -{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>data_class_opt_var}}{{^-last}}, -{{/-last}}{{/optionalVars}} -) { -{{#hasEnums}}{{#vars}}{{#isEnum}} - /** - * {{{description}}} - * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} - */ - enum class {{nameInCamelCase}}(val value: {{datatype}}){ - {{#allowableValues}}{{#enumVars}} - @Json(name = {{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} - {{/enumVars}}{{/allowableValues}} - } -{{/isEnum}}{{/vars}}{{/hasEnums}} -} diff --git a/src/main/resources/mustache/kotlin-client/data_class_opt_var.mustache b/src/main/resources/mustache/kotlin-client/data_class_opt_var.mustache deleted file mode 100644 index a88761ea90..0000000000 --- a/src/main/resources/mustache/kotlin-client/data_class_opt_var.mustache +++ /dev/null @@ -1,4 +0,0 @@ -{{#description}} - /* {{{description}}} */ -{{/description}} - val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/data_class_req_var.mustache b/src/main/resources/mustache/kotlin-client/data_class_req_var.mustache deleted file mode 100644 index 8a33a15a18..0000000000 --- a/src/main/resources/mustache/kotlin-client/data_class_req_var.mustache +++ /dev/null @@ -1,4 +0,0 @@ -{{#description}} - /* {{{description}}} */ -{{/description}} - val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/enum_class.mustache b/src/main/resources/mustache/kotlin-client/enum_class.mustache deleted file mode 100644 index 6b85b0fba5..0000000000 --- a/src/main/resources/mustache/kotlin-client/enum_class.mustache +++ /dev/null @@ -1,11 +0,0 @@ -import com.squareup.moshi.Json - -/** -* {{{description}}} -* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} -*/ -enum class {{classname}}(val value: {{dataType}}){ -{{#allowableValues}}{{#enumVars}} - @Json(name = {{{value}}}) {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} -{{/enumVars}}{{/allowableValues}} -} diff --git a/src/main/resources/mustache/kotlin-client/enum_doc.mustache b/src/main/resources/mustache/kotlin-client/enum_doc.mustache deleted file mode 100644 index fcb3d7e61a..0000000000 --- a/src/main/resources/mustache/kotlin-client/enum_doc.mustache +++ /dev/null @@ -1,7 +0,0 @@ -# {{classname}} - -## Enum - -{{#allowableValues}}{{#enumVars}} - * `{{name}}` (value: `{{{value}}}`) -{{/enumVars}}{{/allowableValues}} diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/ApiAbstractions.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/ApiAbstractions.kt.mustache deleted file mode 100644 index 0a42ce534d..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/ApiAbstractions.kt.mustache +++ /dev/null @@ -1,20 +0,0 @@ -package {{packageName}}.infrastructure - -typealias MultiValueMap = Map> - -fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) { - "csv" -> "," - "tsv" -> "\t" - "pipes" -> "|" - "ssv" -> " " - else -> "" -} - -val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" } - -fun toMultiValue(items: List, collectionFormat: String, map: (item: Any?) -> String = defaultMultiValueConverter): List { - return when(collectionFormat) { - "multi" -> items.map(map) - else -> listOf(items.map(map).joinToString(separator = collectionDelimiter(collectionFormat))) - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/ApiClient.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/ApiClient.kt.mustache deleted file mode 100644 index 934cf63524..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/ApiClient.kt.mustache +++ /dev/null @@ -1,133 +0,0 @@ -package {{packageName}}.infrastructure - -import okhttp3.* -import java.io.File - -open class ApiClient(val baseUrl: String) { - companion object { - protected val ContentType = "Content-Type" - protected val Accept = "Accept" - protected val JsonMediaType = "application/json" - protected val FormDataMediaType = "multipart/form-data" - protected val XmlMediaType = "application/xml" - - @JvmStatic - val client by lazy { - builder.build() - } - - @JvmStatic - val builder: OkHttpClient.Builder = OkHttpClient.Builder() - - @JvmStatic - var defaultHeaders: Map by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType)) - - @JvmStatic - val jsonHeaders: Map = mapOf(ContentType to JsonMediaType, Accept to JsonMediaType) - } - - inline protected fun requestBody(content: T, mediaType: String = JsonMediaType): RequestBody { - if(content is File) { - return RequestBody.create( - MediaType.parse(mediaType), content - ) - } else if(mediaType == FormDataMediaType) { - var builder = FormBody.Builder() - // content's type *must* be Map - @Suppress("UNCHECKED_CAST") - (content as Map).forEach { key, value -> - builder = builder.add(key, value) - } - return builder.build() - } else if(mediaType == JsonMediaType) { - return RequestBody.create( - MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) - ) - } else if (mediaType == XmlMediaType) { - TODO("xml not currently supported.") - } - - // TODO: this should be extended with other serializers - TODO("requestBody currently only supports JSON body and File body.") - } - - inline protected fun responseBody(body: ResponseBody?, mediaType: String = JsonMediaType): T? { - if(body == null) return null - return when(mediaType) { - JsonMediaType -> Serializer.moshi.adapter(T::class.java).fromJson(body.source()) - else -> TODO() - } - } - - inline protected fun request(requestConfig: RequestConfig, body : Any? = null): ApiInfrastructureResponse { - val httpUrl = HttpUrl.parse(baseUrl) ?: throw IllegalStateException("baseUrl is invalid.") - - var urlBuilder = httpUrl.newBuilder() - .addPathSegments(requestConfig.path.trimStart('/')) - - requestConfig.query.forEach { query -> - query.value.forEach { queryValue -> - urlBuilder = urlBuilder.addQueryParameter(query.key, queryValue) - } - } - - val url = urlBuilder.build() - val headers = requestConfig.headers + defaultHeaders - - if(headers[ContentType] ?: "" == "") { - throw kotlin.IllegalStateException("Missing Content-Type header. This is required.") - } - - if(headers[Accept] ?: "" == "") { - throw kotlin.IllegalStateException("Missing Accept header. This is required.") - } - - // TODO: support multiple contentType,accept options here. - val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() - val accept = (headers[Accept] as String).substringBefore(";").toLowerCase() - - var request : Request.Builder = when (requestConfig.method) { - RequestMethod.DELETE -> Request.Builder().url(url).delete() - RequestMethod.GET -> Request.Builder().url(url) - RequestMethod.HEAD -> Request.Builder().url(url).head() - RequestMethod.PATCH -> Request.Builder().url(url).patch(requestBody(body, contentType)) - RequestMethod.PUT -> Request.Builder().url(url).put(requestBody(body, contentType)) - RequestMethod.POST -> Request.Builder().url(url).post(requestBody(body, contentType)) - RequestMethod.OPTIONS -> Request.Builder().url(url).method("OPTIONS", null) - } - - headers.forEach { header -> request = request.addHeader(header.key, header.value) } - - val realRequest = request.build() - val response = client.newCall(realRequest).execute() - - // TODO: handle specific mapping types. e.g. Map> - when { - response.isRedirect -> return Redirection( - response.code(), - response.headers().toMultimap() - ) - response.isInformational -> return Informational( - response.message(), - response.code(), - response.headers().toMultimap() - ) - response.isSuccessful -> return Success( - responseBody(response.body(), accept), - response.code(), - response.headers().toMultimap() - ) - response.isClientError -> return ClientError( - response.body()?.string(), - response.code(), - response.headers().toMultimap() - ) - else -> return ServerError( - null, - response.body()?.string(), - response.code(), - response.headers().toMultimap() - ) - } - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/ApiInfrastructureResponse.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/ApiInfrastructureResponse.kt.mustache deleted file mode 100644 index a4e0f0f424..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/ApiInfrastructureResponse.kt.mustache +++ /dev/null @@ -1,40 +0,0 @@ -package {{packageName}}.infrastructure - -enum class ResponseType { - Success, Informational, Redirection, ClientError, ServerError -} - -abstract class ApiInfrastructureResponse(val responseType: ResponseType) { - abstract val statusCode: Int - abstract val headers: Map> -} - -class Success( - val data: T, - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -): ApiInfrastructureResponse(ResponseType.Success) - -class Informational( - val statusText: String, - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -) : ApiInfrastructureResponse(ResponseType.Informational) - -class Redirection( - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -) : ApiInfrastructureResponse(ResponseType.Redirection) - -class ClientError( - val body: Any? = null, - override val statusCode: Int = -1, - override val headers: Map> = mapOf() -) : ApiInfrastructureResponse(ResponseType.ClientError) - -class ServerError( - val message: String? = null, - val body: Any? = null, - override val statusCode: Int = -1, - override val headers: Map> -): ApiInfrastructureResponse(ResponseType.ServerError) \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/ApplicationDelegates.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/ApplicationDelegates.kt.mustache deleted file mode 100644 index bc4e1cd6a1..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/ApplicationDelegates.kt.mustache +++ /dev/null @@ -1,29 +0,0 @@ -package {{packageName}}.infrastructure - -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty - -object ApplicationDelegates { - /** - * Provides a property delegate, allowing the property to be set once and only once. - * - * If unset (no default value), a get on the property will throw [IllegalStateException]. - */ - fun setOnce(defaultValue: T? = null) : ReadWriteProperty = SetOnce(defaultValue) - - private class SetOnce(defaultValue: T? = null) : ReadWriteProperty { - private var isSet = false - private var value: T? = defaultValue - - override fun getValue(thisRef: Any?, property: KProperty<*>): T { - return value ?: throw IllegalStateException("${property.name} not initialized") - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = synchronized(this) { - if (!isSet) { - this.value = value - isSet = true - } - } - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/Errors.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/Errors.kt.mustache deleted file mode 100644 index 1f6d106d94..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/Errors.kt.mustache +++ /dev/null @@ -1,42 +0,0 @@ -@file:Suppress("unused") -package {{packageName}}.infrastructure - -import java.lang.RuntimeException - -open class ClientException : RuntimeException { - - /** - * Constructs an [ClientException] with no detail message. - */ - constructor() : super() - - /** - * Constructs an [ClientException] with the specified detail message. - - * @param message the detail message. - */ - constructor(message: kotlin.String) : super(message) - - companion object { - private const val serialVersionUID: Long = 123L - } -} - -open class ServerException : RuntimeException { - - /** - * Constructs an [ServerException] with no detail message. - */ - constructor() : super() - - /** - * Constructs an [ServerException] with the specified detail message. - - * @param message the detail message. - */ - constructor(message: kotlin.String) : super(message) - - companion object { - private const val serialVersionUID: Long = 456L - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/RequestConfig.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/RequestConfig.kt.mustache deleted file mode 100644 index 58a3d605aa..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/RequestConfig.kt.mustache +++ /dev/null @@ -1,15 +0,0 @@ -package {{packageName}}.infrastructure - -/** - * Defines a config object for a given request. - * NOTE: This object doesn't include 'body' because it - * allows for caching of the constructed object - * for many request definitions. - * NOTE: Headers is a Map because rfc2616 defines - * multi-valued headers as csv-only. - */ -data class RequestConfig( - val method: RequestMethod, - val path: String, - val headers: Map = mapOf(), - val query: Map> = mapOf()) \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/RequestMethod.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/RequestMethod.kt.mustache deleted file mode 100644 index 5774235985..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/RequestMethod.kt.mustache +++ /dev/null @@ -1,8 +0,0 @@ -package {{packageName}}.infrastructure - -/** - * Provides enumerated HTTP verbs - */ -enum class RequestMethod { - GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/ResponseExtensions.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/ResponseExtensions.kt.mustache deleted file mode 100644 index 2e2a3478ff..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/ResponseExtensions.kt.mustache +++ /dev/null @@ -1,23 +0,0 @@ -package {{packageName}}.infrastructure - -import okhttp3.Response - -/** - * Provides an extension to evaluation whether the response is a 1xx code - */ -val Response.isInformational : Boolean get() = this.code() in 100..199 - -/** - * Provides an extension to evaluation whether the response is a 3xx code - */ -val Response.isRedirect : Boolean get() = this.code() in 300..399 - -/** - * Provides an extension to evaluation whether the response is a 4xx code - */ -val Response.isClientError : Boolean get() = this.code() in 400..499 - -/** - * Provides an extension to evaluation whether the response is a 5xx (Standard) through 999 (non-standard) code - */ -val Response.isServerError : Boolean get() = this.code() in 500..999 \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/infrastructure/Serializer.kt.mustache b/src/main/resources/mustache/kotlin-client/infrastructure/Serializer.kt.mustache deleted file mode 100644 index 71cb991ddb..0000000000 --- a/src/main/resources/mustache/kotlin-client/infrastructure/Serializer.kt.mustache +++ /dev/null @@ -1,14 +0,0 @@ -package {{packageName}}.infrastructure - -import com.squareup.moshi.KotlinJsonAdapterFactory -import com.squareup.moshi.Moshi -import com.squareup.moshi.Rfc3339DateJsonAdapter -import java.util.* - -object Serializer { - @JvmStatic - val moshi: Moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe()) - .build() -} diff --git a/src/main/resources/mustache/kotlin-client/licenseInfo.mustache b/src/main/resources/mustache/kotlin-client/licenseInfo.mustache deleted file mode 100644 index aee680977d..0000000000 --- a/src/main/resources/mustache/kotlin-client/licenseInfo.mustache +++ /dev/null @@ -1,11 +0,0 @@ -/** -* {{{appName}}} -* {{{appDescription}}} -* -* {{#version}}OpenAPI spec version: {{{version}}}{{/version}} -* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} -* -* NOTE: This class is auto generated by the swagger code generator program. -* https://github.com/swagger-api/swagger-codegen.git -* Do not edit the class manually. -*/ \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-client/model.mustache b/src/main/resources/mustache/kotlin-client/model.mustache deleted file mode 100644 index f0c5a9bb4a..0000000000 --- a/src/main/resources/mustache/kotlin-client/model.mustache +++ /dev/null @@ -1,14 +0,0 @@ -{{>licenseInfo}} -package {{modelPackage}} - -{{#imports}}import {{import}} -{{/imports}} -{{#threetenbp}} -import org.threeten.bp.LocalDateTime -{{/threetenbp}} - -{{#models}} -{{#model}} -{{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{#isAlias}}typealias {{classname}} = {{dataType}}{{/isAlias}}{{^isAlias}}{{>data_class}}{{/isAlias}}{{/isEnum}} -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/kotlin-client/model_doc.mustache b/src/main/resources/mustache/kotlin-client/model_doc.mustache deleted file mode 100644 index e3b7184211..0000000000 --- a/src/main/resources/mustache/kotlin-client/model_doc.mustache +++ /dev/null @@ -1,3 +0,0 @@ -{{#models}}{{#model}} -{{#isEnum}}{{>enum_doc}}{{/isEnum}}{{^isEnum}}{{>class_doc}}{{/isEnum}} -{{/model}}{{/models}} diff --git a/src/main/resources/mustache/kotlin-client/settings.gradle.mustache b/src/main/resources/mustache/kotlin-client/settings.gradle.mustache deleted file mode 100644 index 448dc07602..0000000000 --- a/src/main/resources/mustache/kotlin-client/settings.gradle.mustache +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = '{{artifactId}}' \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/README.mustache b/src/main/resources/mustache/kotlin-server/README.mustache deleted file mode 100644 index 7b53516d38..0000000000 --- a/src/main/resources/mustache/kotlin-server/README.mustache +++ /dev/null @@ -1,84 +0,0 @@ -# {{packageName}} - Kotlin Server library for {{appName}} - -## Requires - -* Kotlin 1.1.2 -* Gradle 3.3 - -## Build - -First, create the gradle wrapper script: - -``` -gradle wrapper -``` - -Then, run: - -``` -./gradlew check assemble -``` - -This runs all tests and packages the library. - -## Features/Implementation Notes - -* Supports JSON inputs/outputs, File inputs, and Form inputs. -* Supports collection formats for query parameters: csv, tsv, ssv, pipes. -* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in Swagger definitions. - -{{#generateApiDocs}} - -## Documentation for API Endpoints - -All URIs are relative to *{{{basePath}}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} -{{/generateApiDocs}} - -{{#generateModelDocs}} - -## Documentation for Models - -{{#modelPackage}} -{{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) -{{/model}}{{/models}} -{{/modelPackage}} -{{^modelPackage}} -No model defined in this package -{{/modelPackage}} -{{/generateModelDocs}} - -{{! TODO: optional documentation for authorization? }} -## Documentation for Authorization - -{{^authMethods}} -All endpoints do not require authorization. -{{/authMethods}} -{{#authMethods}} -{{#last}} -Authentication schemes defined for the API: -{{/last}} -{{/authMethods}} -{{#authMethods}} - -### {{name}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{keyParamName}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{flow}} -- **Authorization URL**: {{authorizationUrl}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/api_doc.mustache b/src/main/resources/mustache/kotlin-server/api_doc.mustache deleted file mode 100644 index 05e5e43968..0000000000 --- a/src/main/resources/mustache/kotlin-server/api_doc.mustache +++ /dev/null @@ -1,67 +0,0 @@ -# {{classname}}{{#description}} -{{description}}{{/description}} - -All URIs are relative to *{{basePath}}* - -Method | HTTP request | Description -------------- | ------------- | ------------- -{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}} - -{{#operations}} -{{#operation}} -{{#contents}} - -# **{{operationId}}** -> {{#returnType}}{{returnType}} {{/returnType}}{{operationId}}({{#parameters}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - -{{summary}}{{#notes}} - -{{notes}}{{/notes}} - -### Example -```kotlin -// Import classes: -//import {{{packageName}}}.infrastructure.* -//{{#hasModel}}import {{modelPackage}}.*;{{/hasModel}} - -{{! TODO: Auth method documentation examples}} -val apiInstance = {{{classname}}}() -{{#parameters}} -val {{{paramName}}} : {{{dataType}}} = {{{example}}} // {{{dataType}}} | {{{description}}} -{{/parameters}} -try { - {{#returnType}}val result : {{{returnType}}} = {{/returnType}}apiInstance.{{{operationId}}}({{#parameters}}{{{paramName}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}){{#returnType}} - println(result){{/returnType}} -} catch (e: ClientException) { - println("4xx response calling {{{classname}}}#{{{operationId}}}") - e.printStackTrace() -} catch (e: ServerException) { - println("5xx response calling {{{classname}}}#{{{operationId}}}") - e.printStackTrace() -} -``` - -### Parameters -{{^parameters}}This endpoint does not need any parameter.{{/parameters}}{{#parameters}}{{#-last}} -Name | Type | Description | Notes -------------- | ------------- | ------------- | -------------{{/-last}}{{/parameters}} -{{#parameters}} **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}{{#generateModelDocs}}[**{{dataType}}**]({{baseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{dataType}}**{{/generateModelDocs}}{{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}} -{{/parameters}} - -### Return type - -{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#generateModelDocs}}[**{{returnType}}**]({{returnBaseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{returnType}}**{{/generateModelDocs}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}} - -### Authorization - -{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}} - -### HTTP request headers - - - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} - - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} - -{{/contents}} -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/kotlin-server/class_doc.mustache b/src/main/resources/mustache/kotlin-server/class_doc.mustache deleted file mode 100644 index 45e1994273..0000000000 --- a/src/main/resources/mustache/kotlin-server/class_doc.mustache +++ /dev/null @@ -1,15 +0,0 @@ -# {{classname}} - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -{{#vars}}**{{name}}** | {{#isEnum}}[**inline**](#{{datatypeWithEnum}}){{/isEnum}}{{^isEnum}}{{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}}{{/isEnum}} | {{description}} | {{^required}} [optional]{{/required}}{{#readOnly}} [readonly]{{/readOnly}} -{{/vars}} -{{#vars}}{{#isEnum}} - -{{!NOTE: see java's resources "pojo_doc.mustache" once enums are fully implemented}} -## Enum: {{baseName}} -Name | Value ----- | -----{{#allowableValues}} -{{name}} | {{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}} -{{/isEnum}}{{/vars}} diff --git a/src/main/resources/mustache/kotlin-server/data_class.mustache b/src/main/resources/mustache/kotlin-server/data_class.mustache deleted file mode 100644 index 1237ec1f43..0000000000 --- a/src/main/resources/mustache/kotlin-server/data_class.mustache +++ /dev/null @@ -1,25 +0,0 @@ -/** - * {{{description}}} -{{#vars}} - * @param {{name}} {{{description}}} -{{/vars}} - */ -data class {{classname}} ( -{{#requiredVars}} -{{>data_class_req_var}}{{^-last}}, -{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}}, -{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>data_class_opt_var}}{{^-last}}, -{{/-last}}{{/optionalVars}} -) { -{{#hasEnums}}{{#vars}}{{#isEnum}} - /** - * {{{description}}} - * Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} - */ - enum class {{nameInCamelCase}}(val value: {{dataType}}){ - {{#allowableValues}}{{#enumVars}} - {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} - {{/enumVars}}{{/allowableValues}} - } -{{/isEnum}}{{/vars}}{{/hasEnums}} -} diff --git a/src/main/resources/mustache/kotlin-server/data_class_opt_var.mustache b/src/main/resources/mustache/kotlin-server/data_class_opt_var.mustache deleted file mode 100644 index a88761ea90..0000000000 --- a/src/main/resources/mustache/kotlin-server/data_class_opt_var.mustache +++ /dev/null @@ -1,4 +0,0 @@ -{{#description}} - /* {{{description}}} */ -{{/description}} - val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/data_class_req_var.mustache b/src/main/resources/mustache/kotlin-server/data_class_req_var.mustache deleted file mode 100644 index 8a33a15a18..0000000000 --- a/src/main/resources/mustache/kotlin-server/data_class_req_var.mustache +++ /dev/null @@ -1,4 +0,0 @@ -{{#description}} - /* {{{description}}} */ -{{/description}} - val {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/enum_class.mustache b/src/main/resources/mustache/kotlin-server/enum_class.mustache deleted file mode 100644 index 791398b978..0000000000 --- a/src/main/resources/mustache/kotlin-server/enum_class.mustache +++ /dev/null @@ -1,9 +0,0 @@ -/** -* {{{description}}} -* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}} -*/ -enum class {{classname}}(val value: {{dataType}}){ -{{#allowableValues}}{{#enumVars}} - {{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}} -{{/enumVars}}{{/allowableValues}} -} diff --git a/src/main/resources/mustache/kotlin-server/enum_doc.mustache b/src/main/resources/mustache/kotlin-server/enum_doc.mustache deleted file mode 100644 index fcb3d7e61a..0000000000 --- a/src/main/resources/mustache/kotlin-server/enum_doc.mustache +++ /dev/null @@ -1,7 +0,0 @@ -# {{classname}} - -## Enum - -{{#allowableValues}}{{#enumVars}} - * `{{name}}` (value: `{{{value}}}`) -{{/enumVars}}{{/allowableValues}} diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/ApiKeyAuth.kt.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/ApiKeyAuth.kt.mustache deleted file mode 100644 index 39a0ea7a84..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/ApiKeyAuth.kt.mustache +++ /dev/null @@ -1,57 +0,0 @@ -package {{packageName}}.infrastructure - -import io.ktor.application.ApplicationCall -import io.ktor.application.call -import io.ktor.auth.* -import io.ktor.request.ApplicationRequest -import io.ktor.response.respond - - -import io.ktor.application.* -import io.ktor.pipeline.* -import io.ktor.request.* -import io.ktor.response.* -import java.util.* - -enum class ApiKeyLocation(val location: String) { - QUERY("query"), - HEADER("header") -} -data class ApiKey(val value: String): Credential -data class ApiPrincipal(val apiKey: ApiKey?) : Principal -fun ApplicationCall.apiKey(key: String, keyLocation: ApiKeyLocation = ApiKeyLocation.valueOf("header")): ApiKey? = request.apiKey(key, keyLocation) -fun ApplicationRequest.apiKey(key: String, keyLocation: ApiKeyLocation = ApiKeyLocation.valueOf("header")): ApiKey? { - val value: String? = when(keyLocation) { - ApiKeyLocation.QUERY -> this.queryParameters[key] - ApiKeyLocation.HEADER -> this.headers[key] - } - when (value) { - null -> return null - else -> return ApiKey(value) - } -} - -fun AuthenticationPipeline.apiKeyAuth(apiKeyName: String, authLocation: String, validate: suspend (ApiKey) -> ApiPrincipal?) { - intercept(AuthenticationPipeline.RequestAuthentication) { context -> - val credentials = call.request.apiKey(apiKeyName, ApiKeyLocation.values().first { it.location == authLocation }) - val principal = credentials?.let { validate(it) } - - val cause = when { - credentials == null -> AuthenticationFailedCause.NoCredentials - principal == null -> AuthenticationFailedCause.InvalidCredentials - else -> null - } - - if (cause != null) { - context.challenge(apiKeyName, cause) { - // TODO: Verify correct response structure here. - call.respond(UnauthorizedResponse(HttpAuthHeader.Parameterized("API_KEY", mapOf("key" to apiKeyName), HeaderValueEncoding.QUOTED_ALWAYS))) - it.complete() - } - } - if (principal != null) { - context.principal(principal) - } - } -} - diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/AppMain.kt.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/AppMain.kt.mustache deleted file mode 100644 index 53d4a8ba39..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/AppMain.kt.mustache +++ /dev/null @@ -1,74 +0,0 @@ -package {{packageName}} - -import com.codahale.metrics.* -import com.typesafe.config.ConfigFactory -import io.ktor.application.* -import io.ktor.client.HttpClient -import io.ktor.client.engine.apache.Apache -import io.ktor.config.HoconApplicationConfig -import io.ktor.features.* -import io.ktor.gson.GsonConverter -import io.ktor.http.ContentType -import io.ktor.locations.* -import io.ktor.metrics.* -import io.ktor.routing.* -import java.util.concurrent.* -{{#generateApis}} -import {{apiPackage}}.* -{{/generateApis}} - -{{#imports}}import {{import}} -{{/imports}} - -internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader)) - -object HTTP { - val client = HttpClient(Apache) -} - -fun Application.main() { - install(DefaultHeaders) - install(Metrics) { - val reporter = Slf4jReporter.forRegistry(registry) - .outputTo(log) - .convertRatesTo(TimeUnit.SECONDS) - .convertDurationsTo(TimeUnit.MILLISECONDS) - .build() - reporter.start(10, TimeUnit.SECONDS) - } -{{#generateApis}} - install(ContentNegotiation) { - register(ContentType.Application.Json, GsonConverter()) - } - {{#featureAutoHead}} - install(AutoHeadResponse) // see http://ktor.io/features/autoheadresponse.html - {{/featureAutoHead}} - {{#featureConditionalHeaders}} - install(ConditionalHeaders) // see http://ktor.io/features/conditional-headers.html - {{/featureConditionalHeaders}} - {{#featureHSTS}} - install(HSTS, ApplicationHstsConfiguration()) // see http://ktor.io/features/hsts.html - {{/featureHSTS}} - {{#featureCORS}} - install(CORS, ApplicationCORSConfiguration()) // see http://ktor.io/features/cors.html - {{/featureCORS}} - {{#featureCompression}} - install(Compression, ApplicationCompressionConfiguration()) // see http://ktor.io/features/compression.html - {{/featureCompression}} - install(Locations) // see http://ktor.io/features/locations.html - install(Routing) { - {{#apiInfo}} - {{#apis}} - {{#operations}} - {{classname}}() - {{/operations}} - {{/apis}} - {{/apiInfo}} - } -{{/generateApis}} - - environment.monitor.subscribe(ApplicationStopping) - { - HTTP.client.close() - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/Configuration.kt.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/Configuration.kt.mustache deleted file mode 100644 index 1afaa5ff9e..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/Configuration.kt.mustache +++ /dev/null @@ -1,108 +0,0 @@ -package {{packageName}} - -// Use this file to hold package-level internal functions that return receiver object passed to the `install` method. -import io.ktor.auth.OAuthServerSettings -import io.ktor.features.* -import io.ktor.http.* -import java.time.Duration -import java.util.concurrent.Executors - -import {{packageName}}.settings - -{{#featureCORS}} -/** - * Application block for [CORS] configuration. - * - * This file may be excluded in .swagger-codegen-ignore, - * and application specific configuration can be applied in this function. - * - * See http://ktor.io/features/cors.html - */ -internal fun ApplicationCORSConfiguration(): CORS.Configuration.() -> Unit { - return { - // method(HttpMethod.Options) - // header(HttpHeaders.XForwardedProto) - // anyHost() - // host("my-host") - // host("my-host:80") - // host("my-host", subDomains = listOf("www")) - // host("my-host", schemes = listOf("http", "https")) - // allowCredentials = true - // maxAge = Duration.ofDays(1) - } -} -{{/featureCORS}} - -{{#featureHSTS}} -/** - * Application block for [HSTS] configuration. - * - * This file may be excluded in .swagger-codegen-ignore, - * and application specific configuration can be applied in this function. - * - * See http://ktor.io/features/hsts.html - */ -internal fun ApplicationHstsConfiguration(): HSTS.Configuration.() -> Unit { - return { - maxAge = Duration.ofDays(365) - includeSubDomains = true - preload = false - - // You may also apply any custom directives supported by specific user-agent. For example: - // customDirectives.put("redirectHttpToHttps", "false") - } -} -{{/featureHSTS}} - -{{#featureCompression}} -/** - * Application block for [Compression] configuration. - * - * This file may be excluded in .swagger-codegen-ignore, - * and application specific configuration can be applied in this function. - * - * See http://ktor.io/features/compression.html - */ -internal fun ApplicationCompressionConfiguration(): Compression.Configuration.() -> Unit { - return { - gzip { - priority = 1.0 - } - deflate { - priority = 10.0 - minimumSize(1024) // condition - } - } -} -{{/featureCompression}} - -// Defines authentication mechanisms used throughout the application. -val ApplicationAuthProviders: Map = listOf( -{{#authMethods}} - {{#isOAuth}} - OAuthServerSettings.OAuth2ServerSettings( - name = "{{name}}", - authorizeUrl = "{{authorizationUrl}}", - accessTokenUrl = "{{tokenUrl}}", - requestMethod = HttpMethod.Get, - {{! TODO: flow, doesn't seem to be supported yet by ktor }} - clientId = settings.property("auth.oauth.{{name}}.clientId").getString(), - clientSecret = settings.property("auth.oauth.{{name}}.clientSecret").getString(), - defaultScopes = listOf({{#scopes}}"{{scope}}"{{#hasMore}}, {{/hasMore}}{{/scopes}}) - ){{#hasMore}},{{/hasMore}} - {{/isOAuth}} -{{/authMethods}} -// OAuthServerSettings.OAuth2ServerSettings( -// name = "facebook", -// authorizeUrl = "https://graph.facebook.com/oauth/authorize", -// accessTokenUrl = "https://graph.facebook.com/oauth/access_token", -// requestMethod = HttpMethod.Post, -// -// clientId = "settings.property("auth.oauth.facebook.clientId").getString()", -// clientSecret = "settings.property("auth.oauth.facebook.clientSecret").getString()", -// defaultScopes = listOf("public_profile") -// ) -).associateBy { it.name } - -// Provides an application-level fixed thread pool on which to execute coroutines (mainly) -internal val ApplicationExecutors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 4) diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/Dockerfile.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/Dockerfile.mustache deleted file mode 100644 index b9158ac26e..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/Dockerfile.mustache +++ /dev/null @@ -1,7 +0,0 @@ -FROM openjdk:8-jre-alpine - -COPY ./build/libs/{{artifactId}}.jar /root/{{artifactId}}.jar - -WORKDIR /root - -CMD ["java", "-server", "-Xms4g", "-Xmx4g", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "{{artifactId}}.jar"] \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/Paths.kt.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/Paths.kt.mustache deleted file mode 100644 index f2aa869911..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/Paths.kt.mustache +++ /dev/null @@ -1,45 +0,0 @@ -{{>licenseInfo}} -package {{packageName}} - -import io.ktor.application.ApplicationCall -import io.ktor.http.HttpMethod -import io.ktor.locations.* -import io.ktor.pipeline.PipelineContext -import io.ktor.routing.Route -import io.ktor.routing.method -{{#hasModel}}import {{modelPackage}}.*;{{/hasModel}} - -{{#imports}} -import {{import}} -{{/imports}} - -// NOTE: ktor-location@0.9.0 is missing extension for Route.delete. This includes it. -inline fun Route.delete(noinline body: suspend PipelineContext.(T) -> Unit): Route { - return location(T::class) { - method(HttpMethod.Delete) { - handle(body) - } - } -} - -{{#apiInfo}} -object Paths { -{{#apis}} -{{#operations}} - {{#operation}} - {{#contents}} - {{^bodyAllowed}} - /** - * {{summary}} - * {{#unescapedNotes}}{{.}}{{/unescapedNotes}} - {{#parameters}}* @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}}*/ - @Location("{{path}}") class {{operationId}}({{#parameters}}val {{paramName}}: {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - - {{/bodyAllowed}} - {{/contents}} - {{/operation}} -{{/operations}} -{{/apis}} -} -{{/apiInfo}} diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/README.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/README.mustache deleted file mode 100644 index 0b7ca34e4b..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/README.mustache +++ /dev/null @@ -1,101 +0,0 @@ -# {{packageName}} - Kotlin Server library for {{appName}} - -{{#unescapedAppDescription}} -{{.}} -{{/unescapedAppDescription}} - -Generated by Swagger Codegen {{generatorVersion}} ({{generatedDate}}). - -## Requires - -* Kotlin 1.2.10 -* Gradle 4.3 - -## Build - -First, create the gradle wrapper script: - -``` -gradle wrapper -``` - -Then, run: - -``` -./gradlew check assemble -``` - -This runs all tests and packages the library. - -## Running - -The server builds as a fat jar with a main entrypoint. To start the service, run `java -jar ./build/libs/{{artifactId}}.jar`. - -You may also run in docker: - -``` -docker build -t {{artifactId}} . -docker run -p 8080:8080 {{artifactId}} -``` - -## Features/Implementation Notes - -* Supports JSON inputs/outputs, File inputs, and Form inputs (see ktor documentation for more info). -* ~Supports collection formats for query parameters: csv, tsv, ssv, pipes.~ -* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in Swagger definitions. - -{{#generateApiDocs}} - -## Documentation for API Endpoints - -All URIs are relative to *{{{basePath}}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} -{{/generateApiDocs}} - -{{#generateModelDocs}} - -## Documentation for Models - -{{#modelPackage}} -{{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) -{{/model}}{{/models}} -{{/modelPackage}} -{{^modelPackage}} -No model defined in this package -{{/modelPackage}} -{{/generateModelDocs}} - -{{! TODO: optional documentation for authorization? }} -## Documentation for Authorization - -{{^authMethods}} -All endpoints do not require authorization. -{{/authMethods}} -{{#authMethods}} -{{#last}} -Authentication schemes defined for the API: -{{/last}} -{{/authMethods}} -{{#authMethods}} - -### {{name}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{keyParamName}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{flow}} -- **Authorization URL**: {{authorizationUrl}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/_api_body.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/_api_body.mustache deleted file mode 100644 index 9dcf500f49..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/_api_body.mustache +++ /dev/null @@ -1,25 +0,0 @@ -{{#hasAuthMethods}} -{{>libraries/ktor/_principal}} -if (principal == null) { - call.respond(HttpStatusCode.Unauthorized) -} else { - {{#examples}} - {{#-first}} - {{#lambda.indented}}{{>_response}}{{/lambda.indented}} - {{/-first}} - {{/examples}} - {{^examples}} - call.respond(HttpStatusCode.NotImplemented) - {{/examples}} -} -{{/hasAuthMethods}} -{{^hasAuthMethods}} -{{#examples}} -{{#-first}} -{{>libraries/ktor/_response}} -{{/-first}} -{{/examples}} -{{^examples}} -call.respond(HttpStatusCode.NotImplemented) -{{/examples}} -{{/hasAuthMethods}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/_principal.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/_principal.mustache deleted file mode 100644 index d49c5d537f..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/_principal.mustache +++ /dev/null @@ -1,11 +0,0 @@ -{{#authMethods}} -{{#isBasic}} -val principal = call.authentication.principal() -{{/isBasic}} -{{#isApiKey}} -val principal = call.authentication.principal() -{{/isApiKey}} -{{#isOAuth}} -val principal = call.authentication.principal() -{{/isOAuth}} -{{/authMethods}} diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/_response.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/_response.mustache deleted file mode 100644 index fb26fb4a7f..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/_response.mustache +++ /dev/null @@ -1,8 +0,0 @@ -val exampleContentType = "{{{contentType}}}" -val exampleContentString = """{{&example}}""" - -when(exampleContentType) { - "application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java)) - "application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml) - else -> call.respondText(exampleContentString) -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/api.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/api.mustache deleted file mode 100644 index 16b6b9fbf6..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/api.mustache +++ /dev/null @@ -1,114 +0,0 @@ -{{>licenseInfo}} -package {{apiPackage}} - -import com.google.gson.Gson -import io.ktor.application.call -import io.ktor.auth.UserIdPrincipal -import io.ktor.auth.authentication -import io.ktor.auth.basicAuthentication -import io.ktor.auth.oauth -import io.ktor.auth.OAuthAccessTokenResponse -import io.ktor.auth.OAuthServerSettings -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.locations.* -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.* - -import kotlinx.coroutines.experimental.asCoroutineDispatcher - -import {{packageName}}.ApplicationAuthProviders -import {{packageName}}.Paths -import {{packageName}}.ApplicationExecutors -import {{packageName}}.HTTP.client -import {{packageName}}.infrastructure.ApiPrincipal -import {{packageName}}.infrastructure.apiKeyAuth - -// ktor 0.9.x is missing io.ktor.locations.DELETE, this adds it. -// see https://github.com/ktorio/ktor/issues/288 -import {{packageName}}.delete - -{{#imports}}import {{import}} -{{/imports}} - -{{#operations}} -fun Route.{{classname}}() { - val gson = Gson() - val empty = mutableMapOf() -{{#operation}} - {{#bodyAllowed}} - - route("{{path}}") { - {{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}} { - {{#lambda.indented_12}}{{>libraries/ktor/_api_body}}{{/lambda.indented_12}} - } - } - {{/bodyAllowed}} - {{^bodyAllowed}} - - {{! NOTE: Locations can be used on routes without body parameters.}} - {{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}} { it: Paths.{{operationId}} -> - {{#lambda.indented_8}}{{>libraries/ktor/_api_body}}{{/lambda.indented_8}} - } - {{/bodyAllowed}} - {{! THis looks a little weird, but it's completely valid Kotlin code, and simplifies templated route logic above. }} - {{#hasAuthMethods}}.apply { - // TODO: ktor doesn't allow different authentication registrations for endpoints sharing the same path but different methods. - // It could be the authentication block is being abused here. Until this is resolved, swallow duplicate exceptions. - - try { - authentication { - {{#authMethods}} - {{#isBasic}} - basicAuthentication("{{{name}}}") { credentials -> - // TODO: "Apply your basic authentication functionality." - // Accessible in-method via call.principal() - if (credentials.name == "Swagger" && "Codegen" == credentials.password) { - UserIdPrincipal(credentials.name) - } else { - null - } - } - {{/isBasic}} - {{#isApiKey}} - // "Implement API key auth ({{{name}}}) for parameter name '{{{keyParamName}}}'." - apiKeyAuth("{{{keyParamName}}}", {{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInHeader}}"header"{{/isKeyInHeader}}) { - // TODO: "Verify key here , accessible as it.value" - if (it.value == "keyboardcat") { - ApiPrincipal(it) - } else { - null - } - } - {{/isApiKey}} - {{#isOAuth}} - {{#bodyAllowed}} - oauth(client, ApplicationExecutors.asCoroutineDispatcher(), { ApplicationAuthProviders["{{{name}}}"] }, { - // TODO: define a callback url here. - "/" - }) - {{/bodyAllowed}} - {{^bodyAllowed}} - oauthAtLocation(client, ApplicationExecutors.asCoroutineDispatcher(), - providerLookup = { ApplicationAuthProviders["{{{name}}}"] }, - urlProvider = { currentLocation, provider -> - // TODO: define a callback url here. - "/" - }) - {{/bodyAllowed}} - {{/isOAuth}} - {{/authMethods}} - } - } catch(e: io.ktor.application.DuplicateApplicationFeatureException){ - application.environment.log.warn("authentication block for '{{path}}' is duplicated in code. " + - "Generated endpoints may need to be merged under a 'route' entry.") - } - } - {{/hasAuthMethods}} - {{^hasAuthMethods}} - - {{/hasAuthMethods}} -{{/operation}} -} -{{/operations}} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/application.conf.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/application.conf.mustache deleted file mode 100644 index 032be42fa1..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/application.conf.mustache +++ /dev/null @@ -1,27 +0,0 @@ -ktor { - deployment { - environment = development - port = 8080 - autoreload = true - watch = [ {{packageName}} ] - } - - application { - modules = [ {{packageName}}.AppMainKt.main ] - } -} - -# Typesafe config allows multiple ways to provide configuration values without hard-coding them here. -# Please see https://github.com/lightbend/config for details. -auth { - oauth { -{{#authMethods}} -{{#isOAuth}} - {{name}} { - clientId = "" - clientSecret = "" - } -{{/isOAuth}} -{{/authMethods}} - } -} \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/build.gradle.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/build.gradle.mustache deleted file mode 100644 index 7f86e1dc13..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/build.gradle.mustache +++ /dev/null @@ -1,74 +0,0 @@ -group '{{groupId}}' -version '{{artifactVersion}}' - -task wrapper(type: Wrapper) { - gradleVersion = '4.3' - distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" -} - -buildscript { - ext.kotlin_version = '1.2.10' - ext.ktor_version = '0.9.1-alpha-9' - ext.shadow_version = '2.0.2' - - repositories { - mavenCentral() - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.github.jengelman.gradle.plugins:shadow:$shadow_version" - } -} - -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'application' - -mainClassName = "io.ktor.server.netty.DevelopmentEngine" - -// Initialization order with shadow 2.0.1 and Gradle 4.3 is weird. -// See https://github.com/johnrengelman/shadow/issues/336#issuecomment-355402508 -apply plugin: 'com.github.johnrengelman.shadow' - -sourceCompatibility = 1.8 - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -kotlin { - experimental { - coroutines "enable" - } -} - -shadowJar { - baseName = '{{artifactId}}' - classifier = null - version = null -} - -repositories { - mavenCentral() - maven { url "https://dl.bintray.com/kotlin/ktor" } - maven { url "https://dl.bintray.com/kotlin/kotlinx" } -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" - compile "io.ktor:ktor-server-netty:$ktor_version" - compile "io.ktor:ktor-metrics:$ktor_version" - compile "io.ktor:ktor-locations:$ktor_version" - compile "io.ktor:ktor-gson:$ktor_version" - compile "io.ktor:ktor-client-core:$ktor_version" - compile "io.ktor:ktor-client-apache:$ktor_version" - compile "ch.qos.logback:logback-classic:1.2.1" - testCompile group: 'junit', name: 'junit', version: '4.12' -} diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/gradle.properties b/src/main/resources/mustache/kotlin-server/libraries/ktor/gradle.properties deleted file mode 100644 index 5f1ed7bbe0..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -org.gradle.caching=true \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/licenseInfo.mustache b/src/main/resources/mustache/kotlin-server/libraries/ktor/licenseInfo.mustache deleted file mode 100644 index aee680977d..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/licenseInfo.mustache +++ /dev/null @@ -1,11 +0,0 @@ -/** -* {{{appName}}} -* {{{appDescription}}} -* -* {{#version}}OpenAPI spec version: {{{version}}}{{/version}} -* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} -* -* NOTE: This class is auto generated by the swagger code generator program. -* https://github.com/swagger-api/swagger-codegen.git -* Do not edit the class manually. -*/ \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/libraries/ktor/logback.xml b/src/main/resources/mustache/kotlin-server/libraries/ktor/logback.xml deleted file mode 100644 index d0eaba8deb..0000000000 --- a/src/main/resources/mustache/kotlin-server/libraries/ktor/logback.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - - - - diff --git a/src/main/resources/mustache/kotlin-server/licenseInfo.mustache b/src/main/resources/mustache/kotlin-server/licenseInfo.mustache deleted file mode 100644 index aee680977d..0000000000 --- a/src/main/resources/mustache/kotlin-server/licenseInfo.mustache +++ /dev/null @@ -1,11 +0,0 @@ -/** -* {{{appName}}} -* {{{appDescription}}} -* -* {{#version}}OpenAPI spec version: {{{version}}}{{/version}} -* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} -* -* NOTE: This class is auto generated by the swagger code generator program. -* https://github.com/swagger-api/swagger-codegen.git -* Do not edit the class manually. -*/ \ No newline at end of file diff --git a/src/main/resources/mustache/kotlin-server/model.mustache b/src/main/resources/mustache/kotlin-server/model.mustache deleted file mode 100644 index 780dd84b97..0000000000 --- a/src/main/resources/mustache/kotlin-server/model.mustache +++ /dev/null @@ -1,11 +0,0 @@ -{{>licenseInfo}} -package {{modelPackage}} - -{{#imports}}import {{import}} -{{/imports}} - -{{#models}} -{{#model}} -{{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{>data_class}}{{/isEnum}} -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/kotlin-server/model_doc.mustache b/src/main/resources/mustache/kotlin-server/model_doc.mustache deleted file mode 100644 index e3b7184211..0000000000 --- a/src/main/resources/mustache/kotlin-server/model_doc.mustache +++ /dev/null @@ -1,3 +0,0 @@ -{{#models}}{{#model}} -{{#isEnum}}{{>enum_doc}}{{/isEnum}}{{^isEnum}}{{>class_doc}}{{/isEnum}} -{{/model}}{{/models}} diff --git a/src/main/resources/mustache/kotlin-server/settings.gradle.mustache b/src/main/resources/mustache/kotlin-server/settings.gradle.mustache deleted file mode 100644 index 448dc07602..0000000000 --- a/src/main/resources/mustache/kotlin-server/settings.gradle.mustache +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = '{{artifactId}}' \ No newline at end of file diff --git a/src/main/resources/mustache/nodejs/README.mustache b/src/main/resources/mustache/nodejs/README.mustache deleted file mode 100644 index b7df8abcd3..0000000000 --- a/src/main/resources/mustache/nodejs/README.mustache +++ /dev/null @@ -1,27 +0,0 @@ -# Swagger generated server - -## Overview -This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. - -{{^googleCloudFunctions}} -### Running the server -To run the server, run: - -``` -npm start -``` - -To view the Swagger UI interface: - -``` -open http://localhost:{{serverPort}}/docs -``` -{{/googleCloudFunctions}} -{{#googleCloudFunctions}} -### Deploying the function -To deploy this module into Google Cloud Functions, you will have to use Google Cloud SDK commandline tool. - -See [Google Cloud Functions quick start guide](https://cloud.google.com/functions/docs/quickstart) and [Deploying Cloud Functions](https://cloud.google.com/functions/docs/deploying/) for the details. -{{/googleCloudFunctions}} - -This project leverages the mega-awesome [swagger-tools](https://github.com/apigee-127/swagger-tools) middleware which does most all the work. diff --git a/src/main/resources/mustache/nodejs/controller.mustache b/src/main/resources/mustache/nodejs/controller.mustache deleted file mode 100644 index 8566275d65..0000000000 --- a/src/main/resources/mustache/nodejs/controller.mustache +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -var utils = require('../utils/writer.js'); -{{#operations}} -var {{classname}} = require('../{{implFolder}}/{{classname}}Service'); -{{#operation}} -{{#contents}} - -module.exports.{{nickname}} = function {{nickname}} (req, res, next) { - {{#parameters}} - var {{paramName}} = req.swagger.params['{{baseName}}'].value; - {{/parameters}} - {{classname}}.{{nickname}}({{#parameters}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/parameters}}) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; -{{/contents}} -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/nodejs/index-gcf.mustache b/src/main/resources/mustache/nodejs/index-gcf.mustache deleted file mode 100644 index b406ff7f14..0000000000 --- a/src/main/resources/mustache/nodejs/index-gcf.mustache +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -var swaggerTools = require('swagger-tools'); -var jsyaml = require('js-yaml'); -var fs = require('fs'); - -// swaggerRouter configuration -var options = { - controllers: './controllers', - useStubs: false -}; - -// The Swagger document (require it, build it programmatically, fetch it from a URL, ...) -var spec = fs.readFileSync('./api/swagger.yaml', 'utf8'); -var swaggerDoc = jsyaml.safeLoad(spec); - -function toPromise(f, req, res) { - return new Promise(function(resolve, reject) { - f(req, res, function(err) { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); -} - -exports.{{exportedName}} = function(req, res) { - swaggerTools.initializeMiddleware(swaggerDoc, function(middleware) { - var metadata = middleware.swaggerMetadata(); - var validator = middleware.swaggerValidator(); - var router = middleware.swaggerRouter(options); - req.url = swaggerDoc.basePath + req.url; - toPromise(metadata, req, res).then(function() { - return toPromise(validator, req, res); - }).then(function() { - return toPromise(router, req, res); - }).catch(function(err) { - console.error(err); - res.status(res.statusCode || 400).send(err); - }); - }); -}; diff --git a/src/main/resources/mustache/nodejs/index.mustache b/src/main/resources/mustache/nodejs/index.mustache deleted file mode 100644 index ad02896cf1..0000000000 --- a/src/main/resources/mustache/nodejs/index.mustache +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -var fs = require('fs'), - path = require('path'), - http = require('http'); - -var app = require('connect')(); -var oas3Tools = require('oas3-tools'); -var jsyaml = require('js-yaml'); -var serverPort = {{serverPort}}; - -// swaggerRouter configuration -var options = { - swaggerUi: path.join(__dirname, '/swagger.json'), - controllers: path.join(__dirname, './controllers'), - useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode) -}; - -// The Swagger document (require it, build it programmatically, fetch it from a URL, ...) -var spec = fs.readFileSync(path.join(__dirname,'api/swagger.yaml'), 'utf8'); -var swaggerDoc = jsyaml.safeLoad(spec); - -// Initialize the Swagger middleware -oas3Tools.initializeMiddleware(swaggerDoc, function (middleware) { - - // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain - app.use(middleware.swaggerMetadata()); - - // Validate Swagger requests - app.use(middleware.swaggerValidator()); - - // Route validated requests to appropriate controller - app.use(middleware.swaggerRouter(options)); - - // Serve the Swagger documents and Swagger UI - app.use(middleware.swaggerUi()); - - // Start the server - http.createServer(app).listen(serverPort, function () { - console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort); - console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort); - }); - -}); diff --git a/src/main/resources/mustache/nodejs/package.mustache b/src/main/resources/mustache/nodejs/package.mustache deleted file mode 100644 index a80da8e03e..0000000000 --- a/src/main/resources/mustache/nodejs/package.mustache +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "{{projectName}}", - "version": "{{appVersion}}", - "description": "{{{appDescription}}}", - "main": "index.js", - {{^googleCloudFunctions}} - "scripts": { - "prestart": "npm install", - "start": "node index.js" - }, - {{/googleCloudFunctions}} - "keywords": [ - "swagger" - ], - "license": "Unlicense", - "private": true, - "dependencies": { - {{^googleCloudFunctions}} - "connect": "^3.2.0", - {{/googleCloudFunctions}} - "js-yaml": "^3.3.0", - "oas3-tools": "^1.0.1" - } -} diff --git a/src/main/resources/mustache/nodejs/service.mustache b/src/main/resources/mustache/nodejs/service.mustache deleted file mode 100644 index 7aa4d11d5e..0000000000 --- a/src/main/resources/mustache/nodejs/service.mustache +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -{{#operations}} -{{#operation}} -{{#contents}} - -/** - {{#summary}} - * {{{summary}}} - {{/summary}} - {{#notes}} - * {{{notes}}} - {{/notes}} - * -{{#parameters}} - * {{paramName}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}} -{{/parameters}} -{{^returnType}} - * no response value expected for this operation -{{/returnType}} -{{#returnType}} - * returns {{{returnType}}} -{{/returnType}} - **/ -exports.{{{operationId}}} = function({{#parameters}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/parameters}}) { - return new Promise(function(resolve, reject) { - {{#returnType}} - var examples = {}; - {{#examples}} - examples['{{contentType}}'] = {{{example}}}; - {{/examples}} - if (Object.keys(examples).length > 0) { - resolve(examples[Object.keys(examples)[0]]); - } else { - resolve(); - } - {{/returnType}} - {{^returnType}} - resolve(); - {{/returnType}} - }); -} - -{{/contents}} -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/nodejs/writer.mustache b/src/main/resources/mustache/nodejs/writer.mustache deleted file mode 100644 index d79f6e1a52..0000000000 --- a/src/main/resources/mustache/nodejs/writer.mustache +++ /dev/null @@ -1,43 +0,0 @@ -var ResponsePayload = function(code, payload) { - this.code = code; - this.payload = payload; -} - -exports.respondWithCode = function(code, payload) { - return new ResponsePayload(code, payload); -} - -var writeJson = exports.writeJson = function(response, arg1, arg2) { - var code; - var payload; - - if(arg1 && arg1 instanceof ResponsePayload) { - writeJson(response, arg1.payload, arg1.code); - return; - } - - if(arg2 && Number.isInteger(arg2)) { - code = arg2; - } - else { - if(arg1 && Number.isInteger(arg1)) { - code = arg1; - } - } - if(code && arg1) { - payload = arg1; - } - else if(arg1) { - payload = arg1; - } - - if(!code) { - // if no response code given, we default to 200 - code = 200; - } - if(typeof payload === 'object') { - payload = JSON.stringify(payload, null, 2); - } - response.writeHead(code, {'Content-Type': 'application/json'}); - response.end(payload); -} diff --git a/src/main/resources/mustache/php/.php_cs b/src/main/resources/mustache/php/.php_cs deleted file mode 100644 index 6b8e23c818..0000000000 --- a/src/main/resources/mustache/php/.php_cs +++ /dev/null @@ -1,18 +0,0 @@ -level(Symfony\CS\FixerInterface::PSR2_LEVEL) - ->setUsingCache(true) - ->fixers( - [ - 'ordered_use', - 'phpdoc_order', - 'short_array_syntax', - 'strict', - 'strict_param' - ] - ) - ->finder( - Symfony\CS\Finder\DefaultFinder::create() - ->in(__DIR__) - ); diff --git a/src/main/resources/mustache/php/.travis.yml b/src/main/resources/mustache/php/.travis.yml deleted file mode 100644 index d77f3825f6..0000000000 --- a/src/main/resources/mustache/php/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: php -sudo: false -php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - hhvm -before_install: "composer install" -script: "vendor/bin/phpunit" diff --git a/src/main/resources/mustache/php/ApiException.mustache b/src/main/resources/mustache/php/ApiException.mustache deleted file mode 100644 index e8115d2238..0000000000 --- a/src/main/resources/mustache/php/ApiException.mustache +++ /dev/null @@ -1,111 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{invokerPackage}}; - -use \Exception; - -/** - * ApiException Class Doc Comment - * - * @category Class - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -class ApiException extends Exception -{ - - /** - * The HTTP body of the server response either as Json or string. - * - * @var mixed - */ - protected $responseBody; - - /** - * The HTTP header of the server response. - * - * @var string[]|null - */ - protected $responseHeaders; - - /** - * The deserialized response object - * - * @var $responseObject; - */ - protected $responseObject; - - /** - * Constructor - * - * @param string $message Error message - * @param int $code HTTP status code - * @param string[]|null $responseHeaders HTTP response header - * @param mixed $responseBody HTTP decoded body of the server response either as \stdClass or string - */ - public function __construct($message = "", $code = 0, $responseHeaders = [], $responseBody = null) - { - parent::__construct($message, $code); - $this->responseHeaders = $responseHeaders; - $this->responseBody = $responseBody; - } - - /** - * Gets the HTTP response header - * - * @return string[]|null HTTP response header - */ - public function getResponseHeaders() - { - return $this->responseHeaders; - } - - /** - * Gets the HTTP body of the server response either as Json or string - * - * @return mixed HTTP body of the server response either as \stdClass or string - */ - public function getResponseBody() - { - return $this->responseBody; - } - - /** - * Sets the deseralized response object (during deserialization) - * - * @param mixed $obj Deserialized response object - * - * @return void - */ - public function setResponseObject($obj) - { - $this->responseObject = $obj; - } - - /** - * Gets the deseralized response object (during deserialization) - * - * @return mixed the deserialized response object - */ - public function getResponseObject() - { - return $this->responseObject; - } -} diff --git a/src/main/resources/mustache/php/Configuration.mustache b/src/main/resources/mustache/php/Configuration.mustache deleted file mode 100644 index cdbba93a00..0000000000 --- a/src/main/resources/mustache/php/Configuration.mustache +++ /dev/null @@ -1,422 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{invokerPackage}}; - -/** - * Configuration Class Doc Comment - * PHP version 5 - * - * @category Class - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -class Configuration -{ - private static $defaultConfiguration; - - /** - * Associate array to store API key(s) - * - * @var string[] - */ - protected $apiKeys = []; - - /** - * Associate array to store API prefix (e.g. Bearer) - * - * @var string[] - */ - protected $apiKeyPrefixes = []; - - /** - * Access token for OAuth - * - * @var string - */ - protected $accessToken = ''; - - /** - * Username for HTTP basic authentication - * - * @var string - */ - protected $username = ''; - - /** - * Password for HTTP basic authentication - * - * @var string - */ - protected $password = ''; - - /** - * The host - * - * @var string - */ - protected $host = '{{basePath}}'; - - /** - * User agent of the HTTP request, set to "PHP-Swagger" by default - * - * @var string - */ - protected $userAgent = '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{#artifactVersion}}{{{.}}}{{/artifactVersion}}{{^artifactVersion}}1.0.0{{/artifactVersion}}/php{{/httpUserAgent}}'; - - /** - * Debug switch (default set to false) - * - * @var bool - */ - protected $debug = false; - - /** - * Debug file location (log to STDOUT by default) - * - * @var string - */ - protected $debugFile = 'php://output'; - - /** - * Debug file location (log to STDOUT by default) - * - * @var string - */ - protected $tempFolderPath; - - /** - * Constructor - */ - public function __construct() - { - $this->tempFolderPath = sys_get_temp_dir(); - } - - /** - * Sets API key - * - * @param string $apiKeyIdentifier API key identifier (authentication scheme) - * @param string $key API key or token - * - * @return $this - */ - public function setApiKey($apiKeyIdentifier, $key) - { - $this->apiKeys[$apiKeyIdentifier] = $key; - return $this; - } - - /** - * Gets API key - * - * @param string $apiKeyIdentifier API key identifier (authentication scheme) - * - * @return string API key or token - */ - public function getApiKey($apiKeyIdentifier) - { - return isset($this->apiKeys[$apiKeyIdentifier]) ? $this->apiKeys[$apiKeyIdentifier] : null; - } - - /** - * Sets the prefix for API key (e.g. Bearer) - * - * @param string $apiKeyIdentifier API key identifier (authentication scheme) - * @param string $prefix API key prefix, e.g. Bearer - * - * @return $this - */ - public function setApiKeyPrefix($apiKeyIdentifier, $prefix) - { - $this->apiKeyPrefixes[$apiKeyIdentifier] = $prefix; - return $this; - } - - /** - * Gets API key prefix - * - * @param string $apiKeyIdentifier API key identifier (authentication scheme) - * - * @return string - */ - public function getApiKeyPrefix($apiKeyIdentifier) - { - return isset($this->apiKeyPrefixes[$apiKeyIdentifier]) ? $this->apiKeyPrefixes[$apiKeyIdentifier] : null; - } - - /** - * Sets the access token for OAuth - * - * @param string $accessToken Token for OAuth - * - * @return $this - */ - public function setAccessToken($accessToken) - { - $this->accessToken = $accessToken; - return $this; - } - - /** - * Gets the access token for OAuth - * - * @return string Access token for OAuth - */ - public function getAccessToken() - { - return $this->accessToken; - } - - /** - * Sets the username for HTTP basic authentication - * - * @param string $username Username for HTTP basic authentication - * - * @return $this - */ - public function setUsername($username) - { - $this->username = $username; - return $this; - } - - /** - * Gets the username for HTTP basic authentication - * - * @return string Username for HTTP basic authentication - */ - public function getUsername() - { - return $this->username; - } - - /** - * Sets the password for HTTP basic authentication - * - * @param string $password Password for HTTP basic authentication - * - * @return $this - */ - public function setPassword($password) - { - $this->password = $password; - return $this; - } - - /** - * Gets the password for HTTP basic authentication - * - * @return string Password for HTTP basic authentication - */ - public function getPassword() - { - return $this->password; - } - - /** - * Sets the host - * - * @param string $host Host - * - * @return $this - */ - public function setHost($host) - { - $this->host = $host; - return $this; - } - - /** - * Gets the host - * - * @return string Host - */ - public function getHost() - { - return $this->host; - } - - /** - * Sets the user agent of the api client - * - * @param string $userAgent the user agent of the api client - * - * @throws \InvalidArgumentException - * @return $this - */ - public function setUserAgent($userAgent) - { - if (!is_string($userAgent)) { - throw new \InvalidArgumentException('User-agent must be a string.'); - } - - $this->userAgent = $userAgent; - return $this; - } - - /** - * Gets the user agent of the api client - * - * @return string user agent - */ - public function getUserAgent() - { - return $this->userAgent; - } - - /** - * Sets debug flag - * - * @param bool $debug Debug flag - * - * @return $this - */ - public function setDebug($debug) - { - $this->debug = $debug; - return $this; - } - - /** - * Gets the debug flag - * - * @return bool - */ - public function getDebug() - { - return $this->debug; - } - - /** - * Sets the debug file - * - * @param string $debugFile Debug file - * - * @return $this - */ - public function setDebugFile($debugFile) - { - $this->debugFile = $debugFile; - return $this; - } - - /** - * Gets the debug file - * - * @return string - */ - public function getDebugFile() - { - return $this->debugFile; - } - - /** - * Sets the temp folder path - * - * @param string $tempFolderPath Temp folder path - * - * @return $this - */ - public function setTempFolderPath($tempFolderPath) - { - $this->tempFolderPath = $tempFolderPath; - return $this; - } - - /** - * Gets the temp folder path - * - * @return string Temp folder path - */ - public function getTempFolderPath() - { - return $this->tempFolderPath; - } - - /** - * Gets the default configuration instance - * - * @return Configuration - */ - public static function getDefaultConfiguration() - { - if (self::$defaultConfiguration === null) { - self::$defaultConfiguration = new Configuration(); - } - - return self::$defaultConfiguration; - } - - /** - * Sets the detault configuration instance - * - * @param Configuration $config An instance of the Configuration Object - * - * @return void - */ - public static function setDefaultConfiguration(Configuration $config) - { - self::$defaultConfiguration = $config; - } - - /** - * Gets the essential information for debugging - * - * @return string The report for debugging - */ - public static function toDebugReport() - { - $report = 'PHP SDK ({{invokerPackage}}) Debug Report:' . PHP_EOL; - $report .= ' OS: ' . php_uname() . PHP_EOL; - $report .= ' PHP Version: ' . PHP_VERSION . PHP_EOL; - $report .= ' OpenAPI Spec Version: {{version}}' . PHP_EOL; - {{#artifactVersion}} - $report .= ' SDK Package Version: {{artifactVersion}}' . PHP_EOL; - {{/artifactVersion}} - $report .= ' Temp Folder Path: ' . self::getDefaultConfiguration()->getTempFolderPath() . PHP_EOL; - - return $report; - } - - /** - * Get API key (with prefix if set) - * - * @param string $apiKeyIdentifier name of apikey - * - * @return string API key with the prefix - */ - public function getApiKeyWithPrefix($apiKeyIdentifier) - { - $prefix = $this->getApiKeyPrefix($apiKeyIdentifier); - $apiKey = $this->getApiKey($apiKeyIdentifier); - - if ($apiKey === null) { - return null; - } - - if ($prefix === null) { - $keyWithPrefix = $apiKey; - } else { - $keyWithPrefix = $prefix . ' ' . $apiKey; - } - - return $keyWithPrefix; - } -} diff --git a/src/main/resources/mustache/php/HeaderSelector.mustache b/src/main/resources/mustache/php/HeaderSelector.mustache deleted file mode 100644 index 909beb134d..0000000000 --- a/src/main/resources/mustache/php/HeaderSelector.mustache +++ /dev/null @@ -1,100 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{invokerPackage}}; - -use \Exception; - -/** - * ApiException Class Doc Comment - * - * @category Class - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -class HeaderSelector -{ - - /** - * @param string[] $accept - * @param string[] $contentTypes - * @return array - */ - public function selectHeaders($accept, $contentTypes) - { - $headers = []; - - $accept = $this->selectAcceptHeader($accept); - if ($accept !== null) { - $headers['Accept'] = $accept; - } - - $headers['Content-Type'] = $this->selectContentTypeHeader($contentTypes); - return $headers; - } - - /** - * @param string[] $accept - * @return array - */ - public function selectHeadersForMultipart($accept) - { - $headers = $this->selectHeaders($accept, []); - - unset($headers['Content-Type']); - return $headers; - } - - /** - * Return the header 'Accept' based on an array of Accept provided - * - * @param string[] $accept Array of header - * - * @return string Accept (e.g. application/json) - */ - private function selectAcceptHeader($accept) - { - if (count($accept) === 0 || (count($accept) === 1 && $accept[0] === '')) { - return null; - } elseif (preg_grep("/application\/json/i", $accept)) { - return 'application/json'; - } else { - return implode(',', $accept); - } - } - - /** - * Return the content type based on an array of content-type provided - * - * @param string[] $contentType Array fo content-type - * - * @return string Content-Type (e.g. application/json) - */ - private function selectContentTypeHeader($contentType) - { - if (count($contentType) === 0 || (count($contentType) === 1 && $contentType[0] === '')) { - return 'application/json'; - } elseif (preg_grep("/application\/json/i", $contentType)) { - return 'application/json'; - } else { - return implode(',', $contentType); - } - } -} - diff --git a/src/main/resources/mustache/php/ModelInterface.mustache b/src/main/resources/mustache/php/ModelInterface.mustache deleted file mode 100644 index 538bf66169..0000000000 --- a/src/main/resources/mustache/php/ModelInterface.mustache +++ /dev/null @@ -1,86 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{modelPackage}}; - -/** - * Interface abstracting model access. - * - * @package {{modelPackage}} - * @author Swagger Codegen team - */ -interface ModelInterface -{ - /** - * The original name of the model. - * - * @return string - */ - public function getModelName(); - - /** - * Array of property to type mappings. Used for (de)serialization - * - * @return array - */ - public static function swaggerTypes(); - - /** - * Array of property to format mappings. Used for (de)serialization - * - * @return array - */ - public static function swaggerFormats(); - - /** - * Array of attributes where the key is the local name, and the value is the original name - * - * @return array - */ - public static function attributeMap(); - - /** - * Array of attributes to setter functions (for deserialization of responses) - * - * @return array - */ - public static function setters(); - - /** - * Array of attributes to getter functions (for serialization of requests) - * - * @return array - */ - public static function getters(); - - /** - * Show all the invalid properties with reasons. - * - * @return array - */ - public function listInvalidProperties(); - - /** - * Validate all the properties in the model - * return true if all passed - * - * @return bool - */ - public function valid(); -} diff --git a/src/main/resources/mustache/php/ObjectSerializer.mustache b/src/main/resources/mustache/php/ObjectSerializer.mustache deleted file mode 100644 index 460b69b705..0000000000 --- a/src/main/resources/mustache/php/ObjectSerializer.mustache +++ /dev/null @@ -1,307 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{invokerPackage}}; - -/** - * ObjectSerializer Class Doc Comment - * - * @category Class - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -class ObjectSerializer -{ - /** - * Serialize data - * - * @param mixed $data the data to serialize - * @param string $type the SwaggerType of the data - * @param string $format the format of the Swagger type of the data - * - * @return string|object serialized form of $data - */ - public static function sanitizeForSerialization($data, $type = null, $format = null) - { - if (is_scalar($data) || null === $data) { - return $data; - } elseif ($data instanceof \DateTime) { - return ($format === 'date') ? $data->format('Y-m-d') : $data->format(\DateTime::ATOM); - } elseif (is_array($data)) { - foreach ($data as $property => $value) { - $data[$property] = self::sanitizeForSerialization($value); - } - return $data; - } elseif (is_object($data)) { - $values = []; - $formats = $data::swaggerFormats(); - foreach ($data::swaggerTypes() as $property => $swaggerType) { - $getter = $data::getters()[$property]; - $value = $data->$getter(); - if ($value !== null - && !in_array($swaggerType, [{{&primitives}}], true) - && method_exists($swaggerType, 'getAllowableEnumValues') - && !in_array($value, $swaggerType::getAllowableEnumValues())) { - $imploded = implode("', '", $swaggerType::getAllowableEnumValues()); - throw new \InvalidArgumentException("Invalid value for enum '$swaggerType', must be one of: '$imploded'"); - } - if ($value !== null) { - $values[$data::attributeMap()[$property]] = self::sanitizeForSerialization($value, $swaggerType, $formats[$property]); - } - } - return (object)$values; - } else { - return (string)$data; - } - } - - /** - * Sanitize filename by removing path. - * e.g. ../../sun.gif becomes sun.gif - * - * @param string $filename filename to be sanitized - * - * @return string the sanitized filename - */ - public static function sanitizeFilename($filename) - { - if (preg_match("/.*[\/\\\\](.*)$/", $filename, $match)) { - return $match[1]; - } else { - return $filename; - } - } - - /** - * Take value and turn it into a string suitable for inclusion in - * the path, by url-encoding. - * - * @param string $value a string which will be part of the path - * - * @return string the serialized object - */ - public static function toPathValue($value) - { - return rawurlencode(self::toString($value)); - } - - /** - * Take value and turn it into a string suitable for inclusion in - * the query, by imploding comma-separated if it's an object. - * If it's a string, pass through unchanged. It will be url-encoded - * later. - * - * @param string[]|string|\DateTime $object an object to be serialized to a string - * - * @return string the serialized object - */ - public static function toQueryValue($object) - { - if (is_array($object)) { - return implode(',', $object); - } else { - return self::toString($object); - } - } - - /** - * Take value and turn it into a string suitable for inclusion in - * the header. If it's a string, pass through unchanged - * If it's a datetime object, format it in ISO8601 - * - * @param string $value a string which will be part of the header - * - * @return string the header string - */ - public static function toHeaderValue($value) - { - return self::toString($value); - } - - /** - * Take value and turn it into a string suitable for inclusion in - * the http body (form parameter). If it's a string, pass through unchanged - * If it's a datetime object, format it in ISO8601 - * - * @param string|\SplFileObject $value the value of the form parameter - * - * @return string the form string - */ - public static function toFormValue($value) - { - if ($value instanceof \SplFileObject) { - return $value->getRealPath(); - } else { - return self::toString($value); - } - } - - /** - * Take value and turn it into a string suitable for inclusion in - * the parameter. If it's a string, pass through unchanged - * If it's a datetime object, format it in ISO8601 - * - * @param string|\DateTime $value the value of the parameter - * - * @return string the header string - */ - public static function toString($value) - { - if ($value instanceof \DateTime) { // datetime in ISO8601 format - return $value->format(\DateTime::ATOM); - } else { - return $value; - } - } - - /** - * Serialize an array to a string. - * - * @param array $collection collection to serialize to a string - * @param string $collectionFormat the format use for serialization (csv, - * ssv, tsv, pipes, multi) - * @param bool $allowCollectionFormatMulti allow collection format to be a multidimensional array - * - * @return string - */ - public static function serializeCollection(array $collection, $collectionFormat, $allowCollectionFormatMulti = false) - { - if ($allowCollectionFormatMulti && ('multi' === $collectionFormat)) { - // http_build_query() almost does the job for us. We just - // need to fix the result of multidimensional arrays. - return preg_replace('/%5B[0-9]+%5D=/', '=', http_build_query($collection, '', '&')); - } - switch ($collectionFormat) { - case 'pipes': - return implode('|', $collection); - - case 'tsv': - return implode("\t", $collection); - - case 'ssv': - return implode(' ', $collection); - - case 'csv': - // Deliberate fall through. CSV is default format. - default: - return implode(',', $collection); - } - } - - /** - * Deserialize a JSON string into an object - * - * @param mixed $data object or primitive to be deserialized - * @param string $class class name is passed as a string - * @param string[] $httpHeaders HTTP headers - * @param string $discriminator discriminator if polymorphism is used - * - * @return object|array|null an single or an array of $class instances - */ - public static function deserialize($data, $class, $httpHeaders = null) - { - if (null === $data) { - return null; - } elseif (substr($class, 0, 4) === 'map[') { // for associative array e.g. map[string,int] - $inner = substr($class, 4, -1); - $deserialized = []; - if (strrpos($inner, ",") !== false) { - $subClass_array = explode(',', $inner, 2); - $subClass = $subClass_array[1]; - foreach ($data as $key => $value) { - $deserialized[$key] = self::deserialize($value, $subClass, null); - } - } - return $deserialized; - } elseif (strcasecmp(substr($class, -2), '[]') === 0) { - $subClass = substr($class, 0, -2); - $values = []; - foreach ($data as $key => $value) { - $values[] = self::deserialize($value, $subClass, null); - } - return $values; - } elseif ($class === 'object') { - settype($data, 'array'); - return $data; - } elseif ($class === '\DateTime') { - // Some API's return an invalid, empty string as a - // date-time property. DateTime::__construct() will return - // the current time for empty input which is probably not - // what is meant. The invalid empty string is probably to - // be interpreted as a missing field/value. Let's handle - // this graceful. - if (!empty($data)) { - return new \DateTime($data); - } else { - return null; - } - } elseif (in_array($class, [{{&primitives}}], true)) { - settype($data, $class); - return $data; - } elseif ($class === '\SplFileObject') { - /** @var \Psr\Http\Message\StreamInterface $data */ - - // determine file name - if (array_key_exists('Content-Disposition', $httpHeaders) && - preg_match('/inline; filename=[\'"]?([^\'"\s]+)[\'"]?$/i', $httpHeaders['Content-Disposition'], $match)) { - $filename = Configuration::getDefaultConfiguration()->getTempFolderPath() . DIRECTORY_SEPARATOR . self::sanitizeFilename($match[1]); - } else { - $filename = tempnam(Configuration::getDefaultConfiguration()->getTempFolderPath(), ''); - } - - $file = fopen($filename, 'w'); - while ($chunk = $data->read(200)) { - fwrite($file, $chunk); - } - fclose($file); - - return new \SplFileObject($filename, 'r'); - } elseif (method_exists($class, 'getAllowableEnumValues')) { - if (!in_array($data, $class::getAllowableEnumValues())) { - $imploded = implode("', '", $class::getAllowableEnumValues()); - throw new \InvalidArgumentException("Invalid value for enum '$class', must be one of: '$imploded'"); - } - return $data; - } else { - // If a discriminator is defined and points to a valid subclass, use it. - $discriminator = $class::DISCRIMINATOR; - if (!empty($discriminator) && isset($data->{$discriminator}) && is_string($data->{$discriminator})) { - $subclass = '\{{invokerPackage}}\Model\\' . $data->{$discriminator}; - if (is_subclass_of($subclass, $class)) { - $class = $subclass; - } - } - $instance = new $class(); - foreach ($instance::swaggerTypes() as $property => $type) { - $propertySetter = $instance::setters()[$property]; - - if (!isset($propertySetter) || !isset($data->{$instance::attributeMap()[$property]})) { - continue; - } - - $propertyValue = $data->{$instance::attributeMap()[$property]}; - if (isset($propertyValue)) { - $instance->$propertySetter(self::deserialize($propertyValue, $type, null)); - } - } - return $instance; - } - } -} diff --git a/src/main/resources/mustache/php/README.mustache b/src/main/resources/mustache/php/README.mustache deleted file mode 100644 index 8c8fb41055..0000000000 --- a/src/main/resources/mustache/php/README.mustache +++ /dev/null @@ -1,141 +0,0 @@ -# {{packagePath}} -{{#appDescription}} -{{{appDescription}}} -{{/appDescription}} - -This PHP package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: - -- API version: {{appVersion}} -{{#artifactVersion}} -- Package version: {{artifactVersion}} -{{/artifactVersion}} -{{^hideGenerationTimestamp}} -- Build date: {{generatedDate}} -{{/hideGenerationTimestamp}} -- Build package: {{generatorClass}} -{{#infoUrl}} -For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) -{{/infoUrl}} - -## Requirements - -PHP 5.5 and later - -## Installation & Usage -### Composer - -To install the bindings via [Composer](http://getcomposer.org/), add the following to `composer.json`: - -``` -{ - "repositories": [ - { - "type": "git", - "url": "https://github.com/{{#composerVendorName}}{{.}}{{/composerVendorName}}{{^composerVendorName}}{{gitUserId}}{{/composerVendorName}}/{{#composerProjectName}}{{.}}{{/composerProjectName}}{{^composerProjectName}}{{gitRepoId}}{{/composerProjectName}}.git" - } - ], - "require": { - "{{#composerVendorName}}{{.}}{{/composerVendorName}}{{^composerVendorName}}{{gitUserId}}{{/composerVendorName}}/{{#composerProjectName}}{{.}}{{/composerProjectName}}{{^composerProjectName}}{{gitRepoId}}{{/composerProjectName}}": "*@dev" - } -} -``` - -Then run `composer install` - -### Manual Installation - -Download the files and include `autoload.php`: - -```php - require_once('/path/to/{{packagePath}}/vendor/autoload.php'); -``` - -## Tests - -To run the unit tests: - -``` -composer install -./vendor/bin/phpunit -``` - -## Getting Started - -Please follow the [installation procedure](#installation--usage) and then run the following: - -```php -setUsername('YOUR_USERNAME') - ->setPassword('YOUR_PASSWORD');{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: {{{name}}} -$config = {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKey('{{{keyParamName}}}', 'YOUR_API_KEY'); -// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -// $config = {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKeyPrefix('{{{keyParamName}}}', 'Bearer');{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: {{{name}}} -$config = {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setAccessToken('YOUR_ACCESS_TOKEN');{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} - -$apiInstance = new {{invokerPackage}}\Api\{{classname}}( - // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`. - // This is optional, `GuzzleHttp\Client` will be used as default. - new GuzzleHttp\Client(){{#hasAuthMethods}}, - $config{{/hasAuthMethods}} -); -{{#parameters}}${{paramName}} = {{{example}}}; // {{{dataType}}} | {{{description}}} -{{/parameters}} - -try { - {{#returnType}}$result = {{/returnType}}$apiInstance->{{{operationId}}}({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - print_r($result);{{/returnType}} -} catch (Exception $e) { - echo 'Exception when calling {{classname}}->{{operationId}}: ', $e->getMessage(), PHP_EOL; -} -{{/-first}}{{/contents}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}} -?> -``` - -## Documentation for API Endpoints - -All URIs are relative to *{{basePath}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}/{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} - -## Documentation For Models - -{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}/{{{classname}}}.md) -{{/model}}{{/models}} - -## Documentation For Authorization - -{{^authMethods}} All endpoints do not require authorization. -{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}} -{{#authMethods}}## {{{name}}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{{keyParamName}}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{{flow}}} -- **Authorization URL**: {{{authorizationUrl}}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - **{{{scope}}}**: {{{description}}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} - -## Author - -{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} -{{/hasMore}}{{/apis}}{{/apiInfo}} - diff --git a/src/main/resources/mustache/php/api.mustache b/src/main/resources/mustache/php/api.mustache deleted file mode 100644 index 3087239331..0000000000 --- a/src/main/resources/mustache/php/api.mustache +++ /dev/null @@ -1,518 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{apiPackage}}; - -use GuzzleHttp\Client; -use GuzzleHttp\ClientInterface; -use GuzzleHttp\Exception\RequestException; -use GuzzleHttp\Psr7\MultipartStream; -use GuzzleHttp\Psr7\Request; -use GuzzleHttp\RequestOptions; -use {{invokerPackage}}\ApiException; -use {{invokerPackage}}\Configuration; -use {{invokerPackage}}\HeaderSelector; -use {{invokerPackage}}\ObjectSerializer; - -/** - * {{classname}} Class Doc Comment - * - * @category Class - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -{{#operations}}class {{classname}} -{ - /** - * @var ClientInterface - */ - protected $client; - - /** - * @var Configuration - */ - protected $config; - - /** - * @var HeaderSelector - */ - protected $headerSelector; - - /** - * @param ClientInterface $client - * @param Configuration $config - * @param HeaderSelector $selector - */ - public function __construct( - ClientInterface $client = null, - Configuration $config = null, - HeaderSelector $selector = null - ) { - $this->client = $client ?: new Client(); - $this->config = $config ?: new Configuration(); - $this->headerSelector = $selector ?: new HeaderSelector(); - } - - /** - * @return Configuration - */ - public function getConfig() - { - return $this->config; - } - -{{#operation}} -{{#contents}} - /** - * Operation {{{operationId}}} -{{#summary}} - * - * {{{summary}}} -{{/summary}} - * -{{#description}} - * {{.}} - * -{{/description}} -{{#parameters}} - * @param {{dataType}} ${{paramName}}{{#description}} {{description}}{{/description}}{{^description}} {{paramName}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/parameters}} - * - * @throws \{{invokerPackage}}\ApiException on non-2xx response - * @throws \InvalidArgumentException - * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} - */ - public function {{operationId}}({{#parameters}}${{paramName}}{{^required}} = {{#defaultValue}}'{{{.}}}'{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - { - {{#returnType}}list($response) = {{/returnType}}$this->{{operationId}}WithHttpInfo({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - return $response;{{/returnType}} - } - - /** - * Operation {{{operationId}}}WithHttpInfo -{{#summary}} - * - * {{{summary}}} -{{/summary}} - * -{{#description}} - * {{.}} - * -{{/description}} -{{#parameters}} - * @param {{dataType}} ${{paramName}}{{#description}} {{description}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/parameters}} - * - * @throws \{{invokerPackage}}\ApiException on non-2xx response - * @throws \InvalidArgumentException - * @return array of {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}null{{/returnType}}, HTTP status code, HTTP response headers (array of strings) - */ - public function {{operationId}}WithHttpInfo({{#parameters}}${{paramName}}{{^required}} = {{#defaultValue}}'{{{.}}}'{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - { - $returnType = '{{returnType}}'; - $request = $this->{{operationId}}Request({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); - - try { - $options = $this->createHttpClientOption(); - try { - $response = $this->client->send($request, $options); - } catch (RequestException $e) { - throw new ApiException( - "[{$e->getCode()}] {$e->getMessage()}", - $e->getCode(), - $e->getResponse() ? $e->getResponse()->getHeaders() : null, - $e->getResponse() ? $e->getResponse()->getBody()->getContents() : null - ); - } - - $statusCode = $response->getStatusCode(); - - if ($statusCode < 200 || $statusCode > 299) { - throw new ApiException( - sprintf( - '[%d] Error connecting to the API (%s)', - $statusCode, - $request->getUri() - ), - $statusCode, - $response->getHeaders(), - $response->getBody() - ); - } - - {{#returnType}} - $responseBody = $response->getBody(); - if ($returnType === '\SplFileObject') { - $content = $responseBody; //stream goes to serializer - } else { - $content = $responseBody->getContents(); - if ($returnType !== 'string') { - $content = json_decode($content); - } - } - - return [ - ObjectSerializer::deserialize($content, $returnType, []), - $response->getStatusCode(), - $response->getHeaders() - ]; - {{/returnType}} - {{^returnType}} - return [null, $statusCode, $response->getHeaders()]; - {{/returnType}} - - } catch (ApiException $e) { - switch ($e->getCode()) { - {{#responses}} - {{#dataType}} - {{^isWildcard}}case {{code}}:{{/isWildcard}}{{#isWildcard}}default:{{/isWildcard}} - $data = ObjectSerializer::deserialize( - $e->getResponseBody(), - '{{dataType}}', - $e->getResponseHeaders() - ); - $e->setResponseObject($data); - break; - {{/dataType}} - {{/responses}} - } - throw $e; - } - } - - /** - * Operation {{{operationId}}}Async - * - * {{{summary}}} - * -{{#description}} - * {{.}} - * -{{/description}} -{{#parameters}} - * @param {{dataType}} ${{paramName}}{{#description}} {{description}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/parameters}} - * - * @throws \InvalidArgumentException - * @return \GuzzleHttp\Promise\PromiseInterface - */ - public function {{operationId}}Async({{#parameters}}${{paramName}}{{^required}} = {{#defaultValue}}'{{{.}}}'{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - { - return $this->{{operationId}}AsyncWithHttpInfo({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - ->then( - function ($response) { - return $response[0]; - } - ); - } - - /** - * Operation {{{operationId}}}AsyncWithHttpInfo - * - * {{{summary}}} - * -{{#description}} - * {{.}} - * -{{/description}} -{{#parameters}} - * @param {{dataType}} ${{paramName}}{{#description}} {{description}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/parameters}} - * - * @throws \InvalidArgumentException - * @return \GuzzleHttp\Promise\PromiseInterface - */ - public function {{operationId}}AsyncWithHttpInfo({{#parameters}}${{paramName}}{{^required}} = {{#defaultValue}}'{{{.}}}'{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - { - $returnType = '{{returnType}}'; - $request = $this->{{operationId}}Request({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}); - - return $this->client - ->sendAsync($request, $this->createHttpClientOption()) - ->then( - function ($response) use ($returnType) { - {{#returnType}} - $responseBody = $response->getBody(); - if ($returnType === '\SplFileObject') { - $content = $responseBody; //stream goes to serializer - } else { - $content = $responseBody->getContents(); - if ($returnType !== 'string') { - $content = json_decode($content); - } - } - - return [ - ObjectSerializer::deserialize($content, $returnType, []), - $response->getStatusCode(), - $response->getHeaders() - ]; - {{/returnType}} - {{^returnType}} - return [null, $response->getStatusCode(), $response->getHeaders()]; - {{/returnType}} - }, - function ($exception) { - $response = $exception->getResponse(); - $statusCode = $response->getStatusCode(); - throw new ApiException( - sprintf( - '[%d] Error connecting to the API (%s)', - $statusCode, - $exception->getRequest()->getUri() - ), - $statusCode, - $response->getHeaders(), - $response->getBody() - ); - } - ); - } - - /** - * Create request for operation '{{{operationId}}}' - * -{{#parameters}} - * @param {{dataType}} ${{paramName}}{{#description}} {{description}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/parameters}} - * - * @throws \InvalidArgumentException - * @return \GuzzleHttp\Psr7\Request - */ - protected function {{operationId}}Request({{#parameters}}${{paramName}}{{^required}} = {{#defaultValue}}'{{{.}}}'{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - { - {{#parameters}} - {{#required}} - // verify the required parameter '{{paramName}}' is set - if (${{paramName}} === null || (is_array(${{paramName}}) && count(${{paramName}}) === 0)) { - throw new \InvalidArgumentException( - 'Missing the required parameter ${{paramName}} when calling {{operationId}}' - ); - } - {{/required}} - {{#hasValidation}} - {{#maxLength}} - if ({{^required}}${{paramName}} !== null && {{/required}}strlen(${{paramName}}) > {{maxLength}}) { - throw new \InvalidArgumentException('invalid length for "${{paramName}}" when calling {{classname}}.{{operationId}}, must be smaller than or equal to {{maxLength}}.'); - } - {{/maxLength}} - {{#minLength}} - if ({{^required}}${{paramName}} !== null && {{/required}}strlen(${{paramName}}) < {{minLength}}) { - throw new \InvalidArgumentException('invalid length for "${{paramName}}" when calling {{classname}}.{{operationId}}, must be bigger than or equal to {{minLength}}.'); - } - {{/minLength}} - {{#maximum}} - if ({{^required}}${{paramName}} !== null && {{/required}}${{paramName}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}) { - throw new \InvalidArgumentException('invalid value for "${{paramName}}" when calling {{classname}}.{{operationId}}, must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{maximum}}.'); - } - {{/maximum}} - {{#minimum}} - if ({{^required}}${{paramName}} !== null && {{/required}}${{paramName}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}) { - throw new \InvalidArgumentException('invalid value for "${{paramName}}" when calling {{classname}}.{{operationId}}, must be bigger than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{minimum}}.'); - } - {{/minimum}} - {{#pattern}} - if ({{^required}}${{paramName}} !== null && {{/required}}!preg_match("{{{pattern}}}", ${{paramName}})) { - throw new \InvalidArgumentException("invalid value for \"{{paramName}}\" when calling {{classname}}.{{operationId}}, must conform to the pattern {{{pattern}}}."); - } - {{/pattern}} - {{#maxItems}} - if ({{^required}}${{paramName}} !== null && {{/required}}count(${{paramName}}) > {{maxItems}}) { - throw new \InvalidArgumentException('invalid value for "${{paramName}}" when calling {{classname}}.{{operationId}}, number of items must be less than or equal to {{maxItems}}.'); - } - {{/maxItems}} - {{#minItems}} - if ({{^required}}${{paramName}} !== null && {{/required}}count(${{paramName}}) < {{minItems}}) { - throw new \InvalidArgumentException('invalid value for "${{paramName}}" when calling {{classname}}.{{operationId}}, number of items must be greater than or equal to {{minItems}}.'); - } - {{/minItems}} - - {{/hasValidation}} - {{/parameters}} - - $resourcePath = '{{{path}}}'; - $formParams = []; - $queryParams = []; - $headerParams = []; - $httpBody = ''; - $multipart = false; - - {{#queryParams}} - // query params - {{#collectionFormat}} - if (is_array(${{paramName}})) { - ${{paramName}} = ObjectSerializer::serializeCollection(${{paramName}}, '{{collectionFormat}}', true); - } - {{/collectionFormat}} - if (${{paramName}} !== null) { - $queryParams['{{baseName}}'] = ObjectSerializer::toQueryValue(${{paramName}}); - } - {{/queryParams}} - {{#headerParams}} - // header params - {{#collectionFormat}} - if (is_array(${{paramName}})) { - ${{paramName}} = ObjectSerializer::serializeCollection(${{paramName}}, '{{collectionFormat}}'); - } - {{/collectionFormat}} - if (${{paramName}} !== null) { - $headerParams['{{baseName}}'] = ObjectSerializer::toHeaderValue(${{paramName}}); - } - {{/headerParams}} - - {{#pathParams}} - // path params - {{#collectionFormat}} - if (is_array(${{paramName}})) { - ${{paramName}} = ObjectSerializer::serializeCollection(${{paramName}}, '{{collectionFormat}}'); - } - {{/collectionFormat}} - if (${{paramName}} !== null) { - $resourcePath = str_replace( - '{' . '{{baseName}}' . '}', - ObjectSerializer::toPathValue(${{paramName}}), - $resourcePath - ); - } - {{/pathParams}} - - {{#formParams}} - // form params - if (${{paramName}} !== null) { - {{#isFile}} - $multipart = true; - $formParams['{{baseName}}'] = \GuzzleHttp\Psr7\try_fopen(ObjectSerializer::toFormValue(${{paramName}}), 'rb'); - {{/isFile}} - {{^isFile}} - $formParams['{{baseName}}'] = ObjectSerializer::toFormValue(${{paramName}}); - {{/isFile}} - } - {{/formParams}} - // body params - $_tempBody = null; - {{#bodyParams}} - if (isset(${{paramName}})) { - $_tempBody = ${{paramName}}; - } - {{/bodyParams}} - - if ($multipart) { - $headers = $this->headerSelector->selectHeadersForMultipart( - [{{#produces}}'{{{mediaType}}}'{{#hasMore}}, {{/hasMore}}{{/produces}}] - ); - } else { - $headers = $this->headerSelector->selectHeaders( - [{{#produces}}'{{{mediaType}}}'{{#hasMore}}, {{/hasMore}}{{/produces}}], - [{{#consumes}}'{{{mediaType}}}'{{#hasMore}}, {{/hasMore}}{{/consumes}}] - ); - } - - // for model (json/xml) - if (isset($_tempBody)) { - // $_tempBody is the method argument, if present - $httpBody = $_tempBody; - // \stdClass has no __toString(), so we should encode it manually - if ($httpBody instanceof \stdClass && $headers['Content-Type'] === 'application/json') { - $httpBody = \GuzzleHttp\json_encode($httpBody); - } - } elseif (count($formParams) > 0) { - if ($multipart) { - $multipartContents = []; - foreach ($formParams as $formParamName => $formParamValue) { - $multipartContents[] = [ - 'name' => $formParamName, - 'contents' => $formParamValue - ]; - } - // for HTTP post (form) - $httpBody = new MultipartStream($multipartContents); - - } elseif ($headers['Content-Type'] === 'application/json') { - $httpBody = \GuzzleHttp\json_encode($formParams); - - } else { - // for HTTP post (form) - $httpBody = \GuzzleHttp\Psr7\build_query($formParams); - } - } - - {{#authMethods}} - {{#isApiKey}} - // this endpoint requires API key authentication - $apiKey = $this->config->getApiKeyWithPrefix('{{keyParamName}}'); - if ($apiKey !== null) { - {{#isKeyInHeader}}$headers['{{keyParamName}}'] = $apiKey;{{/isKeyInHeader}}{{#isKeyInQuery}}$queryParams['{{keyParamName}}'] = $apiKey;{{/isKeyInQuery}} - } - {{/isApiKey}} - {{#isBasic}} - // this endpoint requires HTTP basic authentication - if ($this->config->getUsername() !== null || $this->config->getPassword() !== null) { - $headers['Authorization'] = 'Basic ' . base64_encode($this->config->getUsername() . ":" . $this->config->getPassword()); - } - {{/isBasic}} - {{#isOAuth}} - // this endpoint requires OAuth (access token) - if ($this->config->getAccessToken() !== null) { - $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken(); - } - {{/isOAuth}} - {{/authMethods}} - - $defaultHeaders = []; - if ($this->config->getUserAgent()) { - $defaultHeaders['User-Agent'] = $this->config->getUserAgent(); - } - - $headers = array_merge( - $defaultHeaders, - $headerParams, - $headers - ); - - $query = \GuzzleHttp\Psr7\build_query($queryParams); - return new Request( - '{{httpMethod}}', - $this->config->getHost() . $resourcePath . ($query ? "?{$query}" : ''), - $headers, - $httpBody - ); - } - - {{/contents}} - {{/operation}} - /** - * Create http client option - * - * @throws \RuntimeException on file opening failure - * @return array of http client options - */ - protected function createHttpClientOption() - { - $options = []; - if ($this->config->getDebug()) { - $options[RequestOptions::DEBUG] = fopen($this->config->getDebugFile(), 'a'); - if (!$options[RequestOptions::DEBUG]) { - throw new \RuntimeException('Failed to open the debug file: ' . $this->config->getDebugFile()); - } - } - - return $options; - } -} -{{/operations}} diff --git a/src/main/resources/mustache/php/api_doc.mustache b/src/main/resources/mustache/php/api_doc.mustache deleted file mode 100644 index aa949603db..0000000000 --- a/src/main/resources/mustache/php/api_doc.mustache +++ /dev/null @@ -1,81 +0,0 @@ -# {{invokerPackage}}\{{classname}}{{#description}} -{{description}}{{/description}} - -All URIs are relative to *{{basePath}}* - -Method | HTTP request | Description -------------- | ------------- | ------------- -{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}} - -{{#operations}} -{{#operation}} -{{#contents}} -# **{{{operationId}}}** -> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) - -{{{summary}}}{{#notes}} - -{{{notes}}}{{/notes}} - -### Example -```php -setUsername('YOUR_USERNAME') - ->setPassword('YOUR_PASSWORD'); -{{/isBasic}}{{#isApiKey}} -// Configure API key authorization: {{{name}}} -$config = {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKey('{{{keyParamName}}}', 'YOUR_API_KEY'); -// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -// $config = {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setApiKeyPrefix('{{{keyParamName}}}', 'Bearer');{{/isApiKey}}{{#isOAuth}} -// Configure OAuth2 access token for authorization: {{{name}}} -$config = {{{invokerPackage}}}\Configuration::getDefaultConfiguration()->setAccessToken('YOUR_ACCESS_TOKEN');{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} - -$apiInstance = new {{invokerPackage}}\Api\{{classname}}( - // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`. - // This is optional, `GuzzleHttp\Client` will be used as default. - new GuzzleHttp\Client(){{#hasAuthMethods}}, - $config{{/hasAuthMethods}} -); -{{#parameters}}${{paramName}} = {{{example}}}; // {{{dataType}}} | {{{description}}} -{{/parameters}} - -try { - {{#returnType}}$result = {{/returnType}}$apiInstance->{{{operationId}}}({{#parameters}}${{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});{{#returnType}} - print_r($result);{{/returnType}} -} catch (Exception $e) { - echo 'Exception when calling {{classname}}->{{operationId}}: ', $e->getMessage(), PHP_EOL; -} -?> -``` - -### Parameters -{{^parameters}}This endpoint does not need any parameter.{{/parameters}}{{#parameters}}{{#-last}} -Name | Type | Description | Notes -------------- | ------------- | ------------- | -------------{{/-last}}{{/parameters}} -{{#parameters}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isFile}}[**{{dataType}}**](../Model/{{baseType}}.md){{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}} -{{/parameters}} - -### Return type - -{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**](../Model/{{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}} - -### Authorization - -{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}} - -### HTTP request headers - - - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} - - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} - -[[Back to top]](#) [[Back to API list]](../../README.md#documentation-for-api-endpoints) [[Back to Model list]](../../README.md#documentation-for-models) [[Back to README]](../../README.md) - -{{/contents}} -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/php/api_test.mustache b/src/main/resources/mustache/php/api_test.mustache deleted file mode 100644 index af93752482..0000000000 --- a/src/main/resources/mustache/php/api_test.mustache +++ /dev/null @@ -1,76 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Please update the test case below to test the endpoint. - */ - -namespace {{invokerPackage}}; - -use \{{invokerPackage}}\Configuration; -use \{{invokerPackage}}\ApiException; -use \{{invokerPackage}}\ObjectSerializer; - -/** - * {{classname}}Test Class Doc Comment - * - * @category Class - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -{{#operations}}class {{classname}}Test extends \PHPUnit_Framework_TestCase -{ - - /** - * Setup before running any test cases - */ - public static function setUpBeforeClass() - { - } - - /** - * Setup before running each test case - */ - public function setUp() - { - } - - /** - * Clean up after running each test case - */ - public function tearDown() - { - } - - /** - * Clean up after running all test cases - */ - public static function tearDownAfterClass() - { - } - {{#operation}} - - /** - * Test case for {{{operationId}}} - * - * {{{summary}}}. - * - */ - public function test{{vendorExtensions.x-testOperationId}}() - { - } - {{/operation}} -} -{{/operations}} diff --git a/src/main/resources/mustache/php/composer.mustache b/src/main/resources/mustache/php/composer.mustache deleted file mode 100644 index 0a7732fafe..0000000000 --- a/src/main/resources/mustache/php/composer.mustache +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "{{#composerVendorName}}{{.}}{{/composerVendorName}}{{^composerVendorName}}{{gitUserId}}{{/composerVendorName}}/{{#composerProjectName}}{{.}}{{/composerProjectName}}{{^composerProjectName}}{{gitRepoId}}{{/composerProjectName}}", - {{#artifactVersion}} - "version": "{{artifactVersion}}", - {{/artifactVersion}} - "description": "{{description}}", - "keywords": [ - "swagger", - "php", - "sdk", - "api" - ], - "homepage": "http://swagger.io", - "license": "proprietary", - "authors": [ - { - "name": "Swagger and contributors", - "homepage": "https://github.com/swagger-api/swagger-codegen" - } - ], - "require": { - "php": ">=5.5", - "ext-curl": "*", - "ext-json": "*", - "ext-mbstring": "*", - "guzzlehttp/guzzle": "^6.2" - }, - "require-dev": { - "phpunit/phpunit": "^4.8", - "squizlabs/php_codesniffer": "~2.6", - "friendsofphp/php-cs-fixer": "~1.12" - }, - "autoload": { - "psr-4": { "{{escapedInvokerPackage}}\\" : "{{srcBasePath}}/" } - }, - "autoload-dev": { - "psr-4": { "{{escapedInvokerPackage}}\\" : "{{testBasePath}}/" } - } -} diff --git a/src/main/resources/mustache/php/git_push.sh.mustache b/src/main/resources/mustache/php/git_push.sh.mustache deleted file mode 100755 index f65b794638..0000000000 --- a/src/main/resources/mustache/php/git_push.sh.mustache +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="{{{gitUserId}}}" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="{{{gitRepoId}}}" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="{{{releaseNote}}}" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/src/main/resources/mustache/php/model.mustache b/src/main/resources/mustache/php/model.mustache deleted file mode 100644 index 9382cfa5ff..0000000000 --- a/src/main/resources/mustache/php/model.mustache +++ /dev/null @@ -1,43 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Do not edit the class manually. - */ - -namespace {{modelPackage}}; -{{^isEnum}} -{{^parentSchema}} - -use \ArrayAccess; -{{/parentSchema}} -{{/isEnum}} -use \{{invokerPackage}}\ObjectSerializer; - -/** - * {{classname}} Class Doc Comment - * - * @category Class -{{#description}} - * @description {{description}} -{{/description}} - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -{{#isEnum}}{{>model_enum}}{{/isEnum}}{{^isEnum}}{{>model_generic}}{{/isEnum}} -{{/model}}{{/models}} diff --git a/src/main/resources/mustache/php/model_doc.mustache b/src/main/resources/mustache/php/model_doc.mustache deleted file mode 100644 index 569550df37..0000000000 --- a/src/main/resources/mustache/php/model_doc.mustache +++ /dev/null @@ -1,11 +0,0 @@ -{{#models}}{{#model}}# {{classname}} - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}} -{{/vars}} - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - -{{/model}}{{/models}} diff --git a/src/main/resources/mustache/php/model_enum.mustache b/src/main/resources/mustache/php/model_enum.mustache deleted file mode 100644 index 5e6b2aea21..0000000000 --- a/src/main/resources/mustache/php/model_enum.mustache +++ /dev/null @@ -1,19 +0,0 @@ -class {{classname}} -{ - /** - * Possible values of this enum - */ - {{#allowableValues}}{{#enumVars}}const {{{name}}} = {{{value}}}; - {{/enumVars}}{{/allowableValues}} - /** - * Gets allowable values of the enum - * @return string[] - */ - public static function getAllowableEnumValues() - { - return [ - {{#allowableValues}}{{#enumVars}}self::{{{name}}},{{^-last}} - {{/-last}}{{/enumVars}}{{/allowableValues}} - ]; - } -} diff --git a/src/main/resources/mustache/php/model_generic.mustache b/src/main/resources/mustache/php/model_generic.mustache deleted file mode 100644 index fe64626058..0000000000 --- a/src/main/resources/mustache/php/model_generic.mustache +++ /dev/null @@ -1,418 +0,0 @@ -class {{classname}} {{#parentSchema}}extends {{{parent}}} {{/parentSchema}}{{^parentSchema}}implements ModelInterface, ArrayAccess{{/parentSchema}} -{ - const DISCRIMINATOR = {{#discriminator}}'{{discriminator.propertyName}}'{{/discriminator}}{{^discriminator}}null{{/discriminator}}; - - /** - * The original name of the model. - * - * @var string - */ - protected static $swaggerModelName = '{{name}}'; - - /** - * Array of property to type mappings. Used for (de)serialization - * - * @var string[] - */ - protected static $swaggerTypes = [ - {{#vars}}'{{name}}' => '{{{datatype}}}'{{#hasMore}}, - {{/hasMore}}{{/vars}} - ]; - - /** - * Array of property to format mappings. Used for (de)serialization - * - * @var string[] - */ - protected static $swaggerFormats = [ - {{#vars}}'{{name}}' => {{#dataFormat}}'{{{dataFormat}}}'{{/dataFormat}}{{^dataFormat}}null{{/dataFormat}}{{#hasMore}}, - {{/hasMore}}{{/vars}} - ]; - - /** - * Array of property to type mappings. Used for (de)serialization - * - * @return array - */ - public static function swaggerTypes() - { - return self::$swaggerTypes{{#parentSchema}} + parent::swaggerTypes(){{/parentSchema}}; - } - - /** - * Array of property to format mappings. Used for (de)serialization - * - * @return array - */ - public static function swaggerFormats() - { - return self::$swaggerFormats{{#parentSchema}} + parent::swaggerFormats(){{/parentSchema}}; - } - - /** - * Array of attributes where the key is the local name, - * and the value is the original name - * - * @var string[] - */ - protected static $attributeMap = [ - {{#vars}}'{{name}}' => '{{baseName}}'{{#hasMore}}, - {{/hasMore}}{{/vars}} - ]; - - /** - * Array of attributes to setter functions (for deserialization of responses) - * - * @var string[] - */ - protected static $setters = [ - {{#vars}}'{{name}}' => '{{setter}}'{{#hasMore}}, - {{/hasMore}}{{/vars}} - ]; - - /** - * Array of attributes to getter functions (for serialization of requests) - * - * @var string[] - */ - protected static $getters = [ - {{#vars}}'{{name}}' => '{{getter}}'{{#hasMore}}, - {{/hasMore}}{{/vars}} - ]; - - /** - * Array of attributes where the key is the local name, - * and the value is the original name - * - * @return array - */ - public static function attributeMap() - { - return {{#parentSchema}}parent::attributeMap() + {{/parentSchema}}self::$attributeMap; - } - - /** - * Array of attributes to setter functions (for deserialization of responses) - * - * @return array - */ - public static function setters() - { - return {{#parentSchema}}parent::setters() + {{/parentSchema}}self::$setters; - } - - /** - * Array of attributes to getter functions (for serialization of requests) - * - * @return array - */ - public static function getters() - { - return {{#parentSchema}}parent::getters() + {{/parentSchema}}self::$getters; - } - - /** - * The original name of the model. - * - * @return string - */ - public function getModelName() - { - return self::$swaggerModelName; - } - - {{#vars}}{{#isEnum}}{{#allowableValues}}{{#enumVars}}const {{enumName}}_{{{name}}} = {{{value}}}; - {{/enumVars}}{{/allowableValues}}{{/isEnum}}{{/vars}} - - {{#vars}}{{#isEnum}} - /** - * Gets allowable values of the enum - * - * @return string[] - */ - public function {{getter}}AllowableValues() - { - return [ - {{#allowableValues}}{{#enumVars}}self::{{enumName}}_{{{name}}},{{^-last}} - {{/-last}}{{/enumVars}}{{/allowableValues}} - ]; - } - {{/isEnum}}{{/vars}} - - {{^parentSchema}} - /** - * Associative array for storing property values - * - * @var mixed[] - */ - protected $container = []; - {{/parentSchema}} - - /** - * Constructor - * - * @param mixed[] $data Associated array of property values - * initializing the model - */ - public function __construct(array $data = null) - { - {{#parentSchema}} - parent::__construct($data); - - {{/parentSchema}} - {{#vars}} - $this->container['{{name}}'] = isset($data['{{name}}']) ? $data['{{name}}'] : {{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}; - {{/vars}} - {{#discriminator}} - - // Initialize discriminator property with the model name. - $discriminator = array_search('{{discriminator.propertyName}}', self::$attributeMap); - $this->container[$discriminator] = static::$swaggerModelName; - {{/discriminator}} - } - - /** - * Show all the invalid properties with reasons. - * - * @return array invalid properties with reasons - */ - public function listInvalidProperties() - { - {{#parent}} - $invalidProperties = parent::listInvalidProperties(); - {{/parent}} - {{^parent}} - $invalidProperties = []; - {{/parent}} - - {{#vars}} - {{#required}} - if ($this->container['{{name}}'] === null) { - $invalidProperties[] = "'{{name}}' can't be null"; - } - {{/required}} - {{#isEnum}} - {{^isContainer}} - $allowedValues = $this->{{getter}}AllowableValues(); - if (!is_null($this->container['{{name}}']) && !in_array($this->container['{{name}}'], $allowedValues, true)) { - $invalidProperties[] = sprintf( - "invalid value for '{{name}}', must be one of '%s'", - implode("', '", $allowedValues) - ); - } - - {{/isContainer}} - {{/isEnum}} - {{#hasValidation}} - {{#maxLength}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}(mb_strlen($this->container['{{name}}']) > {{maxLength}})) { - $invalidProperties[] = "invalid value for '{{name}}', the character length must be smaller than or equal to {{{maxLength}}}."; - } - - {{/maxLength}} - {{#minLength}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}(mb_strlen($this->container['{{name}}']) < {{minLength}})) { - $invalidProperties[] = "invalid value for '{{name}}', the character length must be bigger than or equal to {{{minLength}}}."; - } - - {{/minLength}} - {{#maximum}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}($this->container['{{name}}'] >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}})) { - $invalidProperties[] = "invalid value for '{{name}}', must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{maximum}}."; - } - - {{/maximum}} - {{#minimum}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}($this->container['{{name}}'] <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}})) { - $invalidProperties[] = "invalid value for '{{name}}', must be bigger than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{minimum}}."; - } - - {{/minimum}} - {{#pattern}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}!preg_match("{{{pattern}}}", $this->container['{{name}}'])) { - $invalidProperties[] = "invalid value for '{{name}}', must be conform to the pattern {{{pattern}}}."; - } - - {{/pattern}} - {{#maxItems}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}(count($this->container['{{name}}']) > {{maxItems}})) { - $invalidProperties[] = "invalid value for '{{name}}', number of items must be less than or equal to {{{maxItems}}}."; - } - - {{/maxItems}} - {{#minItems}} - if ({{^required}}!is_null($this->container['{{name}}']) && {{/required}}(count($this->container['{{name}}']) < {{minItems}})) { - $invalidProperties[] = "invalid value for '{{name}}', number of items must be greater than or equal to {{{minItems}}}."; - } - - {{/minItems}} - {{/hasValidation}} - {{/vars}} - return $invalidProperties; - } - - /** - * Validate all the properties in the model - * return true if all passed - * - * @return bool True if all properties are valid - */ - public function valid() - { - return count($this->listInvalidProperties()) === 0; - } - - {{#vars}} - - /** - * Gets {{name}} - * - * @return {{datatype}} - */ - public function {{getter}}() - { - return $this->container['{{name}}']; - } - - /** - * Sets {{name}} - * - * @param {{datatype}} ${{name}}{{#description}} {{{description}}}{{/description}}{{^description}} {{{name}}}{{/description}} - * - * @return $this - */ - public function {{setter}}(${{name}}) - { - {{#isEnum}} - $allowedValues = $this->{{getter}}AllowableValues(); - {{^isContainer}} - if ({{^required}}!is_null(${{name}}) && {{/required}}!in_array(${{{name}}}, $allowedValues, true)) { - throw new \InvalidArgumentException( - sprintf( - "Invalid value for '{{name}}', must be one of '%s'", - implode("', '", $allowedValues) - ) - ); - } - {{/isContainer}} - {{#isContainer}} - if ({{^required}}!is_null(${{name}}) && {{/required}}array_diff(${{{name}}}, $allowedValues)) { - throw new \InvalidArgumentException( - sprintf( - "Invalid value for '{{name}}', must be one of '%s'", - implode("', '", $allowedValues) - ) - ); - } - {{/isContainer}} - {{/isEnum}} - {{#hasValidation}} - {{#maxLength}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(mb_strlen(${{name}}) > {{maxLength}})) { - throw new \InvalidArgumentException('invalid length for ${{name}} when calling {{classname}}.{{operationId}}, must be smaller than or equal to {{maxLength}}.'); - }{{/maxLength}} - {{#minLength}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(mb_strlen(${{name}}) < {{minLength}})) { - throw new \InvalidArgumentException('invalid length for ${{name}} when calling {{classname}}.{{operationId}}, must be bigger than or equal to {{minLength}}.'); - } - {{/minLength}} - {{#maximum}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(${{name}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}})) { - throw new \InvalidArgumentException('invalid value for ${{name}} when calling {{classname}}.{{operationId}}, must be smaller than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}{{maximum}}.'); - } - {{/maximum}} - {{#minimum}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(${{name}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}})) { - throw new \InvalidArgumentException('invalid value for ${{name}} when calling {{classname}}.{{operationId}}, must be bigger than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}{{minimum}}.'); - } - {{/minimum}} - {{#pattern}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(!preg_match("{{{pattern}}}", ${{name}}))) { - throw new \InvalidArgumentException("invalid value for ${{name}} when calling {{classname}}.{{operationId}}, must conform to the pattern {{{pattern}}}."); - } - {{/pattern}} - {{#maxItems}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(count(${{name}}) > {{maxItems}})) { - throw new \InvalidArgumentException('invalid value for ${{name}} when calling {{classname}}.{{operationId}}, number of items must be less than or equal to {{maxItems}}.'); - }{{/maxItems}} - {{#minItems}} - if ({{^required}}!is_null(${{name}}) && {{/required}}(count(${{name}}) < {{minItems}})) { - throw new \InvalidArgumentException('invalid length for ${{name}} when calling {{classname}}.{{operationId}}, number of items must be greater than or equal to {{minItems}}.'); - } - {{/minItems}} - {{/hasValidation}} - $this->container['{{name}}'] = ${{name}}; - - return $this; - } - {{/vars}} - /** - * Returns true if offset exists. False otherwise. - * - * @param integer $offset Offset - * - * @return boolean - */ - public function offsetExists($offset) - { - return isset($this->container[$offset]); - } - - /** - * Gets offset. - * - * @param integer $offset Offset - * - * @return mixed - */ - public function offsetGet($offset) - { - return isset($this->container[$offset]) ? $this->container[$offset] : null; - } - - /** - * Sets value based on offset. - * - * @param integer $offset Offset - * @param mixed $value Value to be set - * - * @return void - */ - public function offsetSet($offset, $value) - { - if (is_null($offset)) { - $this->container[] = $value; - } else { - $this->container[$offset] = $value; - } - } - - /** - * Unsets offset. - * - * @param integer $offset Offset - * - * @return void - */ - public function offsetUnset($offset) - { - unset($this->container[$offset]); - } - - /** - * Gets the string presentation of the object - * - * @return string - */ - public function __toString() - { - if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print - return json_encode( - ObjectSerializer::sanitizeForSerialization($this), - JSON_PRETTY_PRINT - ); - } - - return json_encode(ObjectSerializer::sanitizeForSerialization($this)); - } -} diff --git a/src/main/resources/mustache/php/model_test.mustache b/src/main/resources/mustache/php/model_test.mustache deleted file mode 100644 index 99064308f5..0000000000 --- a/src/main/resources/mustache/php/model_test.mustache +++ /dev/null @@ -1,81 +0,0 @@ -partial_header}} -/** - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen - * Please update the test case below to test the model. - */ - -namespace {{invokerPackage}}; - -/** - * {{classname}}Test Class Doc Comment - * - * @category Class - * @description {{#description}}{{description}}{{/description}}{{^description}}{{classname}}{{/description}} - * @package {{invokerPackage}} - * @author Swagger Codegen team - * @link https://github.com/swagger-api/swagger-codegen - */ -class {{classname}}Test extends \PHPUnit_Framework_TestCase -{ - - /** - * Setup before running any test case - */ - public static function setUpBeforeClass() - { - } - - /** - * Setup before running each test case - */ - public function setUp() - { - } - - /** - * Clean up after running each test case - */ - public function tearDown() - { - } - - /** - * Clean up after running all test cases - */ - public static function tearDownAfterClass() - { - } - - /** - * Test "{{classname}}" - */ - public function test{{classname}}() - { - } -{{#vars}} - - /** - * Test attribute "{{name}}" - */ - public function testProperty{{nameInCamelCase}}() - { - } -{{/vars}} -} -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/php/partial_header.mustache b/src/main/resources/mustache/php/partial_header.mustache deleted file mode 100644 index 4cf2337cac..0000000000 --- a/src/main/resources/mustache/php/partial_header.mustache +++ /dev/null @@ -1,14 +0,0 @@ -/** - {{#appName}} - * {{{appName}}} - * - {{/appName}} - {{#appDescription}} - * {{{appDescription}}} - * - {{/appDescription}} - * {{#version}}OpenAPI spec version: {{{version}}}{{/version}} - * {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} - * Generated by: https://github.com/swagger-api/swagger-codegen.git - * Swagger Codegen version: {{{generatorVersion}}} - */ diff --git a/src/main/resources/mustache/php/phpunit.xml.mustache b/src/main/resources/mustache/php/phpunit.xml.mustache deleted file mode 100644 index 5de6fea575..0000000000 --- a/src/main/resources/mustache/php/phpunit.xml.mustache +++ /dev/null @@ -1,21 +0,0 @@ - - - - - {{apiTestPath}} - {{modelTestPath}} - - - - - - {{apiSrcPath}} - {{modelSrcPath}} - - - diff --git a/src/main/resources/mustache/python/README.mustache b/src/main/resources/mustache/python/README.mustache deleted file mode 100644 index 094a6474c3..0000000000 --- a/src/main/resources/mustache/python/README.mustache +++ /dev/null @@ -1,129 +0,0 @@ -# {{{projectName}}} -{{#appDescription}} -{{{appDescription}}} -{{/appDescription}} - -This Python package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: - -- API version: {{appVersion}} -- Package version: {{packageVersion}} -{{^hideGenerationTimestamp}} -- Build date: {{generatedDate}} -{{/hideGenerationTimestamp}} -- Build package: {{generatorClass}} -{{#infoUrl}} -For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) -{{/infoUrl}} - -## Requirements. - -Python 2.7 and 3.4+ - -## Installation & Usage -### pip install - -If the python package is hosted on Github, you can install directly from Github - -```sh -pip install git+https://github.com/{{{gitUserId}}}/{{{gitRepoId}}}.git -``` -(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/{{{gitUserId}}}/{{{gitRepoId}}}.git`) - -Then import the package: -```python -import {{{packageName}}} -``` - -### Setuptools - -Install via [Setuptools](http://pypi.python.org/pypi/setuptools). - -```sh -python setup.py install --user -``` -(or `sudo python setup.py install` to install the package for all users) - -Then import the package: -```python -import {{{packageName}}} -``` - -## Getting Started - -Please follow the [installation procedure](#installation--usage) and then run the following: - -```python -from __future__ import print_function -import time -import {{{packageName}}} -from {{{packageName}}}.rest import ApiException -from pprint import pprint -{{#apiInfo}}{{#apis}}{{#-first}}{{#operations}}{{#operation}}{{#contents}}{{#-first}}{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} -# Configure HTTP basic authorization: {{{name}}} -configuration = {{{packageName}}}.Configuration() -configuration.username = 'YOUR_USERNAME' -configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}} -# Configure API key authorization: {{{name}}} -configuration = {{{packageName}}}.Configuration() -configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY' -# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -# configuration.api_key_prefix['{{{keyParamName}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}} -# Configure OAuth2 access token for authorization: {{{name}}} -configuration = {{{packageName}}}.Configuration() -configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}} -{{/hasAuthMethods}} - -# create an instance of the API class -api_instance = {{{packageName}}}.{{{classname}}}({{{packageName}}}.ApiClient(configuration)) -{{#parameters}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} -{{/parameters}} - -try: -{{#summary}} # {{{.}}} -{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationId}}}({{#parameters}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}){{#returnType}} - pprint(api_response){{/returnType}} -except ApiException as e: - print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e) -{{/-first}}{{/contents}}{{/operation}}{{/operations}}{{/-first}}{{/apis}}{{/apiInfo}} -``` - -## Documentation for API Endpoints - -All URIs are relative to *{{basePath}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} - -## Documentation For Models - -{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) -{{/model}}{{/models}} - -## Documentation For Authorization - -{{^authMethods}} All endpoints do not require authorization. -{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}} -{{#authMethods}}## {{{name}}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{{keyParamName}}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{{flow}}} -- **Authorization URL**: {{{authorizationUrl}}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - **{{{scope}}}**: {{{description}}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} - -## Author - -{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} -{{/hasMore}}{{/apis}}{{/apiInfo}} diff --git a/src/main/resources/mustache/python/__init__api.mustache b/src/main/resources/mustache/python/__init__api.mustache deleted file mode 100644 index db658a10fa..0000000000 --- a/src/main/resources/mustache/python/__init__api.mustache +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import absolute_import - -# flake8: noqa - -# import apis into api package -{{#apiInfo}}{{#apis}}from {{apiPackage}}.{{classVarName}} import {{classname}} -{{/apis}}{{/apiInfo}} \ No newline at end of file diff --git a/src/main/resources/mustache/python/__init__model.mustache b/src/main/resources/mustache/python/__init__model.mustache deleted file mode 100644 index 2266b3d17f..0000000000 --- a/src/main/resources/mustache/python/__init__model.mustache +++ /dev/null @@ -1,10 +0,0 @@ -# coding: utf-8 - -# flake8: noqa -{{>partial_header}} - -from __future__ import absolute_import - -# import models into model package -{{#models}}{{#model}}from {{modelPackage}}.{{classFilename}} import {{classname}}{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/python/__init__package.mustache b/src/main/resources/mustache/python/__init__package.mustache deleted file mode 100644 index cd42506f54..0000000000 --- a/src/main/resources/mustache/python/__init__package.mustache +++ /dev/null @@ -1,17 +0,0 @@ -# coding: utf-8 - -# flake8: noqa - -{{>partial_header}} - -from __future__ import absolute_import - -# import apis into sdk package -{{#apiInfo}}{{#apis}}from {{apiPackage}}.{{classVarName}} import {{classname}} -{{/apis}}{{/apiInfo}} -# import ApiClient -from {{packageName}}.api_client import ApiClient -from {{packageName}}.configuration import Configuration -# import models into sdk package -{{#models}}{{#model}}from {{modelPackage}}.{{classFilename}} import {{classname}} -{{/model}}{{/models}} \ No newline at end of file diff --git a/src/main/resources/mustache/python/__init__test.mustache b/src/main/resources/mustache/python/__init__test.mustache deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/main/resources/mustache/python/api.mustache b/src/main/resources/mustache/python/api.mustache deleted file mode 100644 index 8e22ab317e..0000000000 --- a/src/main/resources/mustache/python/api.mustache +++ /dev/null @@ -1,216 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -from __future__ import absolute_import - -import re # noqa: F401 - -# python 2 and python 3 compatibility library -import six - -from {{packageName}}.api_client import ApiClient - - -{{#operations}} -class {{classname}}(object): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - Ref: https://github.com/swagger-api/swagger-codegen - """ - - def __init__(self, api_client=None): - if api_client is None: - api_client = ApiClient() - self.api_client = api_client -{{#operation}} -{{#contents}} - - def {{operationId}}(self, {{#sortParamsByRequiredFlag}}{{#parameters}}{{#required}}{{paramName}}, {{/required}}{{/parameters}}{{/sortParamsByRequiredFlag}}**kwargs): # noqa: E501 - """{{#summary}}{{{.}}}{{/summary}}{{^summary}}{{operationId}}{{/summary}} # noqa: E501 - -{{#notes}} - {{{notes}}} # noqa: E501 -{{/notes}} - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True -{{#sortParamsByRequiredFlag}} - >>> thread = api.{{operationId}}({{#parameters}}{{#required}}{{paramName}}, {{/required}}{{/parameters}}async_req=True) -{{/sortParamsByRequiredFlag}} -{{^sortParamsByRequiredFlag}} - >>> thread = api.{{operationId}}({{#parameters}}{{#required}}{{paramName}}={{paramName}}_value, {{/required}}{{/parameters}}async_req=True) -{{/sortParamsByRequiredFlag}} - >>> result = thread.get() - - :param async_req bool -{{#parameters}} - :param {{dataType}} {{paramName}}:{{#description}} {{{description}}}{{/description}}{{#required}} (required){{/required}}{{#optional}}(optional){{/optional}} -{{/parameters}} - :return: {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}None{{/returnType}} - If the method is called asynchronously, - returns the request thread. - """ - kwargs['_return_http_data_only'] = True - if kwargs.get('async_req'): - return self.{{operationId}}_with_http_info({{#sortParamsByRequiredFlag}}{{#parameters}}{{#required}}{{paramName}}, {{/required}}{{/parameters}}{{/sortParamsByRequiredFlag}}**kwargs) # noqa: E501 - else: - (data) = self.{{operationId}}_with_http_info({{#sortParamsByRequiredFlag}}{{#parameters}}{{#required}}{{paramName}}, {{/required}}{{/parameters}}{{/sortParamsByRequiredFlag}}**kwargs) # noqa: E501 - return data - - def {{operationId}}_with_http_info(self, {{#sortParamsByRequiredFlag}}{{#parameters}}{{#required}}{{paramName}}, {{/required}}{{/parameters}}{{/sortParamsByRequiredFlag}}**kwargs): # noqa: E501 - """{{#summary}}{{{.}}}{{/summary}}{{^summary}}{{operationId}}{{/summary}} # noqa: E501 - -{{#notes}} - {{{notes}}} # noqa: E501 -{{/notes}} - This method makes a synchronous HTTP request by default. To make an - asynchronous HTTP request, please pass async_req=True -{{#sortParamsByRequiredFlag}} - >>> thread = api.{{operationId}}_with_http_info({{#parameters}}{{#required}}{{paramName}}, {{/required}}{{/parameters}}async_req=True) -{{/sortParamsByRequiredFlag}} -{{^sortParamsByRequiredFlag}} - >>> thread = api.{{operationId}}_with_http_info({{#parameters}}{{#required}}{{paramName}}={{paramName}}_value, {{/required}}{{/parameters}}async_req=True) -{{/sortParamsByRequiredFlag}} - >>> result = thread.get() - - :param async_req bool -{{#parameters}} - :param {{dataType}} {{paramName}}:{{#description}} {{{description}}}{{/description}}{{#required}} (required){{/required}}{{#optional}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/optional}} -{{/parameters}} - :return: {{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}None{{/returnType}} - If the method is called asynchronously, - returns the request thread. - """ - - all_params = [{{#parameters}}'{{paramName}}'{{#hasMore}}, {{/hasMore}}{{/parameters}}] # noqa: E501 - all_params.append('async_req') - all_params.append('_return_http_data_only') - all_params.append('_preload_content') - all_params.append('_request_timeout') - - params = locals() - for key, val in six.iteritems(params['kwargs']): - if key not in all_params: - raise TypeError( - "Got an unexpected keyword argument '%s'" - " to method {{operationId}}" % key - ) - params[key] = val - del params['kwargs'] -{{#parameters}} -{{#required}} - # verify the required parameter '{{paramName}}' is set - if ('{{paramName}}' not in params or - params['{{paramName}}'] is None): - raise ValueError("Missing the required parameter `{{paramName}}` when calling `{{operationId}}`") # noqa: E501 -{{/required}} -{{/parameters}} - -{{#parameters}} -{{#hasValidation}} - {{#maxLength}} - if ('{{paramName}}' in params and - len(params['{{paramName}}']) > {{maxLength}}): - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, length must be less than or equal to `{{maxLength}}`") # noqa: E501 - {{/maxLength}} - {{#minLength}} - if ('{{paramName}}' in params and - len(params['{{paramName}}']) < {{minLength}}): - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, length must be greater than or equal to `{{minLength}}`") # noqa: E501 - {{/minLength}} - {{#maximum}} - if '{{paramName}}' in params and params['{{paramName}}'] >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}: # noqa: E501 - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, must be a value less than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}`{{maximum}}`") # noqa: E501 - {{/maximum}} - {{#minimum}} - if '{{paramName}}' in params and params['{{paramName}}'] <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}: # noqa: E501 - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, must be a value greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}`{{minimum}}`") # noqa: E501 - {{/minimum}} - {{#pattern}} - if '{{paramName}}' in params and not re.search(r'{{{vendorExtensions.x-regex}}}', params['{{paramName}}']{{#vendorExtensions.x-modifiers}}{{#-first}}, flags={{/-first}}re.{{.}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}): # noqa: E501 - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, must conform to the pattern `{{{pattern}}}`") # noqa: E501 - {{/pattern}} - {{#maxItems}} - if ('{{paramName}}' in params and - len(params['{{paramName}}']) > {{maxItems}}): - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, number of items must be less than or equal to `{{maxItems}}`") # noqa: E501 - {{/maxItems}} - {{#minItems}} - if ('{{paramName}}' in params and - len(params['{{paramName}}']) < {{minItems}}): - raise ValueError("Invalid value for parameter `{{paramName}}` when calling `{{operationId}}`, number of items must be greater than or equal to `{{minItems}}`") # noqa: E501 - {{/minItems}} -{{/hasValidation}} -{{#-last}} -{{/-last}} -{{/parameters}} - collection_formats = {} - - path_params = {} -{{#pathParams}} - if '{{paramName}}' in params: - path_params['{{baseName}}'] = params['{{paramName}}']{{#isListContainer}} # noqa: E501 - collection_formats['{{baseName}}'] = '{{collectionFormat}}'{{/isListContainer}} # noqa: E501 -{{/pathParams}} - - query_params = [] -{{#queryParams}} - if '{{paramName}}' in params: - query_params.append(('{{baseName}}', params['{{paramName}}'])){{#isListContainer}} # noqa: E501 - collection_formats['{{baseName}}'] = '{{collectionFormat}}'{{/isListContainer}} # noqa: E501 -{{/queryParams}} - - header_params = {} -{{#headerParams}} - if '{{paramName}}' in params: - header_params['{{baseName}}'] = params['{{paramName}}']{{#isListContainer}} # noqa: E501 - collection_formats['{{baseName}}'] = '{{collectionFormat}}'{{/isListContainer}} # noqa: E501 -{{/headerParams}} - - form_params = [] - local_var_files = {} -{{#formParams}} - if '{{paramName}}' in params: - {{#notFile}}form_params.append(('{{baseName}}', params['{{paramName}}'])){{/notFile}}{{#isFile}}local_var_files['{{baseName}}'] = params['{{paramName}}']{{/isFile}}{{#isListContainer}} # noqa: E501 - collection_formats['{{baseName}}'] = '{{collectionFormat}}'{{/isListContainer}} # noqa: E501 -{{/formParams}} - - body_params = None -{{#bodyParam}} - if '{{paramName}}' in params: - body_params = params['{{paramName}}'] -{{/bodyParam}} - {{#hasProduces}} - # HTTP header `Accept` - header_params['Accept'] = self.api_client.select_header_accept( - [{{#produces}}'{{{mediaType}}}'{{#hasMore}}, {{/hasMore}}{{/produces}}]) # noqa: E501 - - {{/hasProduces}} - {{#hasConsumes}} - # HTTP header `Content-Type` - header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 - [{{#consumes}}'{{{mediaType}}}'{{#hasMore}}, {{/hasMore}}{{/consumes}}]) # noqa: E501 - - {{/hasConsumes}} - # Authentication setting - auth_settings = [{{#authMethods}}'{{name}}'{{#hasMore}}, {{/hasMore}}{{/authMethods}}] # noqa: E501 - - return self.api_client.call_api( - '{{{path}}}', '{{httpMethod}}', - path_params, - query_params, - header_params, - body=body_params, - post_params=form_params, - files=local_var_files, - response_type={{#returnType}}'{{returnType}}'{{/returnType}}{{^returnType}}None{{/returnType}}, # noqa: E501 - auth_settings=auth_settings, - async_req=params.get('async_req'), - _return_http_data_only=params.get('_return_http_data_only'), - _preload_content=params.get('_preload_content', True), - _request_timeout=params.get('_request_timeout'), - collection_formats=collection_formats) -{{/contents}} -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/python/api_client.mustache b/src/main/resources/mustache/python/api_client.mustache deleted file mode 100644 index e46230fd75..0000000000 --- a/src/main/resources/mustache/python/api_client.mustache +++ /dev/null @@ -1,635 +0,0 @@ -# coding: utf-8 -{{>partial_header}} -from __future__ import absolute_import - -import datetime -import json -import mimetypes -from multiprocessing.pool import ThreadPool -import os -import re -import tempfile - -# python 2 and python 3 compatibility library -import six -from six.moves.urllib.parse import quote -{{#tornado}} -import tornado.gen -{{/tornado}} - -from {{packageName}}.configuration import Configuration -import {{modelPackage}} -from {{packageName}} import rest - - -class ApiClient(object): - """Generic API client for Swagger client library builds. - - Swagger generic API client. This client handles the client- - server communication, and is invariant across implementations. Specifics of - the methods and models for each application are generated from the Swagger - templates. - - NOTE: This class is auto generated by the swagger code generator program. - Ref: https://github.com/swagger-api/swagger-codegen - Do not edit the class manually. - - :param configuration: .Configuration object for this client - :param header_name: a header to pass when making calls to the API. - :param header_value: a header value to pass when making calls to - the API. - :param cookie: a cookie to include in the header when making calls - to the API - """ - - PRIMITIVE_TYPES = (float, bool, bytes, six.text_type) + six.integer_types - NATIVE_TYPES_MAPPING = { - 'int': int, - 'long': int if six.PY3 else long, # noqa: F821 - 'float': float, - 'str': str, - 'bool': bool, - 'date': datetime.date, - 'datetime': datetime.datetime, - 'object': object, - } - - def __init__(self, configuration=None, header_name=None, header_value=None, - cookie=None): - if configuration is None: - configuration = Configuration() - self.configuration = configuration - - self.pool = ThreadPool() - self.rest_client = rest.RESTClientObject(configuration) - self.default_headers = {} - if header_name is not None: - self.default_headers[header_name] = header_value - self.cookie = cookie - # Set default User-Agent. - self.user_agent = '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{packageVersion}}}/python{{/httpUserAgent}}' - - def __del__(self): - self.pool.close() - self.pool.join() - - @property - def user_agent(self): - """User agent for this API client""" - return self.default_headers['User-Agent'] - - @user_agent.setter - def user_agent(self, value): - self.default_headers['User-Agent'] = value - - def set_default_header(self, header_name, header_value): - self.default_headers[header_name] = header_value - - {{#tornado}} - @tornado.gen.coroutine - {{/tornado}} - {{#asyncio}}async {{/asyncio}}def __call_api( - self, resource_path, method, path_params=None, - query_params=None, header_params=None, body=None, post_params=None, - files=None, response_type=None, auth_settings=None, - _return_http_data_only=None, collection_formats=None, - _preload_content=True, _request_timeout=None): - - config = self.configuration - - # header parameters - header_params = header_params or {} - header_params.update(self.default_headers) - if self.cookie: - header_params['Cookie'] = self.cookie - if header_params: - header_params = self.sanitize_for_serialization(header_params) - header_params = dict(self.parameters_to_tuples(header_params, - collection_formats)) - - # path parameters - if path_params: - path_params = self.sanitize_for_serialization(path_params) - path_params = self.parameters_to_tuples(path_params, - collection_formats) - for k, v in path_params: - # specified safe chars, encode everything - resource_path = resource_path.replace( - '{%s}' % k, - quote(str(v), safe=config.safe_chars_for_path_param) - ) - - # query parameters - if query_params: - query_params = self.sanitize_for_serialization(query_params) - query_params = self.parameters_to_tuples(query_params, - collection_formats) - - # post parameters - if post_params or files: - post_params = self.prepare_post_parameters(post_params, files) - post_params = self.sanitize_for_serialization(post_params) - post_params = self.parameters_to_tuples(post_params, - collection_formats) - - # auth setting - self.update_params_for_auth(header_params, query_params, auth_settings) - - # body - if body: - body = self.sanitize_for_serialization(body) - - # request url - url = self.configuration.host + resource_path - - # perform request and return response - response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request( - method, url, query_params=query_params, headers=header_params, - post_params=post_params, body=body, - _preload_content=_preload_content, - _request_timeout=_request_timeout) - - self.last_response = response_data - - return_data = response_data - if _preload_content: - # deserialize response data - if response_type: - return_data = self.deserialize(response_data, response_type) - else: - return_data = None - -{{^tornado}} - if _return_http_data_only: - return (return_data) - else: - return (return_data, response_data.status, - response_data.getheaders()) -{{/tornado}} -{{#tornado}} - if _return_http_data_only: - raise tornado.gen.Return(return_data) - else: - raise tornado.gen.Return((return_data, response_data.status, - response_data.getheaders())) -{{/tornado}} - - def sanitize_for_serialization(self, obj): - """Builds a JSON POST object. - - If obj is None, return None. - If obj is str, int, long, float, bool, return directly. - If obj is datetime.datetime, datetime.date - convert to string in iso8601 format. - If obj is list, sanitize each element in the list. - If obj is dict, return the dict. - If obj is swagger model, return the properties dict. - - :param obj: The data to serialize. - :return: The serialized form of data. - """ - if obj is None: - return None - elif isinstance(obj, self.PRIMITIVE_TYPES): - return obj - elif isinstance(obj, list): - return [self.sanitize_for_serialization(sub_obj) - for sub_obj in obj] - elif isinstance(obj, tuple): - return tuple(self.sanitize_for_serialization(sub_obj) - for sub_obj in obj) - elif isinstance(obj, (datetime.datetime, datetime.date)): - return obj.isoformat() - - if isinstance(obj, dict): - obj_dict = obj - else: - # Convert model obj to dict except - # attributes `swagger_types`, `attribute_map` - # and attributes which value is not None. - # Convert attribute name to json key in - # model definition for request. - obj_dict = {obj.attribute_map[attr]: getattr(obj, attr) - for attr, _ in six.iteritems(obj.swagger_types) - if getattr(obj, attr) is not None} - - return {key: self.sanitize_for_serialization(val) - for key, val in six.iteritems(obj_dict)} - - def deserialize(self, response, response_type): - """Deserializes response into an object. - - :param response: RESTResponse object to be deserialized. - :param response_type: class literal for - deserialized object, or string of class name. - - :return: deserialized object. - """ - # handle file downloading - # save response body into a tmp file and return the instance - if response_type == "file": - return self.__deserialize_file(response) - - # fetch data from response object - try: - data = json.loads(response.data) - except ValueError: - data = response.data - - return self.__deserialize(data, response_type) - - def __deserialize(self, data, klass): - """Deserializes dict, list, str into an object. - - :param data: dict, list or str. - :param klass: class literal, or string of class name. - - :return: object. - """ - if data is None: - return None - - if type(klass) == str: - if klass.startswith('list['): - sub_kls = re.match(r'list\[(.*)\]', klass).group(1) - return [self.__deserialize(sub_data, sub_kls) - for sub_data in data] - - if klass.startswith('dict('): - sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2) - return {k: self.__deserialize(v, sub_kls) - for k, v in six.iteritems(data)} - - # convert str to class - if klass in self.NATIVE_TYPES_MAPPING: - klass = self.NATIVE_TYPES_MAPPING[klass] - else: - klass = getattr({{modelPackage}}, klass) - - if klass in self.PRIMITIVE_TYPES: - return self.__deserialize_primitive(data, klass) - elif klass == object: - return self.__deserialize_object(data) - elif klass == datetime.date: - return self.__deserialize_date(data) - elif klass == datetime.datetime: - return self.__deserialize_datatime(data) - else: - return self.__deserialize_model(data, klass) - - def call_api(self, resource_path, method, - path_params=None, query_params=None, header_params=None, - body=None, post_params=None, files=None, - response_type=None, auth_settings=None, async_req=None, - _return_http_data_only=None, collection_formats=None, - _preload_content=True, _request_timeout=None): - """Makes the HTTP request (synchronous) and returns deserialized data. - - To make an async request, set the async_req parameter. - - :param resource_path: Path to method endpoint. - :param method: Method to call. - :param path_params: Path parameters in the url. - :param query_params: Query parameters in the url. - :param header_params: Header parameters to be - placed in the request header. - :param body: Request body. - :param post_params dict: Request post form parameters, - for `application/x-www-form-urlencoded`, `multipart/form-data`. - :param auth_settings list: Auth Settings names for the request. - :param response: Response data type. - :param files dict: key -> filename, value -> filepath, - for `multipart/form-data`. - :param async_req bool: execute request asynchronously - :param _return_http_data_only: response data without head status code - and headers - :param collection_formats: dict of collection formats for path, query, - header, and post parameters. - :param _preload_content: if False, the urllib3.HTTPResponse object will - be returned without reading/decoding response - data. Default is True. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - :return: - If async_req parameter is True, - the request will be called asynchronously. - The method will return the request thread. - If parameter async_req is False or missing, - then the method will return the response directly. - """ - if not async_req: - return self.__call_api(resource_path, method, - path_params, query_params, header_params, - body, post_params, files, - response_type, auth_settings, - _return_http_data_only, collection_formats, - _preload_content, _request_timeout) - else: - thread = self.pool.apply_async(self.__call_api, (resource_path, - method, path_params, query_params, - header_params, body, - post_params, files, - response_type, auth_settings, - _return_http_data_only, - collection_formats, - _preload_content, _request_timeout)) - return thread - - def request(self, method, url, query_params=None, headers=None, - post_params=None, body=None, _preload_content=True, - _request_timeout=None): - """Makes the HTTP request using RESTClient.""" - if method == "GET": - return self.rest_client.GET(url, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - headers=headers) - elif method == "HEAD": - return self.rest_client.HEAD(url, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - headers=headers) - elif method == "OPTIONS": - return self.rest_client.OPTIONS(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "POST": - return self.rest_client.POST(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "PUT": - return self.rest_client.PUT(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "PATCH": - return self.rest_client.PATCH(url, - query_params=query_params, - headers=headers, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - elif method == "DELETE": - return self.rest_client.DELETE(url, - query_params=query_params, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - else: - raise ValueError( - "http method must be `GET`, `HEAD`, `OPTIONS`," - " `POST`, `PATCH`, `PUT` or `DELETE`." - ) - - def parameters_to_tuples(self, params, collection_formats): - """Get parameters as list of tuples, formatting collections. - - :param params: Parameters as dict or list of two-tuples - :param dict collection_formats: Parameter collection formats - :return: Parameters as list of tuples, collections formatted - """ - new_params = [] - if collection_formats is None: - collection_formats = {} - for k, v in six.iteritems(params) if isinstance(params, dict) else params: # noqa: E501 - if k in collection_formats: - collection_format = collection_formats[k] - if collection_format == 'multi': - new_params.extend((k, value) for value in v) - else: - if collection_format == 'ssv': - delimiter = ' ' - elif collection_format == 'tsv': - delimiter = '\t' - elif collection_format == 'pipes': - delimiter = '|' - else: # csv is the default - delimiter = ',' - new_params.append( - (k, delimiter.join(str(value) for value in v))) - else: - new_params.append((k, v)) - return new_params - - def prepare_post_parameters(self, post_params=None, files=None): - """Builds form parameters. - - :param post_params: Normal form parameters. - :param files: File parameters. - :return: Form parameters with files. - """ - params = [] - - if post_params: - params = post_params - - if files: - for k, v in six.iteritems(files): - if not v: - continue - file_names = v if type(v) is list else [v] - for n in file_names: - with open(n, 'rb') as f: - filename = os.path.basename(f.name) - filedata = f.read() - mimetype = (mimetypes.guess_type(filename)[0] or - 'application/octet-stream') - params.append( - tuple([k, tuple([filename, filedata, mimetype])])) - - return params - - def select_header_accept(self, accepts): - """Returns `Accept` based on an array of accepts provided. - - :param accepts: List of headers. - :return: Accept (e.g. application/json). - """ - if not accepts: - return - - accepts = [x.lower() for x in accepts] - - if 'application/json' in accepts: - return 'application/json' - else: - return ', '.join(accepts) - - def select_header_content_type(self, content_types): - """Returns `Content-Type` based on an array of content_types provided. - - :param content_types: List of content-types. - :return: Content-Type (e.g. application/json). - """ - if not content_types: - return 'application/json' - - content_types = [x.lower() for x in content_types] - - if 'application/json' in content_types or '*/*' in content_types: - return 'application/json' - else: - return content_types[0] - - def update_params_for_auth(self, headers, querys, auth_settings): - """Updates header and query params based on authentication setting. - - :param headers: Header parameters dict to be updated. - :param querys: Query parameters tuple list to be updated. - :param auth_settings: Authentication setting identifiers list. - """ - if not auth_settings: - return - - for auth in auth_settings: - auth_setting = self.configuration.auth_settings().get(auth) - if auth_setting: - if not auth_setting['value']: - continue - elif auth_setting['in'] == 'header': - headers[auth_setting['key']] = auth_setting['value'] - elif auth_setting['in'] == 'query': - querys.append((auth_setting['key'], auth_setting['value'])) - else: - raise ValueError( - 'Authentication token must be in `query` or `header`' - ) - - def __deserialize_file(self, response): - """Deserializes body to file - - Saves response body into a file in a temporary folder, - using the filename from the `Content-Disposition` header if provided. - - :param response: RESTResponse. - :return: file path. - """ - fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path) - os.close(fd) - os.remove(path) - - content_disposition = response.getheader("Content-Disposition") - if content_disposition: - filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', - content_disposition).group(1) - path = os.path.join(os.path.dirname(path), filename) - - with open(path, "wb") as f: - f.write(response.data) - - return path - - def __deserialize_primitive(self, data, klass): - """Deserializes string to primitive type. - - :param data: str. - :param klass: class literal. - - :return: int, long, float, str, bool. - """ - try: - return klass(data) - except UnicodeEncodeError: - return six.text_type(data) - except TypeError: - return data - - def __deserialize_object(self, value): - """Return a original value. - - :return: object. - """ - return value - - def __deserialize_date(self, string): - """Deserializes string to date. - - :param string: str. - :return: date. - """ - try: - from dateutil.parser import parse - return parse(string).date() - except ImportError: - return string - except ValueError: - raise rest.ApiException( - status=0, - reason="Failed to parse `{0}` as date object".format(string) - ) - - def __deserialize_datatime(self, string): - """Deserializes string to datetime. - - The string should be in iso8601 datetime format. - - :param string: str. - :return: datetime. - """ - try: - from dateutil.parser import parse - return parse(string) - except ImportError: - return string - except ValueError: - raise rest.ApiException( - status=0, - reason=( - "Failed to parse `{0}` as datetime object" - .format(string) - ) - ) - - def __hasattr(self, object, name): - return name in object.__class__.__dict__ - - def __deserialize_model(self, data, klass): - """Deserializes list or dict to model. - - :param data: dict, list. - :param klass: class literal. - :return: model object. - """ - - if not klass.swagger_types and not self.__hasattr(klass, 'get_real_child_model'): - return data - - kwargs = {} - if klass.swagger_types is not None: - for attr, attr_type in six.iteritems(klass.swagger_types): - if (data is not None and - klass.attribute_map[attr] in data and - isinstance(data, (list, dict))): - value = data[klass.attribute_map[attr]] - kwargs[attr] = self.__deserialize(value, attr_type) - - instance = klass(**kwargs) - - if (isinstance(instance, dict) and - klass.swagger_types is not None and - isinstance(data, dict)): - for key, value in data.items(): - if key not in klass.swagger_types: - instance[key] = value - if self.__hasattr(instance, 'get_real_child_model'): - klass_name = instance.get_real_child_model(data) - if klass_name: - instance = self.__deserialize(data, klass_name) - return instance diff --git a/src/main/resources/mustache/python/api_doc.mustache b/src/main/resources/mustache/python/api_doc.mustache deleted file mode 100644 index 32c26d929d..0000000000 --- a/src/main/resources/mustache/python/api_doc.mustache +++ /dev/null @@ -1,85 +0,0 @@ -# {{packageName}}.{{classname}}{{#description}} -{{description}}{{/description}} - -All URIs are relative to *{{basePath}}* - -Method | HTTP request | Description -------------- | ------------- | ------------- -{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}} - -{{#operations}} -{{#operation}} -# **{{{operationId}}}** -> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#allParams}}{{#required}}{{{paramName}}}{{/required}}{{^required}}{{{paramName}}}={{{paramName}}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - -{{{summary}}}{{#notes}} - -{{{notes}}}{{/notes}} - -### Example -```python -from __future__ import print_function -import time -import {{{packageName}}} -from {{{packageName}}}.rest import ApiException -from pprint import pprint -{{#hasAuthMethods}}{{#authMethods}}{{#isBasic}} -# Configure HTTP basic authorization: {{{name}}} -configuration = {{{packageName}}}.Configuration() -configuration.username = 'YOUR_USERNAME' -configuration.password = 'YOUR_PASSWORD'{{/isBasic}}{{#isApiKey}} -# Configure API key authorization: {{{name}}} -configuration = {{{packageName}}}.Configuration() -configuration.api_key['{{{keyParamName}}}'] = 'YOUR_API_KEY' -# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed -# configuration.api_key_prefix['{{{keyParamName}}}'] = 'Bearer'{{/isApiKey}}{{#isOAuth}} -# Configure OAuth2 access token for authorization: {{{name}}} -configuration = {{{packageName}}}.Configuration() -configuration.access_token = 'YOUR_ACCESS_TOKEN'{{/isOAuth}}{{/authMethods}} - -# create an instance of the API class -api_instance = {{{packageName}}}.{{{classname}}}({{{packageName}}}.ApiClient(configuration)) -{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} -{{/allParams}} -{{/hasAuthMethods}} -{{^hasAuthMethods}} - -# create an instance of the API class -api_instance = {{{packageName}}}.{{{classname}}}() -{{#allParams}}{{paramName}} = {{{example}}} # {{{dataType}}} | {{{description}}}{{^required}} (optional){{/required}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} -{{/allParams}} -{{/hasAuthMethods}} - -try: -{{#summary}} # {{{.}}} -{{/summary}} {{#returnType}}api_response = {{/returnType}}api_instance.{{{operationId}}}({{#allParams}}{{#required}}{{paramName}}{{/required}}{{^required}}{{paramName}}={{paramName}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}} - pprint(api_response){{/returnType}} -except ApiException as e: - print("Exception when calling {{classname}}->{{operationId}}: %s\n" % e) -``` - -### Parameters -{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}} -Name | Type | Description | Notes -------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}} -{{#allParams}} **{{paramName}}** | {{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{baseType}}.md){{/isPrimitiveType}}{{/isFile}}| {{description}} | {{^required}}[optional] {{/required}}{{#defaultValue}}[default to {{defaultValue}}]{{/defaultValue}} -{{/allParams}} - -### Return type - -{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}[**{{{returnType}}}**]({{returnBaseType}}.md){{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}} - -### Authorization - -{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](../README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}} - -### HTTP request headers - - - **Content-Type**: {{#consumes}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} - - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/python/api_test.mustache b/src/main/resources/mustache/python/api_test.mustache deleted file mode 100644 index 90fafc15f3..0000000000 --- a/src/main/resources/mustache/python/api_test.mustache +++ /dev/null @@ -1,37 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -from __future__ import absolute_import - -import unittest - -import {{packageName}} -from {{apiPackage}}.{{classVarName}} import {{classname}} # noqa: E501 -from {{packageName}}.rest import ApiException - - -class {{#operations}}Test{{classname}}(unittest.TestCase): - """{{classname}} unit test stubs""" - - def setUp(self): - self.api = {{apiPackage}}.{{classVarName}}.{{classname}}() # noqa: E501 - - def tearDown(self): - pass - - {{#operation}} - def test_{{operationId}}(self): - """Test case for {{{operationId}}} - -{{#summary}} - {{{summary}}} # noqa: E501 -{{/summary}} - """ - pass - - {{/operation}} -{{/operations}} - -if __name__ == '__main__': - unittest.main() diff --git a/src/main/resources/mustache/python/asyncio/rest.mustache b/src/main/resources/mustache/python/asyncio/rest.mustache deleted file mode 100644 index 39003abfbf..0000000000 --- a/src/main/resources/mustache/python/asyncio/rest.mustache +++ /dev/null @@ -1,260 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -import io -import json -import logging -import re -import ssl - -import aiohttp -import certifi -# python 2 and python 3 compatibility library -from six.moves.urllib.parse import urlencode - -logger = logging.getLogger(__name__) - - -class RESTResponse(io.IOBase): - - def __init__(self, resp, data): - self.aiohttp_response = resp - self.status = resp.status - self.reason = resp.reason - self.data = data - - def getheaders(self): - """Returns a CIMultiDictProxy of the response headers.""" - return self.aiohttp_response.headers - - def getheader(self, name, default=None): - """Returns a given response header.""" - return self.aiohttp_response.headers.get(name, default) - - -class RESTClientObject(object): - - def __init__(self, configuration, pools_size=4, maxsize=4): - # maxsize is number of requests to host that are allowed in parallel - # ca_certs vs cert_file vs key_file - # http://stackoverflow.com/a/23957365/2985775 - - # ca_certs - if configuration.ssl_ca_cert: - ca_certs = configuration.ssl_ca_cert - else: - # if not set certificate file, use Mozilla's root certificates. - ca_certs = certifi.where() - - ssl_context = ssl.create_default_context(cafile=ca_certs) - if configuration.cert_file: - ssl_context.load_cert_chain( - configuration.cert_file, keyfile=configuration.key_file - ) - - connector = aiohttp.TCPConnector( - limit=maxsize, - ssl_context=ssl_context, - verify_ssl=configuration.verify_ssl - ) - - # https pool manager - if configuration.proxy: - self.pool_manager = aiohttp.ClientSession( - connector=connector, - proxy=configuration.proxy - ) - else: - self.pool_manager = aiohttp.ClientSession( - connector=connector - ) - - async def request(self, method, url, query_params=None, headers=None, - body=None, post_params=None, _preload_content=True, - _request_timeout=None): - """Execute request - - :param method: http request method - :param url: http request url - :param query_params: query parameters in the url - :param headers: http request headers - :param body: request json body, for `application/json` - :param post_params: request post parameters, - `application/x-www-form-urlencoded` - and `multipart/form-data` - :param _preload_content: this is a non-applicable field for - the AiohttpClient. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - """ - method = method.upper() - assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', - 'PATCH', 'OPTIONS'] - - if post_params and body: - raise ValueError( - "body parameter cannot be used with post_params parameter." - ) - - post_params = post_params or {} - headers = headers or {} - timeout = _request_timeout or 5 * 60 - - if 'Content-Type' not in headers: - headers['Content-Type'] = 'application/json' - - args = { - "method": method, - "url": url, - "timeout": timeout, - "headers": headers - } - - if query_params: - args["url"] += '?' + urlencode(query_params) - - # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` - if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: - if re.search('json', headers['Content-Type'], re.IGNORECASE): - if body is not None: - body = json.dumps(body) - args["data"] = body - elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 - args["data"] = aiohttp.FormData(post_params) - elif headers['Content-Type'] == 'multipart/form-data': - # must del headers['Content-Type'], or the correct - # Content-Type which generated by aiohttp - del headers['Content-Type'] - data = aiohttp.FormData() - for param in post_params: - k, v = param - if isinstance(v, tuple) and len(v) == 3: - data.add_field(k, - value=v[1], - filename=v[0], - content_type=v[2]) - else: - data.add_field(k, v) - args["data"] = data - - # Pass a `bytes` parameter directly in the body to support - # other content types than Json when `body` argument is provided - # in serialized form - elif isinstance(body, bytes): - args["data"] = body - else: - # Cannot generate the request from given parameters - msg = """Cannot prepare a request message for provided - arguments. Please check that your arguments match - declared content type.""" - raise ApiException(status=0, reason=msg) - - async with self.pool_manager.request(**args) as r: - data = await r.text() - r = RESTResponse(r, data) - - # log response body - logger.debug("response body: %s", r.data) - - if not 200 <= r.status <= 299: - raise ApiException(http_resp=r) - - return r - - async def GET(self, url, headers=None, query_params=None, - _preload_content=True, _request_timeout=None): - return (await self.request("GET", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params)) - - async def HEAD(self, url, headers=None, query_params=None, - _preload_content=True, _request_timeout=None): - return (await self.request("HEAD", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params)) - - async def OPTIONS(self, url, headers=None, query_params=None, - post_params=None, body=None, _preload_content=True, - _request_timeout=None): - return (await self.request("OPTIONS", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body)) - - async def DELETE(self, url, headers=None, query_params=None, body=None, - _preload_content=True, _request_timeout=None): - return (await self.request("DELETE", url, - headers=headers, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body)) - - async def POST(self, url, headers=None, query_params=None, - post_params=None, body=None, _preload_content=True, - _request_timeout=None): - return (await self.request("POST", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body)) - - async def PUT(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return (await self.request("PUT", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body)) - - async def PATCH(self, url, headers=None, query_params=None, - post_params=None, body=None, _preload_content=True, - _request_timeout=None): - return (await self.request("PATCH", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body)) - - -class ApiException(Exception): - - def __init__(self, status=None, reason=None, http_resp=None): - if http_resp: - self.status = http_resp.status - self.reason = http_resp.reason - self.body = http_resp.data - self.headers = http_resp.getheaders() - else: - self.status = status - self.reason = reason - self.body = None - self.headers = None - - def __str__(self): - """Custom error messages for exception""" - error_message = "({0})\nReason: {1}\n".format(self.status, self.reason) - if self.headers: - error_message += "HTTP response headers: {0}\n".format( - self.headers) - - if self.body: - error_message += "HTTP response body: {0}\n".format(self.body) - - return error_message diff --git a/src/main/resources/mustache/python/configuration.mustache b/src/main/resources/mustache/python/configuration.mustache deleted file mode 100644 index 84e6ad4d20..0000000000 --- a/src/main/resources/mustache/python/configuration.mustache +++ /dev/null @@ -1,260 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -from __future__ import absolute_import - -import copy -import logging -import multiprocessing -import sys -import urllib3 - -import six -from six.moves import http_client as httplib - - -class TypeWithDefault(type): - def __init__(cls, name, bases, dct): - super(TypeWithDefault, cls).__init__(name, bases, dct) - cls._default = None - - def __call__(cls): - if cls._default is None: - cls._default = type.__call__(cls) - return copy.copy(cls._default) - - def set_default(cls, default): - cls._default = copy.copy(default) - - -class Configuration(six.with_metaclass(TypeWithDefault, object)): - """NOTE: This class is auto generated by the swagger code generator program. - - Ref: https://github.com/swagger-api/swagger-codegen - Do not edit the class manually. - """ - - def __init__(self): - """Constructor""" - # Default Base url - self.host = "{{{basePath}}}" - # Temp file folder for downloading files - self.temp_folder_path = None - - # Authentication Settings - # dict to store API key(s) - self.api_key = {} - # dict to store API prefix (e.g. Bearer) - self.api_key_prefix = {} - # Username for HTTP basic authentication - self.username = "" - # Password for HTTP basic authentication - self.password = "" -{{#authMethods}}{{#isOAuth}} - # access token for OAuth - self.access_token = "" -{{/isOAuth}}{{/authMethods}} - # Logging Settings - self.logger = {} - self.logger["package_logger"] = logging.getLogger("{{packageName}}") - self.logger["urllib3_logger"] = logging.getLogger("urllib3") - # Log format - self.logger_format = '%(asctime)s %(levelname)s %(message)s' - # Log stream handler - self.logger_stream_handler = None - # Log file handler - self.logger_file_handler = None - # Debug file location - self.logger_file = None - # Debug switch - self.debug = False - - # SSL/TLS verification - # Set this to false to skip verifying SSL certificate when calling API - # from https server. - self.verify_ssl = True - # Set this to customize the certificate file to verify the peer. - self.ssl_ca_cert = None - # client certificate file - self.cert_file = None - # client key file - self.key_file = None - # Set this to True/False to enable/disable SSL hostname verification. - self.assert_hostname = None - - # urllib3 connection pool's maximum number of connections saved - # per pool. urllib3 uses 1 connection as default value, but this is - # not the best value when you are making a lot of possibly parallel - # requests to the same host, which is often the case here. - # cpu_count * 5 is used as default value to increase performance. - self.connection_pool_maxsize = multiprocessing.cpu_count() * 5 - - # Proxy URL - self.proxy = None - # Safe chars for path_param - self.safe_chars_for_path_param = '' - - @property - def logger_file(self): - """The logger file. - - If the logger_file is None, then add stream handler and remove file - handler. Otherwise, add file handler and remove stream handler. - - :param value: The logger_file path. - :type: str - """ - return self.__logger_file - - @logger_file.setter - def logger_file(self, value): - """The logger file. - - If the logger_file is None, then add stream handler and remove file - handler. Otherwise, add file handler and remove stream handler. - - :param value: The logger_file path. - :type: str - """ - self.__logger_file = value - if self.__logger_file: - # If set logging file, - # then add file handler and remove stream handler. - self.logger_file_handler = logging.FileHandler(self.__logger_file) - self.logger_file_handler.setFormatter(self.logger_formatter) - for _, logger in six.iteritems(self.logger): - logger.addHandler(self.logger_file_handler) - if self.logger_stream_handler: - logger.removeHandler(self.logger_stream_handler) - else: - # If not set logging file, - # then add stream handler and remove file handler. - self.logger_stream_handler = logging.StreamHandler() - self.logger_stream_handler.setFormatter(self.logger_formatter) - for _, logger in six.iteritems(self.logger): - logger.addHandler(self.logger_stream_handler) - if self.logger_file_handler: - logger.removeHandler(self.logger_file_handler) - - @property - def debug(self): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - return self.__debug - - @debug.setter - def debug(self, value): - """Debug status - - :param value: The debug status, True or False. - :type: bool - """ - self.__debug = value - if self.__debug: - # if debug status is True, turn on debug logging - for _, logger in six.iteritems(self.logger): - logger.setLevel(logging.DEBUG) - # turn on httplib debug - httplib.HTTPConnection.debuglevel = 1 - else: - # if debug status is False, turn off debug logging, - # setting log level to default `logging.WARNING` - for _, logger in six.iteritems(self.logger): - logger.setLevel(logging.WARNING) - # turn off httplib debug - httplib.HTTPConnection.debuglevel = 0 - - @property - def logger_format(self): - """The logger format. - - The logger_formatter will be updated when sets logger_format. - - :param value: The format string. - :type: str - """ - return self.__logger_format - - @logger_format.setter - def logger_format(self, value): - """The logger format. - - The logger_formatter will be updated when sets logger_format. - - :param value: The format string. - :type: str - """ - self.__logger_format = value - self.logger_formatter = logging.Formatter(self.__logger_format) - - def get_api_key_with_prefix(self, identifier): - """Gets API key (with prefix if set). - - :param identifier: The identifier of apiKey. - :return: The token for api key authentication. - """ - if (self.api_key.get(identifier) and - self.api_key_prefix.get(identifier)): - return self.api_key_prefix[identifier] + ' ' + self.api_key[identifier] # noqa: E501 - elif self.api_key.get(identifier): - return self.api_key[identifier] - - def get_basic_auth_token(self): - """Gets HTTP basic authentication header (string). - - :return: The token for basic HTTP authentication. - """ - return urllib3.util.make_headers( - basic_auth=self.username + ':' + self.password - ).get('authorization') - - def auth_settings(self): - """Gets Auth Settings dict for api client. - - :return: The Auth Settings information dict. - """ - return { -{{#authMethods}} -{{#isApiKey}} - '{{name}}': - { - 'type': 'api_key', - 'in': {{#isKeyInHeader}}'header'{{/isKeyInHeader}}{{#isKeyInQuery}}'query'{{/isKeyInQuery}}, - 'key': '{{keyParamName}}', - 'value': self.get_api_key_with_prefix('{{keyParamName}}') - }, -{{/isApiKey}} -{{#isBasic}} - '{{name}}': - { - 'type': 'basic', - 'in': 'header', - 'key': 'Authorization', - 'value': self.get_basic_auth_token() - }, -{{/isBasic}}{{#isOAuth}} - '{{name}}': - { - 'type': 'oauth2', - 'in': 'header', - 'key': 'Authorization', - 'value': 'Bearer ' + self.access_token - }, -{{/isOAuth}}{{/authMethods}} - } - - def to_debug_report(self): - """Gets the essential information for debugging. - - :return: The report for debugging. - """ - return "Python SDK Debug Report:\n"\ - "OS: {env}\n"\ - "Python Version: {pyversion}\n"\ - "Version of the API: {{version}}\n"\ - "SDK Package Version: {{packageVersion}}".\ - format(env=sys.platform, pyversion=sys.version) diff --git a/src/main/resources/mustache/python/gitignore.mustache b/src/main/resources/mustache/python/gitignore.mustache deleted file mode 100644 index a655050c26..0000000000 --- a/src/main/resources/mustache/python/gitignore.mustache +++ /dev/null @@ -1,64 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -venv/ -.python-version - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -#Ipython Notebook -.ipynb_checkpoints diff --git a/src/main/resources/mustache/python/model.mustache b/src/main/resources/mustache/python/model.mustache deleted file mode 100644 index e3dedc9bc5..0000000000 --- a/src/main/resources/mustache/python/model.mustache +++ /dev/null @@ -1,222 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -import pprint -import re # noqa: F401 - -import six -{{#imports}}{{#-first}} -{{/-first}} -{{import}} # noqa: F401,E501 -{{/imports}} - - -{{#models}} -{{#model}} -class {{classname}}({{#parent}}{{parent}}{{/parent}}{{^parent}}object{{/parent}}): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """{{#allowableValues}} - - """ - allowed enum values - """ -{{#enumVars}} - {{name}} = {{{value}}}{{^-last}} -{{/-last}} -{{/enumVars}}{{/allowableValues}} - - """ - Attributes: - swagger_types (dict): The key is attribute name - and the value is attribute type. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - """ - swagger_types = { -{{#vars}} - '{{name}}': '{{{datatype}}}'{{#hasMore}},{{/hasMore}} -{{/vars}} - } - - attribute_map = { -{{#vars}} - '{{name}}': '{{baseName}}'{{#hasMore}},{{/hasMore}} -{{/vars}} - } -{{#discriminator}} - - discriminator_value_class_map = { - {{#children}}'{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}': '{{{classname}}}'{{^-last}}, - {{/-last}}{{/children}} - } -{{/discriminator}} - - def __init__(self{{#vars}}, {{name}}={{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}None{{/defaultValue}}{{/vars}}): # noqa: E501 - """{{classname}} - a model defined in Swagger""" # noqa: E501 -{{#vars}}{{#-first}} -{{/-first}} - self._{{name}} = None -{{/vars}} - self.discriminator = {{#discriminator}}'{{discriminator.propertyName}}'{{/discriminator}}{{^discriminator}}None{{/discriminator}} -{{#vars}}{{#-first}} -{{/-first}} -{{#required}} - self.{{name}} = {{name}} -{{/required}} -{{^required}} - if {{name}} is not None: - self.{{name}} = {{name}} -{{/required}} -{{/vars}} - -{{#vars}} - @property - def {{name}}(self): - """Gets the {{name}} of this {{classname}}. # noqa: E501 - -{{#description}} - {{{description}}} # noqa: E501 -{{/description}} - - :return: The {{name}} of this {{classname}}. # noqa: E501 - :rtype: {{datatype}} - """ - return self._{{name}} - - @{{name}}.setter - def {{name}}(self, {{name}}): - """Sets the {{name}} of this {{classname}}. - -{{#description}} - {{{description}}} # noqa: E501 -{{/description}} - - :param {{name}}: The {{name}} of this {{classname}}. # noqa: E501 - :type: {{datatype}} - """ -{{#required}} - if {{name}} is None: - raise ValueError("Invalid value for `{{name}}`, must not be `None`") # noqa: E501 -{{/required}} -{{#isEnum}} -{{#isContainer}} - allowed_values = [{{#allowableValues}}{{#values}}{{#items.isString}}"{{/items.isString}}{{{this}}}{{#items.isString}}"{{/items.isString}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] # noqa: E501 -{{#isListContainer}} - if not set({{{name}}}).issubset(set(allowed_values)): - raise ValueError( - "Invalid values for `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 - .format(", ".join(map(str, set({{{name}}}) - set(allowed_values))), # noqa: E501 - ", ".join(map(str, allowed_values))) - ) -{{/isListContainer}} -{{#isMapContainer}} - if not set({{{name}}}.keys()).issubset(set(allowed_values)): - raise ValueError( - "Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 - .format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501 - ", ".join(map(str, allowed_values))) - ) -{{/isMapContainer}} -{{/isContainer}} -{{^isContainer}} - allowed_values = [{{#allowableValues}}{{#values}}{{#isString}}"{{/isString}}{{{this}}}{{#isString}}"{{/isString}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] # noqa: E501 - if {{{name}}} not in allowed_values: - raise ValueError( - "Invalid value for `{{{name}}}` ({0}), must be one of {1}" # noqa: E501 - .format({{{name}}}, allowed_values) - ) -{{/isContainer}} -{{/isEnum}} -{{^isEnum}} -{{#hasValidation}} -{{#maxLength}} - if {{name}} is not None and len({{name}}) > {{maxLength}}: - raise ValueError("Invalid value for `{{name}}`, length must be less than or equal to `{{maxLength}}`") # noqa: E501 -{{/maxLength}} -{{#minLength}} - if {{name}} is not None and len({{name}}) < {{minLength}}: - raise ValueError("Invalid value for `{{name}}`, length must be greater than or equal to `{{minLength}}`") # noqa: E501 -{{/minLength}} -{{#maximum}} - if {{name}} is not None and {{name}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}: # noqa: E501 - raise ValueError("Invalid value for `{{name}}`, must be a value less than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}`{{maximum}}`") # noqa: E501 -{{/maximum}} -{{#minimum}} - if {{name}} is not None and {{name}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}: # noqa: E501 - raise ValueError("Invalid value for `{{name}}`, must be a value greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}`{{minimum}}`") # noqa: E501 -{{/minimum}} -{{#pattern}} - if {{name}} is not None and not re.search(r'{{{vendorExtensions.x-regex}}}', {{name}}{{#vendorExtensions.x-modifiers}}{{#-first}}, flags={{/-first}}re.{{.}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}): # noqa: E501 - raise ValueError(r"Invalid value for `{{name}}`, must be a follow pattern or equal to `{{{pattern}}}`") # noqa: E501 -{{/pattern}} -{{#maxItems}} - if {{name}} is not None and len({{name}}) > {{maxItems}}: - raise ValueError("Invalid value for `{{name}}`, number of items must be less than or equal to `{{maxItems}}`") # noqa: E501 -{{/maxItems}} -{{#minItems}} - if {{name}} is not None and len({{name}}) < {{minItems}}: - raise ValueError("Invalid value for `{{name}}`, number of items must be greater than or equal to `{{minItems}}`") # noqa: E501 -{{/minItems}} -{{/hasValidation}} -{{/isEnum}} - - self._{{name}} = {{name}} - -{{/vars}} -{{#discriminator}} - def get_real_child_model(self, data): - """Returns the real base class specified by the discriminator""" - discriminator_value = data[self.discriminator].lower() - return self.discriminator_value_class_map.get(discriminator_value) - -{{/discriminator}} - def to_dict(self): - """Returns the model properties as a dict""" - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - if issubclass({{classname}}, dict): - for key, value in self.items(): - result[key] = value - - return result - - def to_str(self): - """Returns the string representation of the model""" - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - if not isinstance(other, {{classname}}): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/python/model_doc.mustache b/src/main/resources/mustache/python/model_doc.mustache deleted file mode 100644 index 569550df37..0000000000 --- a/src/main/resources/mustache/python/model_doc.mustache +++ /dev/null @@ -1,11 +0,0 @@ -{{#models}}{{#model}}# {{classname}} - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -{{#vars}}**{{name}}** | {{#isPrimitiveType}}**{{datatype}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{datatype}}**]({{complexType}}.md){{/isPrimitiveType}} | {{description}} | {{^required}}[optional] {{/required}}{{#readOnly}}[readonly] {{/readOnly}}{{#defaultValue}}[default to {{{.}}}]{{/defaultValue}} -{{/vars}} - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - -{{/model}}{{/models}} diff --git a/src/main/resources/mustache/python/model_test.mustache b/src/main/resources/mustache/python/model_test.mustache deleted file mode 100644 index 765e4f9c2c..0000000000 --- a/src/main/resources/mustache/python/model_test.mustache +++ /dev/null @@ -1,35 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -from __future__ import absolute_import - -import unittest - -{{#models}} -{{#model}} -import {{packageName}} -from {{modelPackage}}.{{classFilename}} import {{classname}} # noqa: E501 -from {{packageName}}.rest import ApiException - - -class Test{{classname}}(unittest.TestCase): - """{{classname}} unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def test{{classname}}(self): - """Test {{classname}}""" - # FIXME: construct object with mandatory attributes with example values - # model = {{packageName}}.models.{{classFilename}}.{{classname}}() # noqa: E501 - pass - -{{/model}} -{{/models}} - -if __name__ == '__main__': - unittest.main() diff --git a/src/main/resources/mustache/python/partial_header.mustache b/src/main/resources/mustache/python/partial_header.mustache deleted file mode 100644 index 513ad04cdb..0000000000 --- a/src/main/resources/mustache/python/partial_header.mustache +++ /dev/null @@ -1,13 +0,0 @@ -""" -{{#appName}} - {{{appName}}} -{{/appName}} - -{{#appDescription}} - {{{appDescription}}} # noqa: E501 -{{/appDescription}} - - {{#version}}OpenAPI spec version: {{{version}}}{{/version}} - {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} - Generated by: https://github.com/swagger-api/swagger-codegen.git -""" diff --git a/src/main/resources/mustache/python/requirements.mustache b/src/main/resources/mustache/python/requirements.mustache deleted file mode 100644 index bafdc07532..0000000000 --- a/src/main/resources/mustache/python/requirements.mustache +++ /dev/null @@ -1,5 +0,0 @@ -certifi >= 14.05.14 -six >= 1.10 -python_dateutil >= 2.5.3 -setuptools >= 21.0.0 -urllib3 >= 1.15.1 diff --git a/src/main/resources/mustache/python/rest.mustache b/src/main/resources/mustache/python/rest.mustache deleted file mode 100644 index ff9b019dc5..0000000000 --- a/src/main/resources/mustache/python/rest.mustache +++ /dev/null @@ -1,314 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -from __future__ import absolute_import - -import io -import json -import logging -import re -import ssl - -import certifi -# python 2 and python 3 compatibility library -import six -from six.moves.urllib.parse import urlencode - -try: - import urllib3 -except ImportError: - raise ImportError('Swagger python client requires urllib3.') - - -logger = logging.getLogger(__name__) - - -class RESTResponse(io.IOBase): - - def __init__(self, resp): - self.urllib3_response = resp - self.status = resp.status - self.reason = resp.reason - self.data = resp.data - - def getheaders(self): - """Returns a dictionary of the response headers.""" - return self.urllib3_response.getheaders() - - def getheader(self, name, default=None): - """Returns a given response header.""" - return self.urllib3_response.getheader(name, default) - - -class RESTClientObject(object): - - def __init__(self, configuration, pools_size=4, maxsize=None): - # urllib3.PoolManager will pass all kw parameters to connectionpool - # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/poolmanager.py#L75 # noqa: E501 - # https://github.com/shazow/urllib3/blob/f9409436f83aeb79fbaf090181cd81b784f1b8ce/urllib3/connectionpool.py#L680 # noqa: E501 - # maxsize is the number of requests to host that are allowed in parallel # noqa: E501 - # Custom SSL certificates and client certificates: http://urllib3.readthedocs.io/en/latest/advanced-usage.html # noqa: E501 - - # cert_reqs - if configuration.verify_ssl: - cert_reqs = ssl.CERT_REQUIRED - else: - cert_reqs = ssl.CERT_NONE - - # ca_certs - if configuration.ssl_ca_cert: - ca_certs = configuration.ssl_ca_cert - else: - # if not set certificate file, use Mozilla's root certificates. - ca_certs = certifi.where() - - addition_pool_args = {} - if configuration.assert_hostname is not None: - addition_pool_args['assert_hostname'] = configuration.assert_hostname # noqa: E501 - - if maxsize is None: - if configuration.connection_pool_maxsize is not None: - maxsize = configuration.connection_pool_maxsize - else: - maxsize = 4 - - # https pool manager - if configuration.proxy: - self.pool_manager = urllib3.ProxyManager( - num_pools=pools_size, - maxsize=maxsize, - cert_reqs=cert_reqs, - ca_certs=ca_certs, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - proxy_url=configuration.proxy, - **addition_pool_args - ) - else: - self.pool_manager = urllib3.PoolManager( - num_pools=pools_size, - maxsize=maxsize, - cert_reqs=cert_reqs, - ca_certs=ca_certs, - cert_file=configuration.cert_file, - key_file=configuration.key_file, - **addition_pool_args - ) - - def request(self, method, url, query_params=None, headers=None, - body=None, post_params=None, _preload_content=True, - _request_timeout=None): - """Perform requests. - - :param method: http request method - :param url: http request url - :param query_params: query parameters in the url - :param headers: http request headers - :param body: request json body, for `application/json` - :param post_params: request post parameters, - `application/x-www-form-urlencoded` - and `multipart/form-data` - :param _preload_content: if False, the urllib3.HTTPResponse object will - be returned without reading/decoding response - data. Default is True. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - """ - method = method.upper() - assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', - 'PATCH', 'OPTIONS'] - - if post_params and body: - raise ValueError( - "body parameter cannot be used with post_params parameter." - ) - - post_params = post_params or {} - headers = headers or {} - - timeout = None - if _request_timeout: - if isinstance(_request_timeout, (int, ) if six.PY3 else (int, long)): # noqa: E501,F821 - timeout = urllib3.Timeout(total=_request_timeout) - elif (isinstance(_request_timeout, tuple) and - len(_request_timeout) == 2): - timeout = urllib3.Timeout( - connect=_request_timeout[0], read=_request_timeout[1]) - - if 'Content-Type' not in headers: - headers['Content-Type'] = 'application/json' - - try: - # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` - if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: - if query_params: - url += '?' + urlencode(query_params) - if re.search('json', headers['Content-Type'], re.IGNORECASE): - request_body = None - if body is not None: - request_body = json.dumps(body) - r = self.pool_manager.request( - method, url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 - r = self.pool_manager.request( - method, url, - fields=post_params, - encode_multipart=False, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - elif headers['Content-Type'] == 'multipart/form-data': - # must del headers['Content-Type'], or the correct - # Content-Type which generated by urllib3 will be - # overwritten. - del headers['Content-Type'] - r = self.pool_manager.request( - method, url, - fields=post_params, - encode_multipart=True, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - # Pass a `string` parameter directly in the body to support - # other content types than Json when `body` argument is - # provided in serialized form - elif isinstance(body, str): - request_body = body - r = self.pool_manager.request( - method, url, - body=request_body, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - else: - # Cannot generate the request from given parameters - msg = """Cannot prepare a request message for provided - arguments. Please check that your arguments match - declared content type.""" - raise ApiException(status=0, reason=msg) - # For `GET`, `HEAD` - else: - r = self.pool_manager.request(method, url, - fields=query_params, - preload_content=_preload_content, - timeout=timeout, - headers=headers) - except urllib3.exceptions.SSLError as e: - msg = "{0}\n{1}".format(type(e).__name__, str(e)) - raise ApiException(status=0, reason=msg) - - if _preload_content: - r = RESTResponse(r) - - # In the python 3, the response.data is bytes. - # we need to decode it to string. - if six.PY3: - r.data = r.data.decode('utf8') - - # log response body - logger.debug("response body: %s", r.data) - - if not 200 <= r.status <= 299: - raise ApiException(http_resp=r) - - return r - - def GET(self, url, headers=None, query_params=None, _preload_content=True, - _request_timeout=None): - return self.request("GET", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params) - - def HEAD(self, url, headers=None, query_params=None, _preload_content=True, - _request_timeout=None): - return self.request("HEAD", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params) - - def OPTIONS(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("OPTIONS", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def DELETE(self, url, headers=None, query_params=None, body=None, - _preload_content=True, _request_timeout=None): - return self.request("DELETE", url, - headers=headers, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def POST(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("POST", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def PUT(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("PUT", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - def PATCH(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - return self.request("PATCH", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - - -class ApiException(Exception): - - def __init__(self, status=None, reason=None, http_resp=None): - if http_resp: - self.status = http_resp.status - self.reason = http_resp.reason - self.body = http_resp.data - self.headers = http_resp.getheaders() - else: - self.status = status - self.reason = reason - self.body = None - self.headers = None - - def __str__(self): - """Custom error messages for exception""" - error_message = "({0})\n"\ - "Reason: {1}\n".format(self.status, self.reason) - if self.headers: - error_message += "HTTP response headers: {0}\n".format( - self.headers) - - if self.body: - error_message += "HTTP response body: {0}\n".format(self.body) - - return error_message diff --git a/src/main/resources/mustache/python/setup.mustache b/src/main/resources/mustache/python/setup.mustache deleted file mode 100644 index e7107e9be9..0000000000 --- a/src/main/resources/mustache/python/setup.mustache +++ /dev/null @@ -1,43 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -from setuptools import setup, find_packages # noqa: H301 - -NAME = "{{{projectName}}}" -VERSION = "{{packageVersion}}" -{{#apiInfo}} -{{#apis}} -{{^hasMore}} -# To install the library, run the following -# -# python setup.py install -# -# prerequisite: setuptools -# http://pypi.python.org/pypi/setuptools - -REQUIRES = ["urllib3 >= 1.15", "six >= 1.10", "certifi", "python-dateutil"] -{{#asyncio}} -REQUIRES.append("aiohttp") -{{/asyncio}} -{{#tornado}} -REQUIRES.append("tornado") -{{/tornado}} - -setup( - name=NAME, - version=VERSION, - description="{{appName}}", - author_email="{{infoEmail}}", - url="{{packageUrl}}", - keywords=["Swagger", "{{appName}}"], - install_requires=REQUIRES, - packages=find_packages(), - include_package_data=True, - long_description="""\ - {{appDescription}} # noqa: E501 - """ -) -{{/hasMore}} -{{/apis}} -{{/apiInfo}} diff --git a/src/main/resources/mustache/python/test-requirements.mustache b/src/main/resources/mustache/python/test-requirements.mustache deleted file mode 100644 index 31f8d94d99..0000000000 --- a/src/main/resources/mustache/python/test-requirements.mustache +++ /dev/null @@ -1,11 +0,0 @@ -{{^asyncio}} -coverage>=4.0.3 -nose>=1.3.7 -{{/asyncio}} -{{#asyncio}} -pytest>=3.3.1 -pytest-cov>=2.5.1 -{{/asyncio}} -pluggy>=0.3.1 -py>=1.4.31 -randomize>=0.13 diff --git a/src/main/resources/mustache/python/tornado/rest.mustache b/src/main/resources/mustache/python/tornado/rest.mustache deleted file mode 100644 index bc74fbc295..0000000000 --- a/src/main/resources/mustache/python/tornado/rest.mustache +++ /dev/null @@ -1,255 +0,0 @@ -# coding: utf-8 - -{{>partial_header}} - -import io -import json -import logging -import re - -# python 2 and python 3 compatibility library -import six -from six.moves.urllib.parse import urlencode -import tornado -import tornado.gen -from tornado import httpclient -from urllib3.filepost import encode_multipart_formdata - -logger = logging.getLogger(__name__) - - -class RESTResponse(io.IOBase): - - def __init__(self, resp): - self.tornado_response = resp - self.status = resp.code - self.reason = resp.reason - - if resp.body: - # In Python 3, the response body is utf-8 encoded bytes. - if six.PY3: - self.data = resp.body.decode('utf-8') - else: - self.data = resp.body - else: - self.data = None - - def getheaders(self): - """Returns a CIMultiDictProxy of the response headers.""" - return self.tornado_response.headers - - def getheader(self, name, default=None): - """Returns a given response header.""" - return self.tornado_response.headers.get(name, default) - - -class RESTClientObject(object): - - def __init__(self, configuration, pools_size=4, maxsize=4): - # maxsize is number of requests to host that are allowed in parallel - - self.ca_certs = configuration.ssl_ca_cert - self.client_key = configuration.key_file - self.client_cert = configuration.cert_file - - self.proxy_port = self.proxy_host = None - - # https pool manager - if configuration.proxy: - self.proxy_port = 80 - self.proxy_host = configuration.proxy - - self.pool_manager = httpclient.AsyncHTTPClient() - - @tornado.gen.coroutine - def request(self, method, url, query_params=None, headers=None, body=None, - post_params=None, _preload_content=True, - _request_timeout=None): - """Execute Request - - :param method: http request method - :param url: http request url - :param query_params: query parameters in the url - :param headers: http request headers - :param body: request json body, for `application/json` - :param post_params: request post parameters, - `application/x-www-form-urlencoded` - and `multipart/form-data` - :param _preload_content: this is a non-applicable field for - the AiohttpClient. - :param _request_timeout: timeout setting for this request. If one - number provided, it will be total request - timeout. It can also be a pair (tuple) of - (connection, read) timeouts. - """ - method = method.upper() - assert method in ['GET', 'HEAD', 'DELETE', 'POST', 'PUT', - 'PATCH', 'OPTIONS'] - - if post_params and body: - raise ValueError( - "body parameter cannot be used with post_params parameter." - ) - - request = httpclient.HTTPRequest(url) - request.allow_nonstandard_methods = True - request.ca_certs = self.ca_certs - request.client_key = self.client_key - request.client_cert = self.client_cert - request.proxy_host = self.proxy_host - request.proxy_port = self.proxy_port - request.method = method - if headers: - request.headers = headers - if 'Content-Type' not in headers: - request.headers['Content-Type'] = 'application/json' - request.request_timeout = _request_timeout or 5 * 60 - - post_params = post_params or {} - - if query_params: - request.url += '?' + urlencode(query_params) - - # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` - if method in ['POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE']: - if re.search('json', headers['Content-Type'], re.IGNORECASE): - if body: - body = json.dumps(body) - request.body = body - elif headers['Content-Type'] == 'application/x-www-form-urlencoded': # noqa: E501 - request.body = urlencode(post_params) - elif headers['Content-Type'] == 'multipart/form-data': - multipart = encode_multipart_formdata(post_params) - request.body, headers['Content-Type'] = multipart - # Pass a `bytes` parameter directly in the body to support - # other content types than Json when `body` argument is provided - # in serialized form - elif isinstance(body, bytes): - request.body = body - else: - # Cannot generate the request from given parameters - msg = """Cannot prepare a request message for provided - arguments. Please check that your arguments match - declared content type.""" - raise ApiException(status=0, reason=msg) - - r = yield self.pool_manager.fetch(request, raise_error=False) - - if _preload_content: - - r = RESTResponse(r) - - # log response body - logger.debug("response body: %s", r.data) - - if not 200 <= r.status <= 299: - raise ApiException(http_resp=r) - - raise tornado.gen.Return(r) - - @tornado.gen.coroutine - def GET(self, url, headers=None, query_params=None, _preload_content=True, - _request_timeout=None): - result = yield self.request("GET", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params) - raise tornado.gen.Return(result) - - @tornado.gen.coroutine - def HEAD(self, url, headers=None, query_params=None, _preload_content=True, - _request_timeout=None): - result = yield self.request("HEAD", url, - headers=headers, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - query_params=query_params) - raise tornado.gen.Return(result) - - @tornado.gen.coroutine - def OPTIONS(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - result = yield self.request("OPTIONS", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - raise tornado.gen.Return(result) - - @tornado.gen.coroutine - def DELETE(self, url, headers=None, query_params=None, body=None, - _preload_content=True, _request_timeout=None): - result = yield self.request("DELETE", url, - headers=headers, - query_params=query_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - raise tornado.gen.Return(result) - - @tornado.gen.coroutine - def POST(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - result = yield self.request("POST", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - raise tornado.gen.Return(result) - - @tornado.gen.coroutine - def PUT(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - result = yield self.request("PUT", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - raise tornado.gen.Return(result) - - @tornado.gen.coroutine - def PATCH(self, url, headers=None, query_params=None, post_params=None, - body=None, _preload_content=True, _request_timeout=None): - result = yield self.request("PATCH", url, - headers=headers, - query_params=query_params, - post_params=post_params, - _preload_content=_preload_content, - _request_timeout=_request_timeout, - body=body) - raise tornado.gen.Return(result) - - -class ApiException(Exception): - - def __init__(self, status=None, reason=None, http_resp=None): - if http_resp: - self.status = http_resp.status - self.reason = http_resp.reason - self.body = http_resp.data - self.headers = http_resp.getheaders() - else: - self.status = status - self.reason = reason - self.body = None - self.headers = None - - def __str__(self): - """Custom error messages for exception""" - error_message = "({0})\nReason: {1}\n".format( - self.status, self.reason) - if self.headers: - error_message += "HTTP response headers: {0}\n".format( - self.headers) - - if self.body: - error_message += "HTTP response body: {0}\n".format(self.body) - - return error_message diff --git a/src/main/resources/mustache/python/tox.mustache b/src/main/resources/mustache/python/tox.mustache deleted file mode 100644 index 63d12fdeae..0000000000 --- a/src/main/resources/mustache/python/tox.mustache +++ /dev/null @@ -1,20 +0,0 @@ -[tox] -{{^asyncio}} -envlist = py27, py3 -{{/asyncio}} -{{#asyncio}} -envlist = py3 -{{/asyncio}} - -[testenv] -deps=-r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt - -commands= -{{^asyncio}} - nosetests \ - [] -{{/asyncio}} -{{#asyncio}} - pytest -v --cov petstore_api -{{/asyncio}} diff --git a/src/main/resources/mustache/python/travis.mustache b/src/main/resources/mustache/python/travis.mustache deleted file mode 100644 index 86211e2d4a..0000000000 --- a/src/main/resources/mustache/python/travis.mustache +++ /dev/null @@ -1,14 +0,0 @@ -# ref: https://docs.travis-ci.com/user/languages/python -language: python -python: - - "2.7" - - "3.2" - - "3.3" - - "3.4" - - "3.5" - #- "3.5-dev" # 3.5 development branch - #- "nightly" # points to the latest development branch e.g. 3.6-dev -# command to install dependencies -install: "pip install -r requirements.txt" -# command to run tests -script: nosetests diff --git a/src/main/resources/mustache/pythonFlaskConnexion/Dockerfile.mustache b/src/main/resources/mustache/pythonFlaskConnexion/Dockerfile.mustache deleted file mode 100644 index f040d41ad6..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/Dockerfile.mustache +++ /dev/null @@ -1,31 +0,0 @@ -{{#supportPython2}} -FROM python:2-alpine -{{/supportPython2}} -{{^supportPython2}} -FROM python:3-alpine -{{/supportPython2}} - -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app - -COPY requirements.txt /usr/src/app/ - -{{#supportPython2}} -RUN pip install --no-cache-dir -r requirements.txt -{{/supportPython2}} -{{^supportPython2}} -RUN pip3 install --no-cache-dir -r requirements.txt -{{/supportPython2}} - -COPY . /usr/src/app - -EXPOSE {{serverPort}} - -{{#supportPython2}} -ENTRYPOINT ["python"] -{{/supportPython2}} -{{^supportPython2}} -ENTRYPOINT ["python3"] -{{/supportPython2}} - -CMD ["-m", "{{packageName}}"] \ No newline at end of file diff --git a/src/main/resources/mustache/pythonFlaskConnexion/README.mustache b/src/main/resources/mustache/pythonFlaskConnexion/README.mustache deleted file mode 100644 index b73b9e311b..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/README.mustache +++ /dev/null @@ -1,60 +0,0 @@ -# Swagger generated server - -## Overview -This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the -[OpenAPI-Spec](https://github.com/swagger-api/swagger-core/wiki) from a remote server, you can easily generate a server stub. This -is an example of building a swagger-enabled Flask server. - -This example uses the [Connexion](https://github.com/zalando/connexion) library on top of Flask. - -## Requirements -{{#supportPython2}} -Python 2.7+ -{{/supportPython2}} -{{^supportPython2}} -Python 3.5.2+ -{{/supportPython2}} - -## Usage -To run the server, please execute the following from the root directory: - -``` -{{#supportPython2}} -pip install -r requirements.txt -python -m {{packageName}} -{{/supportPython2}} -{{^supportPython2}} -pip3 install -r requirements.txt -python3 -m {{packageName}} -{{/supportPython2}} -``` - -and open your browser to here: - -``` -http://localhost:{{serverPort}}{{contextPath}}/ui/ -``` - -Your Swagger definition lives here: - -``` -http://localhost:{{serverPort}}{{contextPath}}/swagger.json -``` - -To launch the integration tests, use tox: -``` -sudo pip install tox -tox -``` - -## Running with Docker - -To run the server on a Docker container, please execute the following from the root directory: - -```bash -# building the image -docker build -t {{packageName}} . - -# starting up a container -docker run -p {{serverPort}}:{{serverPort}} {{packageName}} -``` \ No newline at end of file diff --git a/src/main/resources/mustache/pythonFlaskConnexion/__init__.mustache b/src/main/resources/mustache/pythonFlaskConnexion/__init__.mustache deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/main/resources/mustache/pythonFlaskConnexion/__init__model.mustache b/src/main/resources/mustache/pythonFlaskConnexion/__init__model.mustache deleted file mode 100644 index 98b56e3d15..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/__init__model.mustache +++ /dev/null @@ -1,7 +0,0 @@ -# coding: utf-8 - -# flake8: noqa -from __future__ import absolute_import -# import models into model package -{{#models}}{{#model}}from {{modelPackage}}.{{classFilename}} import {{classname}}{{/model}} -{{/models}} \ No newline at end of file diff --git a/src/main/resources/mustache/pythonFlaskConnexion/__init__test.mustache b/src/main/resources/mustache/pythonFlaskConnexion/__init__test.mustache deleted file mode 100644 index 9cea80bc63..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/__init__test.mustache +++ /dev/null @@ -1,16 +0,0 @@ -import logging - -import connexion -from flask_testing import TestCase - -from {{packageName}}.encoder import JSONEncoder - - -class BaseTestCase(TestCase): - - def create_app(self): - logging.getLogger('connexion.operation').setLevel('ERROR') - app = connexion.App(__name__, specification_dir='../swagger/') - app.app.json_encoder = JSONEncoder - app.add_api('swagger.yaml') - return app.app diff --git a/src/main/resources/mustache/pythonFlaskConnexion/__main__.mustache b/src/main/resources/mustache/pythonFlaskConnexion/__main__.mustache deleted file mode 100644 index 1da357d70f..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/__main__.mustache +++ /dev/null @@ -1,21 +0,0 @@ -{{#supportPython2}} -#!/usr/bin/env python -{{/supportPython2}} -{{^supportPython2}} -#!/usr/bin/env python3 -{{/supportPython2}} - -import connexion - -from {{packageName}} import encoder - - -def main(): - app = connexion.App(__name__, specification_dir='./swagger/') - app.app.json_encoder = encoder.JSONEncoder - app.add_api('swagger.yaml', arguments={'title': '{{appName}}'}, pythonic_params=True) - app.run(port={{serverPort}}) - - -if __name__ == '__main__': - main() diff --git a/src/main/resources/mustache/pythonFlaskConnexion/authorization_controller.mustache b/src/main/resources/mustache/pythonFlaskConnexion/authorization_controller.mustache deleted file mode 100644 index 723357e74b..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/authorization_controller.mustache +++ /dev/null @@ -1,31 +0,0 @@ -from typing import List -""" -controller generated to handled auth operation described at: -https://connexion.readthedocs.io/en/latest/security.html -""" -{{#authMethods}} -{{#isApiKey}} -def check_{{name}}(api_key, required_scopes): - return {'test_key': 'test_value'} - -{{/isApiKey}} -{{#isBasic}} -def check_{{name}}(username, password, required_scopes): - return {'test_key': 'test_value'} - -{{/isBasic}} -{{#isBearer}} -def check_{{name}}(token): - return {'test_key': 'test_value'} - -{{/isBearer}} -{{#isOAuth}} -def check_{{name}}(token): - return {'scopes': ['read:pets', 'write:pets'], 'uid': 'test_value'} - -def validate_scope_{{name}}(required_scopes, token_scopes): - return set(required_scopes).issubset(set(token_scopes)) - -{{/isOAuth}} -{{/authMethods}} - diff --git a/src/main/resources/mustache/pythonFlaskConnexion/base_model_.mustache b/src/main/resources/mustache/pythonFlaskConnexion/base_model_.mustache deleted file mode 100644 index 54517a06d5..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/base_model_.mustache +++ /dev/null @@ -1,73 +0,0 @@ -import pprint - -import six -{{^supportPython2}} -import typing -{{/supportPython2}} - -from {{packageName}} import util -{{^supportPython2}} - -T = typing.TypeVar('T') -{{/supportPython2}} - - -class Model(object): - # swaggerTypes: The key is attribute name and the - # value is attribute type. - swagger_types = {} - - # attributeMap: The key is attribute name and the - # value is json key in definition. - attribute_map = {} - - @classmethod - def from_dict(cls{{^supportPython2}}: typing.Type[T]{{/supportPython2}}, dikt){{^supportPython2}} -> T{{/supportPython2}}: - """Returns the dict as a model""" - return util.deserialize_model(dikt, cls) - - def to_dict(self): - """Returns the model properties as a dict - - :rtype: dict - """ - result = {} - - for attr, _ in six.iteritems(self.swagger_types): - value = getattr(self, attr) - if isinstance(value, list): - result[attr] = list(map( - lambda x: x.to_dict() if hasattr(x, "to_dict") else x, - value - )) - elif hasattr(value, "to_dict"): - result[attr] = value.to_dict() - elif isinstance(value, dict): - result[attr] = dict(map( - lambda item: (item[0], item[1].to_dict()) - if hasattr(item[1], "to_dict") else item, - value.items() - )) - else: - result[attr] = value - - return result - - def to_str(self): - """Returns the string representation of the model - - :rtype: str - """ - return pprint.pformat(self.to_dict()) - - def __repr__(self): - """For `print` and `pprint`""" - return self.to_str() - - def __eq__(self, other): - """Returns true if both objects are equal""" - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - """Returns true if both objects are not equal""" - return not self == other diff --git a/src/main/resources/mustache/pythonFlaskConnexion/controller.mustache b/src/main/resources/mustache/pythonFlaskConnexion/controller.mustache deleted file mode 100644 index 243da33e57..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/controller.mustache +++ /dev/null @@ -1,112 +0,0 @@ -import connexion -import six - -{{#imports}}{{import}} # noqa: E501 -{{/imports}} -from {{packageName}} import util -{{#operations}} -{{#operation}} - - -def {{operationId}}({{#allParams}}{{paramName}}{{^required}}=None{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}): # noqa: E501 - """{{#summary}}{{.}}{{/summary}}{{^summary}}{{operationId}}{{/summary}} - - {{#notes}}{{.}}{{/notes}} # noqa: E501 - - {{#allParams}} - :param {{paramName}}: {{description}} - {{^isContainer}} - {{#isPrimitiveType}} - :type {{paramName}}: {{>param_type}} - {{/isPrimitiveType}} - {{#isUuid}} - :type {{paramName}}: {{>param_type}} - {{/isUuid}} - {{^isPrimitiveType}} - {{#isFile}} - :type {{paramName}}: werkzeug.datastructures.FileStorage - {{/isFile}} - {{^isFile}} - {{^isUuid}} - :type {{paramName}}: dict | bytes - {{/isUuid}} - {{/isFile}} - {{/isPrimitiveType}} - {{/isContainer}} - {{#isListContainer}} - {{#items}} - {{#isPrimitiveType}} - :type {{paramName}}: List[{{>param_type}}] - {{/isPrimitiveType}} - {{^isPrimitiveType}} - :type {{paramName}}: list | bytes - {{/isPrimitiveType}} - {{/items}} - {{/isListContainer}} - {{#isMapContainer}} - {{#items}} - {{#isPrimitiveType}} - :type {{paramName}}: Dict[str, {{>param_type}}] - {{/isPrimitiveType}} - {{^isPrimitiveType}} - :type {{paramName}}: dict | bytes - {{/isPrimitiveType}} - {{/items}} - {{/isMapContainer}} - {{/allParams}} - - :rtype: {{#returnType}}{{.}}{{/returnType}}{{^returnType}}None{{/returnType}} - """ - {{#allParams}} - {{^isContainer}} - {{#isDate}} - {{paramName}} = util.deserialize_date({{paramName}}) - {{/isDate}} - {{#isDateTime}} - {{paramName}} = util.deserialize_datetime({{paramName}}) - {{/isDateTime}} - {{^isPrimitiveType}} - {{^isFile}} - {{^isUuid}} - if connexion.request.is_json: - {{paramName}} = {{baseType}}.from_dict(connexion.request.get_json()) # noqa: E501 - {{/isUuid}} - {{/isFile}} - {{/isPrimitiveType}} - {{/isContainer}} - {{#isListContainer}} - {{#items}} - {{#isDate}} - if connexion.request.is_json: - {{paramName}} = [util.deserialize_date(s) for s in connexion.request.get_json()] # noqa: E501 - {{/isDate}} - {{#isDateTime}} - if connexion.request.is_json: - {{paramName}} = [util.deserialize_datetime(s) for s in connexion.request.get_json()] # noqa: E501 - {{/isDateTime}} - {{#complexType}} - if connexion.request.is_json: - {{paramName}} = [{{complexType}}.from_dict(d) for d in connexion.request.get_json()] # noqa: E501 - {{/complexType}} - {{/items}} - {{/isListContainer}} - {{#isMapContainer}} - {{#items}} - {{#isDate}} - if connexion.request.is_json: - {{paramName}} = {k: util.deserialize_date(v) for k, v in six.iteritems(connexion.request.get_json())} # noqa: E501 - {{/isDate}} - {{#isDateTime}} - if connexion.request.is_json: - {{paramName}} = {k: util.deserialize_datetime(v) for k, v in six.iteritems(connexion.request.get_json())} # noqa: E501 - {{/isDateTime}} - {{#complexType}} - if connexion.request.is_json: - {{paramName}} = {k: {{baseType}}.from_dict(v) for k, v in six.iteritems(connexion.request.get_json())} # noqa: E501 - {{/complexType}} - {{/items}} - {{/isMapContainer}} - {{/allParams}} - return 'do some magic!' -{{/operation}} -{{/operations}} diff --git a/src/main/resources/mustache/pythonFlaskConnexion/controller_test.mustache b/src/main/resources/mustache/pythonFlaskConnexion/controller_test.mustache deleted file mode 100644 index a41b12f2c2..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/controller_test.mustache +++ /dev/null @@ -1,51 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import - -from flask import json -from six import BytesIO - -{{#imports}}{{import}} # noqa: E501 -{{/imports}} -from {{packageName}}.test import BaseTestCase - - -class {{#operations}}Test{{classname}}(BaseTestCase): - """{{classname}} integration test stubs""" - - {{#operation}} - def test_{{operationId}}(self): - """Test case for {{{operationId}}} - - {{{summary}}} - """ - {{#bodyParam}} - {{paramName}} = {{{example}}} - {{/bodyParam}} - {{#queryParams}} - {{#-first}}query_string = [{{/-first}}{{^-first}} {{/-first}}('{{paramName}}', {{{example}}}){{#hasMore}},{{/hasMore}}{{#-last}}]{{/-last}} - {{/queryParams}} - {{#headerParams}} - {{#-first}}headers = [{{/-first}}{{^-first}} {{/-first}}('{{paramName}}', {{{example}}}){{#hasMore}},{{/hasMore}}{{#-last}}]{{/-last}} - {{/headerParams}} - {{#formParams}} - {{#-first}}data = dict({{/-first}}{{^-first}} {{/-first}}{{paramName}}={{{example}}}{{#hasMore}},{{/hasMore}}{{#-last}}){{/-last}} - {{/formParams}} - response = self.client.open( - '{{#contextPath}}{{{.}}}{{/contextPath}}{{{path}}}'{{#pathParams}}{{#-first}}.format({{/-first}}{{paramName}}={{{example}}}{{#hasMore}}, {{/hasMore}}{{^hasMore}}){{/hasMore}}{{/pathParams}}, - method='{{httpMethod}}'{{#bodyParam}}, - data=json.dumps({{paramName}}){{^consumes}}, - content_type='application/json'{{/consumes}}{{/bodyParam}}{{#headerParams}}{{#-first}}, - headers=headers{{/-first}}{{/headerParams}}{{#formParams}}{{#-first}}, - data=data{{/-first}}{{/formParams}}{{#consumes}}{{#-first}}, - content_type='{{{mediaType}}}'{{/-first}}{{/consumes}}{{#queryParams}}{{#-first}}, - query_string=query_string{{/-first}}{{/queryParams}}) - self.assert200(response, - 'Response body is : ' + response.data.decode('utf-8')) - - {{/operation}} -{{/operations}} - -if __name__ == '__main__': - import unittest - unittest.main() diff --git a/src/main/resources/mustache/pythonFlaskConnexion/dockerignore.mustache b/src/main/resources/mustache/pythonFlaskConnexion/dockerignore.mustache deleted file mode 100644 index cdd823e64e..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/dockerignore.mustache +++ /dev/null @@ -1,72 +0,0 @@ -.travis.yaml -.swagger-codegen-ignore -README.md -tox.ini -git_push.sh -test-requirements.txt -setup.py - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -venv/ -.python-version - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -#Ipython Notebook -.ipynb_checkpoints diff --git a/src/main/resources/mustache/pythonFlaskConnexion/encoder.mustache b/src/main/resources/mustache/pythonFlaskConnexion/encoder.mustache deleted file mode 100644 index e303a0e41a..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/encoder.mustache +++ /dev/null @@ -1,20 +0,0 @@ -from connexion.apps.flask_app import FlaskJSONEncoder -import six - -from {{modelPackage}}.base_model_ import Model - - -class JSONEncoder(FlaskJSONEncoder): - include_nulls = False - - def default(self, o): - if isinstance(o, Model): - dikt = {} - for attr, _ in six.iteritems(o.swagger_types): - value = getattr(o, attr) - if value is None and not self.include_nulls: - continue - attr = o.attribute_map[attr] - dikt[attr] = value - return dikt - return FlaskJSONEncoder.default(self, o) diff --git a/src/main/resources/mustache/pythonFlaskConnexion/git_push.sh.mustache b/src/main/resources/mustache/pythonFlaskConnexion/git_push.sh.mustache deleted file mode 100755 index f65b794638..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/git_push.sh.mustache +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="{{{gitUserId}}}" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="{{{gitRepoId}}}" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="{{{releaseNote}}}" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/src/main/resources/mustache/pythonFlaskConnexion/gitignore.mustache b/src/main/resources/mustache/pythonFlaskConnexion/gitignore.mustache deleted file mode 100644 index a655050c26..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/gitignore.mustache +++ /dev/null @@ -1,64 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -venv/ -.python-version - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -#Ipython Notebook -.ipynb_checkpoints diff --git a/src/main/resources/mustache/pythonFlaskConnexion/model.mustache b/src/main/resources/mustache/pythonFlaskConnexion/model.mustache deleted file mode 100644 index 3f4c62fb1b..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/model.mustache +++ /dev/null @@ -1,161 +0,0 @@ -# coding: utf-8 - -from __future__ import absolute_import -from datetime import date, datetime # noqa: F401 - -from typing import List, Dict # noqa: F401 - -from {{packageName}}.{{modelPackage}}.base_model_ import Model -{{#imports}}{{import}} # noqa: F401,E501 -{{/imports}} -from {{packageName}} import util - - -{{#models}} -{{#model}} -class {{classname}}(Model): - """NOTE: This class is auto generated by the swagger code generator program. - - Do not edit the class manually. - """{{#allowableValues}} - - """ - allowed enum values - """ -{{#enumVars}} - {{name}} = {{{value}}}{{^-last}} -{{/-last}} -{{/enumVars}}{{/allowableValues}} - - def __init__(self{{#vars}}, {{name}}{{^supportPython2}}: {{datatype}}{{/supportPython2}}={{#defaultValue}}{{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}None{{/defaultValue}}{{/vars}}): # noqa: E501 - """{{classname}} - a model defined in Swagger - - {{#vars}} - :param {{name}}: The {{name}} of this {{classname}}. # noqa: E501 - :type {{name}}: {{datatype}} - {{/vars}} - """ - self.swagger_types = { -{{#vars}} - '{{name}}': {{{datatype}}}{{#hasMore}},{{/hasMore}} -{{/vars}} - } - - self.attribute_map = { -{{#vars}} - '{{name}}': '{{baseName}}'{{#hasMore}},{{/hasMore}} -{{/vars}} - } -{{#vars}}{{#-first}} -{{/-first}} - self._{{name}} = {{name}} -{{/vars}} - - @classmethod - def from_dict(cls, dikt){{^supportPython2}} -> '{{classname}}'{{/supportPython2}}: - """Returns the dict as a model - - :param dikt: A dict. - :type: dict - :return: The {{name}} of this {{classname}}. # noqa: E501 - :rtype: {{classname}} - """ - return util.deserialize_model(dikt, cls){{#vars}}{{#-first}} - -{{/-first}} - @property - def {{name}}(self){{^supportPython2}} -> {{datatype}}{{/supportPython2}}: - """Gets the {{name}} of this {{classname}}. - - {{#description}} - {{{description}}} # noqa: E501 - {{/description}} - - :return: The {{name}} of this {{classname}}. - :rtype: {{datatype}} - """ - return self._{{name}} - - @{{name}}.setter - def {{name}}(self, {{name}}{{^supportPython2}}: {{datatype}}{{/supportPython2}}): - """Sets the {{name}} of this {{classname}}. - - {{#description}} - {{{description}}} # noqa: E501 - {{/description}} - - :param {{name}}: The {{name}} of this {{classname}}. - :type {{name}}: {{datatype}} - """ -{{#isEnum}} - allowed_values = [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}] # noqa: E501 -{{#isContainer}} -{{#isListContainer}} - if not set({{{name}}}).issubset(set(allowed_values)): - raise ValueError( - "Invalid values for `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 - .format(", ".join(map(str, set({{{name}}}) - set(allowed_values))), # noqa: E501 - ", ".join(map(str, allowed_values))) - ) -{{/isListContainer}} -{{#isMapContainer}} - if not set({{{name}}}.keys()).issubset(set(allowed_values)): - raise ValueError( - "Invalid keys in `{{{name}}}` [{0}], must be a subset of [{1}]" # noqa: E501 - .format(", ".join(map(str, set({{{name}}}.keys()) - set(allowed_values))), # noqa: E501 - ", ".join(map(str, allowed_values))) - ) -{{/isMapContainer}} -{{/isContainer}} -{{^isContainer}} - if {{{name}}} not in allowed_values: - raise ValueError( - "Invalid value for `{{{name}}}` ({0}), must be one of {1}" - .format({{{name}}}, allowed_values) - ) -{{/isContainer}} -{{/isEnum}} -{{^isEnum}} -{{#required}} - if {{name}} is None: - raise ValueError("Invalid value for `{{name}}`, must not be `None`") # noqa: E501 -{{/required}} -{{#hasValidation}} -{{#maxLength}} - if {{name}} is not None and len({{name}}) > {{maxLength}}: - raise ValueError("Invalid value for `{{name}}`, length must be less than or equal to `{{maxLength}}`") # noqa: E501 -{{/maxLength}} -{{#minLength}} - if {{name}} is not None and len({{name}}) < {{minLength}}: - raise ValueError("Invalid value for `{{name}}`, length must be greater than or equal to `{{minLength}}`") # noqa: E501 -{{/minLength}} -{{#maximum}} - if {{name}} is not None and {{name}} >{{#exclusiveMaximum}}={{/exclusiveMaximum}} {{maximum}}: # noqa: E501 - raise ValueError("Invalid value for `{{name}}`, must be a value less than {{^exclusiveMaximum}}or equal to {{/exclusiveMaximum}}`{{maximum}}`") # noqa: E501 -{{/maximum}} -{{#minimum}} - if {{name}} is not None and {{name}} <{{#exclusiveMinimum}}={{/exclusiveMinimum}} {{minimum}}: # noqa: E501 - raise ValueError("Invalid value for `{{name}}`, must be a value greater than {{^exclusiveMinimum}}or equal to {{/exclusiveMinimum}}`{{minimum}}`") # noqa: E501 -{{/minimum}} -{{#pattern}} - if {{name}} is not None and not re.search(r'{{{vendorExtensions.x-regex}}}', {{name}}{{#vendorExtensions.x-modifiers}}{{#-first}}, flags={{/-first}}re.{{.}}{{^-last}} | {{/-last}}{{/vendorExtensions.x-modifiers}}): # noqa: E501 - raise ValueError("Invalid value for `{{name}}`, must be a follow pattern or equal to `{{{pattern}}}`") # noqa: E501 -{{/pattern}} -{{#maxItems}} - if {{name}} is not None and len({{name}}) > {{maxItems}}: - raise ValueError("Invalid value for `{{name}}`, number of items must be less than or equal to `{{maxItems}}`") # noqa: E501 -{{/maxItems}} -{{#minItems}} - if {{name}} is not None and len({{name}}) < {{minItems}}: - raise ValueError("Invalid value for `{{name}}`, number of items must be greater than or equal to `{{minItems}}`") # noqa: E501 -{{/minItems}} -{{/hasValidation}} -{{/isEnum}} - - self._{{name}} = {{name}}{{^-last}} - -{{/-last}} -{{/vars}} - -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/pythonFlaskConnexion/param_type.mustache b/src/main/resources/mustache/pythonFlaskConnexion/param_type.mustache deleted file mode 100644 index 21e7e07ec5..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/param_type.mustache +++ /dev/null @@ -1 +0,0 @@ -{{#isString}}str{{/isString}}{{#isInteger}}int{{/isInteger}}{{#isLong}}int{{/isLong}}{{#isFloat}}float{{/isFloat}}{{#isDouble}}float{{/isDouble}}{{#isByteArray}}str{{/isByteArray}}{{#isBinary}}str{{/isBinary}}{{#isBoolean}}bool{{/isBoolean}}{{#isDate}}str{{/isDate}}{{#isDateTime}}str{{/isDateTime}} \ No newline at end of file diff --git a/src/main/resources/mustache/pythonFlaskConnexion/requirements.mustache b/src/main/resources/mustache/pythonFlaskConnexion/requirements.mustache deleted file mode 100644 index 82d82c1a49..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/requirements.mustache +++ /dev/null @@ -1,6 +0,0 @@ -connexion == 2.2.0 -python_dateutil == 2.6.0 -{{#supportPython2}} -typing == 3.5.2.2 -{{/supportPython2}} -setuptools >= 21.0.0 diff --git a/src/main/resources/mustache/pythonFlaskConnexion/setup.mustache b/src/main/resources/mustache/pythonFlaskConnexion/setup.mustache deleted file mode 100644 index 56f8bc1ec1..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/setup.mustache +++ /dev/null @@ -1,35 +0,0 @@ -# coding: utf-8 - -import sys -from setuptools import setup, find_packages - -NAME = "{{packageName}}" -VERSION = "{{packageVersion}}" -{{#apiInfo}}{{#apis}}{{^hasMore}} -# To install the library, run the following -# -# python setup.py install -# -# prerequisite: setuptools -# http://pypi.python.org/pypi/setuptools - -REQUIRES = ["connexion"] - -setup( - name=NAME, - version=VERSION, - description="{{appName}}", - author_email="{{infoEmail}}", - url="{{packageUrl}}", - keywords=["Swagger", "{{appName}}"], - install_requires=REQUIRES, - packages=find_packages(), - package_data={'': ['swagger/swagger.yaml']}, - include_package_data=True, - entry_points={ - 'console_scripts': ['{{packageName}}={{packageName}}.__main__:main']}, - long_description="""\ - {{appDescription}} - """ -) -{{/hasMore}}{{/apis}}{{/apiInfo}} diff --git a/src/main/resources/mustache/pythonFlaskConnexion/swagger.mustache b/src/main/resources/mustache/pythonFlaskConnexion/swagger.mustache deleted file mode 100644 index 34fbb53f33..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/swagger.mustache +++ /dev/null @@ -1 +0,0 @@ -{{{openapi-yaml}}} diff --git a/src/main/resources/mustache/pythonFlaskConnexion/test-requirements.mustache b/src/main/resources/mustache/pythonFlaskConnexion/test-requirements.mustache deleted file mode 100644 index 7f8d96e6b4..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/test-requirements.mustache +++ /dev/null @@ -1,6 +0,0 @@ -flask_testing==0.6.1 -coverage>=4.0.3 -nose>=1.3.7 -pluggy>=0.3.1 -py>=1.4.31 -randomize>=0.13 diff --git a/src/main/resources/mustache/pythonFlaskConnexion/tox.mustache b/src/main/resources/mustache/pythonFlaskConnexion/tox.mustache deleted file mode 100644 index 3efa994317..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/tox.mustache +++ /dev/null @@ -1,10 +0,0 @@ -[tox] -envlist = {{#supportPython2}}py27, {{/supportPython2}}py35 - -[testenv] -deps=-r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt - -commands= - nosetests \ - [] \ No newline at end of file diff --git a/src/main/resources/mustache/pythonFlaskConnexion/travis.mustache b/src/main/resources/mustache/pythonFlaskConnexion/travis.mustache deleted file mode 100644 index 167826e42b..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/travis.mustache +++ /dev/null @@ -1,16 +0,0 @@ -# ref: https://docs.travis-ci.com/user/languages/python -language: python -python: -{{#supportPython2}} - - "2.7" -{{/supportPython2}} - - "3.2" - - "3.3" - - "3.4" - - "3.5" - #- "3.5-dev" # 3.5 development branch - #- "nightly" # points to the latest development branch e.g. 3.6-dev -# command to install dependencies -install: "pip install -r requirements.txt" -# command to run tests -script: nosetests diff --git a/src/main/resources/mustache/pythonFlaskConnexion/util.mustache b/src/main/resources/mustache/pythonFlaskConnexion/util.mustache deleted file mode 100644 index 527d1424c3..0000000000 --- a/src/main/resources/mustache/pythonFlaskConnexion/util.mustache +++ /dev/null @@ -1,141 +0,0 @@ -import datetime - -import six -import typing - - -def _deserialize(data, klass): - """Deserializes dict, list, str into an object. - - :param data: dict, list or str. - :param klass: class literal, or string of class name. - - :return: object. - """ - if data is None: - return None - - if klass in six.integer_types or klass in (float, str, bool): - return _deserialize_primitive(data, klass) - elif klass == object: - return _deserialize_object(data) - elif klass == datetime.date: - return deserialize_date(data) - elif klass == datetime.datetime: - return deserialize_datetime(data) - elif type(klass) == typing.GenericMeta: - if klass.__extra__ == list: - return _deserialize_list(data, klass.__args__[0]) - if klass.__extra__ == dict: - return _deserialize_dict(data, klass.__args__[1]) - else: - return deserialize_model(data, klass) - - -def _deserialize_primitive(data, klass): - """Deserializes to primitive type. - - :param data: data to deserialize. - :param klass: class literal. - - :return: int, long, float, str, bool. - :rtype: int | long | float | str | bool - """ - try: - value = klass(data) - except UnicodeEncodeError: - value = six.u(data) - except TypeError: - value = data - return value - - -def _deserialize_object(value): - """Return a original value. - - :return: object. - """ - return value - - -def deserialize_date(string): - """Deserializes string to date. - - :param string: str. - :type string: str - :return: date. - :rtype: date - """ - try: - from dateutil.parser import parse - return parse(string).date() - except ImportError: - return string - - -def deserialize_datetime(string): - """Deserializes string to datetime. - - The string should be in iso8601 datetime format. - - :param string: str. - :type string: str - :return: datetime. - :rtype: datetime - """ - try: - from dateutil.parser import parse - return parse(string) - except ImportError: - return string - - -def deserialize_model(data, klass): - """Deserializes list or dict to model. - - :param data: dict, list. - :type data: dict | list - :param klass: class literal. - :return: model object. - """ - instance = klass() - - if not instance.swagger_types: - return data - - for attr, attr_type in six.iteritems(instance.swagger_types): - if data is not None \ - and instance.attribute_map[attr] in data \ - and isinstance(data, (list, dict)): - value = data[instance.attribute_map[attr]] - setattr(instance, attr, _deserialize(value, attr_type)) - - return instance - - -def _deserialize_list(data, boxed_type): - """Deserializes a list and its elements. - - :param data: list to deserialize. - :type data: list - :param boxed_type: class literal. - - :return: deserialized list. - :rtype: list - """ - return [_deserialize(sub_data, boxed_type) - for sub_data in data] - - -def _deserialize_dict(data, boxed_type): - """Deserializes a dict and its elements. - - :param data: dict to deserialize. - :type data: dict - :param boxed_type: class literal. - - :return: deserialized dict. - :rtype: dict - """ - return {k: _deserialize(v, boxed_type) - for k, v in six.iteritems(data)} diff --git a/src/main/resources/mustache/scala/akka-http-server/api.mustache b/src/main/resources/mustache/scala/akka-http-server/api.mustache deleted file mode 100644 index 40f305dbe4..0000000000 --- a/src/main/resources/mustache/scala/akka-http-server/api.mustache +++ /dev/null @@ -1,70 +0,0 @@ -package {{package}} - -import akka.http.scaladsl.server.Directives._ -import akka.http.scaladsl.server.Route -{{^operations.complexRequestTypes.isEmpty}}import akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller -import akka.http.scaladsl.marshalling.ToEntityMarshaller -{{/operations.complexRequestTypes.isEmpty}} -{{#hasCookieParams}}import akka.http.scaladsl.model.headers.HttpCookiePair -{{/hasCookieParams}} -import {{invokerPackage}}.AkkaHttpHelper._ -{{#imports}}import {{import}} -{{/imports}} - -{{#operations}} -class {{classname}}( - {{classVarName}}Service: {{classname}}Service{{#hasComplexTypes}}, - {{classVarName}}Marshaller: {{classname}}Marshaller{{/hasComplexTypes}} -) { - {{#hasComplexTypes}}import {{classVarName}}Marshaller._ - {{/hasComplexTypes}} - - lazy val route: Route = - {{#operation}} - path({{#vendorExtensions.paths}}{{#isText}}"{{/isText}}{{value}}{{#isText}}"{{/isText}}{{#hasMore}} / {{/hasMore}}{{/vendorExtensions.paths}}) { {{^pathParams.isEmpty}}({{#pathParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/pathParams}}) => {{/pathParams.isEmpty}} - {{vendorExtensions.lowercaseHttpMethod}} { - {{^queryParams.isEmpty}}parameters({{#vendorExtensions.queryParamsWithSupportedType}}"{{baseName}}".as[{{dataType}}]{{^required}}.?{{/required}}{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.queryParamsWithSupportedType}}) { ({{#queryParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/queryParams}}) =>{{/queryParams.isEmpty}} - {{#headerParams}}{{#required}}headerValueByName{{/required}}{{^required}}optionalHeaderValueByName{{/required}}("{{baseName}}") { {{paramName}} => {{/headerParams}} - {{^formParams.isEmpty}}formFields({{#formParams}}"{{baseName}}".as[{{#isPrimitiveType}}{{dataType}}{{/isPrimitiveType}}{{^isPrimitiveType}}String{{/isPrimitiveType}}]{{^required}}.?{{/required}}{{#hasMore}}, {{/hasMore}}{{/formParams}}) { ({{#formParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/formParams}}) =>{{/formParams.isEmpty}} - {{#allParams}}{{#isCookieParam}}{{#required}}cookie({{/required}}{{^required}}optionalCookie({{/required}}"{{baseName}}"){ {{paramName}} => {{/isCookieParam}}{{/allParams}} - {{#bodyParam}}{{^isPrimitiveType}}entity(as[{{dataType}}]){ body =>{{/isPrimitiveType}}{{/bodyParam}} - {{classVarName}}Service.{{operationId}}({{#allParams}}{{paramName}} = {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - {{#bodyParam}}{{^isPrimitiveType}} }{{/isPrimitiveType}}{{/bodyParam}} - {{#allParams}}{{#isCookieParam}} }{{/isCookieParam}}{{/allParams}} - {{^formParams.isEmpty}} }{{/formParams.isEmpty}} - {{#headerParams}} }{{/headerParams}} - {{^queryParams.isEmpty}} }{{/queryParams.isEmpty}} - } - }{{^-last}} ~{{/-last}} - {{/operation}} -} - -trait {{classname}}Service { - -{{#operation}} -{{#responses}} def {{operationId}}{{code}}{{#baseType}}(response{{baseType}}{{containerType}}: {{dataType}}){{^isPrimitiveType}}(implicit toEntityMarshaller{{baseType}}{{containerType}}: ToEntityMarshaller[{{dataType}}]){{/isPrimitiveType}}{{/baseType}}: Route = - complete(({{code}}, {{#baseType}}response{{baseType}}{{containerType}}{{/baseType}}{{^baseType}}"{{message}}"{{/baseType}})) -{{/responses}} - /** -{{#responses}} * {{#code}}Code: {{.}}{{/code}}{{#message}}, Message: {{.}}{{/message}}{{#dataType}}, DataType: {{.}}{{/dataType}} - {{/responses}} - */ - def {{operationId}}({{#vendorExtensions.paramsWithSupportedType}}{{paramName}}: {{^required}}{{^isBodyParam}}Option[{{/isBodyParam}}{{/required}}{{dataType}}{{^required}}{{^isBodyParam}}]{{/isBodyParam}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/vendorExtensions.paramsWithSupportedType}}){{^vendorExtensions.complexReturnTypes.isEmpty}} - (implicit {{#vendorExtensions.complexReturnTypes}}toEntityMarshaller{{baseType}}{{containerType}}: ToEntityMarshaller[{{dataType}}]{{^-last}}, {{/-last}}{{/vendorExtensions.complexReturnTypes}}){{/vendorExtensions.complexReturnTypes.isEmpty}}: Route - -{{/operation}} -} - -{{#hasComplexTypes}} -trait {{classname}}Marshaller { -{{#complexRequestTypes}} implicit def fromRequestUnmarshaller{{.}}: FromRequestUnmarshaller[{{.}}] - -{{/complexRequestTypes}} - -{{#complexReturnTypes}} implicit def toEntityMarshaller{{baseType}}{{containerType}}: ToEntityMarshaller[{{dataType}}] - -{{/complexReturnTypes}} -} -{{/hasComplexTypes}} - -{{/operations}} diff --git a/src/main/resources/mustache/scala/client/README.mustache b/src/main/resources/mustache/scala/client/README.mustache deleted file mode 100644 index 85c72cd1d1..0000000000 --- a/src/main/resources/mustache/scala/client/README.mustache +++ /dev/null @@ -1,129 +0,0 @@ -# NAME - -{{appName}} - -{{#appDescription}}{{{appDescription}}}{{/appDescription}} - -# VERSION - -Automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: - -- API version: {{appVersion}} -- Package version: {{moduleVersion}} -{{^hideGenerationTimestamp}} -- Build date: {{generatedDate}} -{{/hideGenerationTimestamp}} -- Build package: {{generatorClass}} -{{#infoUrl}} -For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) -{{/infoUrl}} - -# Requirements - -Building the API client library requires [Maven](https://maven.apache.org/) to be installed. - -## Installation - -To install the API client library to your local Maven repository, simply execute: - -```shell -mvn install -``` - -To deploy it to a remote Maven repository instead, configure the settings of the repository and execute: - -```shell -mvn deploy -``` - -Refer to the [official documentation](https://maven.apache.org/plugins/maven-deploy-plugin/usage.html) for more information. - -### Maven users - -Add this dependency to your project's POM: - -```xml - - {{{groupId}}} - {{{artifactId}}} - {{{artifactVersion}}} - compile - -``` - -### Gradle users - -Add this dependency to your project's build file: - -```groovy -compile "{{{groupId}}}:{{{artifactId}}}:{{{artifactVersion}}}" -``` - -### SBT users - -```scala -libraryDependencies += "{{{groupId}}}" % "{{{artifactId}}}" % "{{{artifactVersion}}}" -``` - -## Documentation for API Endpoints - -All URIs are relative to *{{basePath}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} - -## Documentation for Models - -{{#models}}{{#model}} - [{{classname}}]({{modelDocPath}}{{classname}}.md) -{{/model}}{{/models}} - -## Documentation for Authorization - -{{^authMethods}}All endpoints do not require authorization. -{{/authMethods}}Authentication schemes defined for the API: -{{#authMethods}}### {{name}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{keyParamName}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{flow}} -- **Authorization URL**: {{authorizationUrl}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - {{scope}}: {{description}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} - - -# BUILDING YOUR LIBRARY - -See the homepage `https://github.com/swagger-api/swagger-codegen` for full details. -But briefly, clone the git repository, build the codegen codebase, set up your build -config file, then run the API build script. You will need git, Java 7 or 8 and Apache -maven 3.0.3 or better already installed. - -Your library files will be built under `WWW::MyProjectName`. - - $ git clone https://github.com/swagger-api/swagger-codegen.git - $ cd swagger-codegen - $ mvn package - $ java -jar modules/swagger-codegen-cli/target/swagger-codegen-cli.jar generate \ - -i [URL or file path to JSON swagger API spec] \ - -l akka-scala \ - -c /path/to/config/file.json \ - -o /path/to/output/folder - -Bang, all done. Run the `autodoc` script in the `bin` directory to see the API -you just built. - -## Author - -{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} -{{/hasMore}}{{/apis}}{{/apiInfo}} \ No newline at end of file diff --git a/src/main/resources/mustache/scala/client/api.mustache b/src/main/resources/mustache/scala/client/api.mustache deleted file mode 100644 index f67133052c..0000000000 --- a/src/main/resources/mustache/scala/client/api.mustache +++ /dev/null @@ -1,160 +0,0 @@ -{{>licenseInfo}} -package {{package}} - -import java.text.SimpleDateFormat - -{{#imports}}import {{import}} -{{/imports}} -import {{invokerPackage}}.{ApiInvoker, ApiException} - -import com.sun.jersey.multipart.FormDataMultiPart -import com.sun.jersey.multipart.file.FileDataBodyPart - -import javax.ws.rs.core.MediaType - -import java.io.File -import java.util.Date -import java.util.TimeZone - -import scala.collection.mutable.HashMap - -import com.wordnik.swagger.client._ -import scala.concurrent.Future -import collection.mutable - -import java.net.URI - -import com.wordnik.swagger.client.ClientResponseReaders.Json4sFormatsReader._ -import com.wordnik.swagger.client.RequestWriters.Json4sFormatsWriter._ - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent._ -import scala.concurrent.duration._ -import scala.util.{Failure, Success, Try} - -import org.json4s._ - -{{#operations}} -class {{classname}}( - val defBasePath: String = "{{{basePath}}}", - defApiInvoker: ApiInvoker = ApiInvoker -) { - private lazy val dateTimeFormatter = { - val formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") - formatter.setTimeZone(TimeZone.getTimeZone("UTC")) - formatter - } - private val dateFormatter = { - val formatter = new SimpleDateFormat("yyyy-MM-dd") - formatter.setTimeZone(TimeZone.getTimeZone("UTC")) - formatter - } - implicit val formats = new org.json4s.DefaultFormats { - override def dateFormatter = dateTimeFormatter - } - implicit val stringReader: ClientResponseReader[String] = ClientResponseReaders.StringReader - implicit val unitReader: ClientResponseReader[Unit] = ClientResponseReaders.UnitReader - implicit val jvalueReader: ClientResponseReader[JValue] = ClientResponseReaders.JValueReader - implicit val jsonReader: ClientResponseReader[Nothing] = JsonFormatsReader - implicit val stringWriter: RequestWriter[String] = RequestWriters.StringWriter - implicit val jsonWriter: RequestWriter[Nothing] = JsonFormatsWriter - - var basePath: String = defBasePath - var apiInvoker: ApiInvoker = defApiInvoker - - def addHeader(key: String, value: String): mutable.HashMap[String, String] = { - apiInvoker.defaultHeaders += key -> value - } - - val config: SwaggerConfig = SwaggerConfig.forUrl(new URI(defBasePath)) - val client = new RestClient(config) - val helper = new {{classname}}AsyncHelper(client, config) - - {{#operation}} - /** - * {{summary}} - * {{notes}} - * -{{#allParams}} * @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} - */ - def {{operationId}}({{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{#defaultValue}} = {{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}{{/defaultValue}}{{/required}}{{^required}}Option[{{dataType}}]{{#defaultValue}} = Option({{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}){{/defaultValue}}{{^defaultValue}} = None{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}: Option[{{returnType}}]{{/returnType}} = { - val await = Try(Await.result({{operationId}}Async({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}), Duration.Inf)) - await match { - case Success(i) => Some(await.get) - case Failure(t) => None - } - } - - /** - * {{summary}} asynchronously - * {{notes}} - * -{{#allParams}} * @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} -{{/allParams}} * @return Future({{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}}) - */ - def {{operationId}}Async({{#allParams}}{{paramName}}: {{#required}}{{dataType}}{{#defaultValue}} = {{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}{{/defaultValue}}{{/required}}{{^required}}Option[{{dataType}}]{{#defaultValue}} = Option({{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}){{/defaultValue}}{{^defaultValue}} = None{{/defaultValue}}{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}){{#returnType}}: Future[{{returnType}}]{{/returnType}} = { - helper.{{operationId}}({{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) - } - - {{/operation}} -} - -class {{classname}}AsyncHelper(client: TransportClient, config: SwaggerConfig) extends ApiClient(client, config) { - -{{#operation}} - def {{operationId}}({{#allParams}}{{^required}}{{paramName}}: Option[{{dataType}}] = {{#defaultValue}}Option({{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}){{/defaultValue}}{{^defaultValue}}None{{/defaultValue}}{{#hasMore}},{{/hasMore}} - {{/required}}{{#required}}{{paramName}}: {{dataType}}{{#defaultValue}} = {{#isString}}"{{{defaultValue}}}"{{/isString}}{{^isString}}{{#isByteArray}}"{{/isByteArray}}{{#isDate}}dateFormatter.parse("{{/isDate}}{{#isDateTime}}dateTimeFormatter.parse("{{/isDateTime}}{{{defaultValue}}}{{#isDate}}"){{/isDate}}{{#isDateTime}}"){{/isDateTime}}{{#isByteArray}}".getBytes{{/isByteArray}}{{/isString}}{{/defaultValue}}{{#hasMore}}, - {{/hasMore}}{{/required}}{{/allParams}})(implicit reader: ClientResponseReader[{{#returnType}}{{returnType}}{{/returnType}}{{^returnType}}Unit{{/returnType}}]{{#bodyParams}}, writer: RequestWriter[{{^required}}Option[{{dataType}}]{{/required}}{{#required}}{{dataType}}{{/required}}]{{/bodyParams}}){{#returnType}}: Future[{{returnType}}]{{/returnType}}{{^returnType}}: Future[Unit]{{/returnType}} = { - // create path and map variables - val path = (addFmt("{{path}}"){{#pathParams}} - replaceAll("\\{" + "{{baseName}}" + "\\}", {{paramName}}.toString){{/pathParams}}) - - // query params - val queryParams = new mutable.HashMap[String, String] - val headerParams = new mutable.HashMap[String, String] - - {{#allParams}} - {{#required}} - {{^isPrimitiveType}} - if ({{paramName}} == null) throw new Exception("Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}") - {{/isPrimitiveType}} - {{#isString}} - if ({{paramName}} == null) throw new Exception("Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}") - - {{/isString}} - {{/required}} - {{/allParams}} - {{#queryParams}} - {{^required}} - {{paramName}} match { - case Some(param) => queryParams += "{{baseName}}" -> param.toString - case _ => queryParams - } - {{/required}} - {{#required}} - queryParams += "{{baseName}}" -> {{paramName}}.toString - {{/required}} - {{/queryParams}} - {{#headerParams}} - {{^required}} - {{paramName}} match { - case Some(param) => headerParams += "{{baseName}}" -> param.toString - case _ => headerParams - } - {{/required}} - {{#required}} - headerParams += "{{baseName}}" -> {{paramName}}.toString - {{/required}} - {{/headerParams}} - - val resFuture = client.submit("{{httpMethod}}", path, queryParams.toMap, headerParams.toMap, {{#bodyParam}}writer.write({{paramName}}){{/bodyParam}}{{^bodyParam}}"{{emptyBodyParam}}"{{/bodyParam}}) - resFuture flatMap { resp => - process(reader.read(resp)) - } - } - -{{/operation}} - -} -{{/operations}} diff --git a/src/main/resources/mustache/scala/client/build.gradle.mustache b/src/main/resources/mustache/scala/client/build.gradle.mustache deleted file mode 100644 index e124eb0a5c..0000000000 --- a/src/main/resources/mustache/scala/client/build.gradle.mustache +++ /dev/null @@ -1,127 +0,0 @@ -apply plugin: 'idea' -apply plugin: 'eclipse' - -group = '{{groupId}}' -version = '{{artifactVersion}}' - -buildscript { - repositories { - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.5.+' - classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' - } -} - -repositories { - jcenter() -} - - -if(hasProperty('target') && target == 'android') { - - apply plugin: 'com.android.library' - apply plugin: 'com.github.dcendents.android-maven' - - android { - compileSdkVersion 23 - buildToolsVersion '23.0.2' - defaultConfig { - minSdkVersion 14 - targetSdkVersion 23 - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - - // Rename the aar correctly - libraryVariants.all { variant -> - variant.outputs.each { output -> - def outputFile = output.outputFile - if (outputFile != null && outputFile.name.endsWith('.aar')) { - def fileName = "${project.name}-${variant.baseName}-${version}.aar" - output.outputFile = new File(outputFile.parent, fileName) - } - } - } - - dependencies { - provided 'javax.annotation:jsr250-api:1.0' - } - } - - afterEvaluate { - android.libraryVariants.all { variant -> - def task = project.tasks.create "jar${variant.name.capitalize()}", Jar - task.description = "Create jar artifact for ${variant.name}" - task.dependsOn variant.javaCompile - task.from variant.javaCompile.destinationDir - task.destinationDir = project.file("${project.buildDir}/outputs/jar") - task.archiveName = "${project.name}-${variant.baseName}-${version}.jar" - artifacts.add('archives', task); - } - } - - task sourcesJar(type: Jar) { - from android.sourceSets.main.java.srcDirs - classifier = 'sources' - } - - artifacts { - archives sourcesJar - } - -} else { - - apply plugin: 'scala' - apply plugin: 'java' - apply plugin: 'maven' - - sourceCompatibility = JavaVersion.VERSION_1_7 - targetCompatibility = JavaVersion.VERSION_1_7 - - install { - repositories.mavenInstaller { - pom.artifactId = '{{artifactId}}' - } - } - - task execute(type:JavaExec) { - main = System.getProperty('mainClass') - classpath = sourceSets.main.runtimeClasspath - } -} - -ext { - scala_version = "2.10.4" - joda_version = "1.2" - jodatime_version = "2.2" - jersey_version = "1.19" - swagger_core_version = "1.5.8" - jersey_async_version = "1.0.5" - jackson_version = "2.4.2" - junit_version = "4.8.1" - scala_test_version = "2.2.4" - swagger_async_httpclient_version = "0.3.5" -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile "com.fasterxml.jackson.module:jackson-module-scala_2.10:$jackson_version" - compile "com.sun.jersey:jersey-client:$jersey_version" - compile "com.sun.jersey.contribs:jersey-multipart:$jersey_version" - compile "org.jfarcand:jersey-ahc-client:$jersey_async_version" - compile "org.scala-lang:scala-library:$scala_version" - compile "io.swagger:swagger-core:$swagger_core_version" - testCompile "org.scalatest:scalatest_2.10:$scala_test_version" - testCompile "junit:junit:$junit_version" - compile "joda-time:joda-time:$jodatime_version" - compile "org.joda:joda-convert:$joda_version" - compile "com.wordnik.swagger:swagger-async-httpclient_2.10:$swagger_async_httpclient_version" -} diff --git a/src/main/resources/mustache/scala/client/gradle-wrapper.properties.mustache b/src/main/resources/mustache/scala/client/gradle-wrapper.properties.mustache deleted file mode 100644 index b7a3647395..0000000000 --- a/src/main/resources/mustache/scala/client/gradle-wrapper.properties.mustache +++ /dev/null @@ -1,6 +0,0 @@ -#Tue May 17 23:08:05 CST 2016 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip diff --git a/src/main/resources/mustache/scala/client/gradle.properties.mustache b/src/main/resources/mustache/scala/client/gradle.properties.mustache deleted file mode 100644 index 05644f0754..0000000000 --- a/src/main/resources/mustache/scala/client/gradle.properties.mustache +++ /dev/null @@ -1,2 +0,0 @@ -# Uncomment to build for Android -#target = android \ No newline at end of file diff --git a/src/main/resources/mustache/scala/client/gradlew.bat.mustache b/src/main/resources/mustache/scala/client/gradlew.bat.mustache deleted file mode 100644 index 5f192121eb..0000000000 --- a/src/main/resources/mustache/scala/client/gradlew.bat.mustache +++ /dev/null @@ -1,90 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/src/main/resources/mustache/scala/client/gradlew.mustache b/src/main/resources/mustache/scala/client/gradlew.mustache deleted file mode 100755 index 9d82f78915..0000000000 --- a/src/main/resources/mustache/scala/client/gradlew.mustache +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/src/main/resources/mustache/scala/client/model.mustache b/src/main/resources/mustache/scala/client/model.mustache deleted file mode 100644 index 51931ba20d..0000000000 --- a/src/main/resources/mustache/scala/client/model.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{>licenseInfo}} -package {{package}} - -{{#imports}} -import {{import}} -{{/imports}} - -{{#models}} -{{#model}} -/** -{{#title}} * = {{{title}}} = - * -{{/title}} -{{#description}} * {{{description}}} - * -{{/description}} -{{#vars}} - * @param {{{name}}} {{#description}}{{{description}}}{{/description}}{{#example}} for example: '''{{{example}}}'''{{/example}} -{{/vars}} - */ -case class {{classname}} ( - {{#vars}} - {{{name}}}: {{^required}}Option[{{/required}}{{datatype}}{{^required}}]{{/required}}{{#hasMore}},{{/hasMore}} - {{/vars}} -) - -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/scala/client/pom.mustache b/src/main/resources/mustache/scala/client/pom.mustache deleted file mode 100644 index 5cfa0e2f19..0000000000 --- a/src/main/resources/mustache/scala/client/pom.mustache +++ /dev/null @@ -1,255 +0,0 @@ - - 4.0.0 - {{groupId}} - {{artifactId}} - jar - {{artifactId}} - {{artifactVersion}} - - - - maven-mongodb-plugin-repo - maven mongodb plugin repository - http://maven-mongodb-plugin.googlecode.com/svn/maven/repo - default - - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.0.0-M1 - - - enforce-maven - - enforce - - - - - 2.2.0 - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.12 - - - - loggerPath - conf/log4j.properties - - - -Xms512m -Xmx1500m - methods - pertest - - - - maven-dependency-plugin - - - package - - copy-dependencies - - - ${project.build.directory}/lib - - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.2 - - - - jar - test-jar - - - - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.9.1 - - - add_sources - generate-sources - - add-source - - - - - src/main/java - - - - - add_test_sources - generate-test-sources - - add-test-source - - - - - src/test/java - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.6.1 - - - 1.7 - 1.7 - - - - net.alchim31.maven - scala-maven-plugin - ${scala-maven-plugin-version} - - - scala-compile-first - process-resources - - add-source - compile - - - - scala-test-compile - process-test-resources - - testCompile - - - - - - -Xms128m - -Xmx1500m - - - - - - - - - org.scala-tools - maven-scala-plugin - - ${scala-version} - - - - - - - com.fasterxml.jackson.module - jackson-module-scala_2.11 - ${jackson-version} - - - com.fasterxml.jackson.datatype - jackson-datatype-joda - ${jackson-version} - - - com.sun.jersey - jersey-client - ${jersey-version} - - - com.sun.jersey.contribs - jersey-multipart - ${jersey-version} - - - org.jfarcand - jersey-ahc-client - ${jersey-async-version} - compile - - - org.scala-lang - scala-library - ${scala-version} - - - io.swagger - swagger-core - ${swagger-core-version} - - - org.scalatest - scalatest_2.11 - ${scala-test-version} - test - - - junit - junit - ${junit-version} - test - - - joda-time - joda-time - ${joda-time-version} - - - org.joda - joda-convert - ${joda-version} - - - com.wordnik.swagger - swagger-async-httpclient_2.11 - ${swagger-async-httpclient-version} - - - - 2.11.12 - 1.9.2 - 2.9.9 - 1.19.4 - 1.5.18 - 1.0.5 - 1.0.0 - 2.9.2 - - 4.12 - 3.1.5 - 3.0.4 - 0.3.5 - - UTF-8 - - diff --git a/src/main/resources/mustache/scala/client/settings.gradle.mustache b/src/main/resources/mustache/scala/client/settings.gradle.mustache deleted file mode 100644 index b8fd6c4c41..0000000000 --- a/src/main/resources/mustache/scala/client/settings.gradle.mustache +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "{{artifactId}}" \ No newline at end of file diff --git a/src/main/resources/mustache/swift3/APIHelper.mustache b/src/main/resources/mustache/swift3/APIHelper.mustache deleted file mode 100644 index 4b90cfc5b4..0000000000 --- a/src/main/resources/mustache/swift3/APIHelper.mustache +++ /dev/null @@ -1,75 +0,0 @@ -// APIHelper.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -class APIHelper { - static func rejectNil(_ source: [String:Any?]) -> [String:Any]? { - var destination = [String:Any]() - for (key, nillableValue) in source { - if let value: Any = nillableValue { - destination[key] = value - } - } - - if destination.isEmpty { - return nil - } - return destination - } - - static func rejectNilHeaders(_ source: [String:Any?]) -> [String:String] { - var destination = [String:String]() - for (key, nillableValue) in source { - if let value: Any = nillableValue { - destination[key] = "\(value)" - } - } - return destination - } - - static func convertBoolToString(_ source: [String: Any]?) -> [String:Any]? { - guard let source = source else { - return nil - } - var destination = [String:Any]() - let theTrue = NSNumber(value: true as Bool) - let theFalse = NSNumber(value: false as Bool) - for (key, value) in source { - switch value { - case let x where x as? NSNumber === theTrue || x as? NSNumber === theFalse: - destination[key] = "\(value as! Bool)" as Any? - default: - destination[key] = value - } - } - return destination - } - - static func mapValuesToQueryItems(values: [String:Any?]) -> [URLQueryItem]? { - let returnValues = values - .filter { $0.1 != nil } - .map { (item: (_key: String, _value: Any?)) -> [URLQueryItem] in - if let value = item._value as? Array { - return value.map { (v) -> URLQueryItem in - URLQueryItem( - name: item._key, - value: v - ) - } - } else { - return [URLQueryItem( - name: item._key, - value: "\(item._value!)" - )] - } - } - .flatMap { $0 } - - if returnValues.isEmpty { return nil } - return returnValues - } -} diff --git a/src/main/resources/mustache/swift3/APIs.mustache b/src/main/resources/mustache/swift3/APIs.mustache deleted file mode 100644 index 557ba31efb..0000000000 --- a/src/main/resources/mustache/swift3/APIs.mustache +++ /dev/null @@ -1,77 +0,0 @@ -// APIs.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -open class {{projectName}}API { - open static var basePath = "{{{basePath}}}" - open static var credential: URLCredential? - open static var customHeaders: [String:String] = [:] - open static var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory() -} - -open class APIBase { - func toParameters(_ encodable: JSONEncodable?) -> [String: Any]? { - let encoded: Any? = encodable?.encodeToJSON() - - if encoded! is [Any] { - var dictionary = [String:Any]() - for (index, item) in (encoded as! [Any]).enumerated() { - dictionary["\(index)"] = item - } - return dictionary - } else { - return encoded as? [String:Any] - } - } -} - -open class RequestBuilder { - var credential: URLCredential? - var headers: [String:String] - public let parameters: Any? - public let isBody: Bool - public let method: String - public let URLString: String - - /// Optional block to obtain a reference to the request's progress instance when available. - public var onProgressReady: ((Progress) -> ())? - - required public init(method: String, URLString: String, parameters: Any?, isBody: Bool, headers: [String:String] = [:]) { - self.method = method - self.URLString = URLString - self.parameters = parameters - self.isBody = isBody - self.headers = headers - - addHeaders({{projectName}}API.customHeaders) - } - - open func addHeaders(_ aHeaders:[String:String]) { - for (header, value) in aHeaders { - addHeader(name: header, value: value) - } - } - - open func execute(_ completion: @escaping (_ response: Response?, _ error: ErrorResponse?) -> Void) { } - - @discardableResult public func addHeader(name: String, value: String) -> Self { - if !value.isEmpty { - headers[name] = value - } - return self - } - - open func addCredential() -> Self { - self.credential = {{projectName}}API.credential - return self - } -} - -public protocol RequestBuilderFactory { - func getBuilder() -> RequestBuilder.Type -} - diff --git a/src/main/resources/mustache/swift3/AlamofireImplementations.mustache b/src/main/resources/mustache/swift3/AlamofireImplementations.mustache deleted file mode 100644 index 863f618326..0000000000 --- a/src/main/resources/mustache/swift3/AlamofireImplementations.mustache +++ /dev/null @@ -1,376 +0,0 @@ -// AlamofireImplementations.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation -import Alamofire - -class AlamofireRequestBuilderFactory: RequestBuilderFactory { - func getBuilder() -> RequestBuilder.Type { - return AlamofireRequestBuilder.self - } -} - -private struct SynchronizedDictionary { - - private var dictionary = [K: V]() - private let queue = DispatchQueue( - label: "SynchronizedDictionary", - qos: DispatchQoS.userInitiated, - attributes: [DispatchQueue.Attributes.concurrent], - autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, - target: nil - ) - - public subscript(key: K) -> V? { - get { - var value: V? - - queue.sync { - value = self.dictionary[key] - } - - return value - } - set { - queue.sync(flags: DispatchWorkItemFlags.barrier) { - self.dictionary[key] = newValue - } - } - } - -} - -class JSONEncodingWrapper: ParameterEncoding { - var bodyParameters: Any? - var encoding: JSONEncoding = JSONEncoding() - - public init(parameters: Any?) { - self.bodyParameters = parameters - } - - public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { - return try encoding.encode(urlRequest, withJSONObject: bodyParameters) - } -} - -// Store manager to retain its reference -private var managerStore = SynchronizedDictionary() - -open class AlamofireRequestBuilder: RequestBuilder { - required public init(method: String, URLString: String, parameters: Any?, isBody: Bool, headers: [String : String] = [:]) { - super.init(method: method, URLString: URLString, parameters: parameters, isBody: isBody, headers: headers) - } - - /** - May be overridden by a subclass if you want to control the session - configuration. - */ - open func createSessionManager() -> Alamofire.SessionManager { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - return Alamofire.SessionManager(configuration: configuration) - } - - /** - May be overridden by a subclass if you want to control the Content-Type - that is given to an uploaded form part. - - Return nil to use the default behavior (inferring the Content-Type from - the file extension). Return the desired Content-Type otherwise. - */ - open func contentTypeForFormPart(fileURL: URL) -> String? { - return nil - } - - /** - May be overridden by a subclass if you want to control the request - configuration (e.g. to override the cache policy). - */ - open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) -> DataRequest { - return manager.request(URLString, method: method, parameters: parameters as? Parameters, encoding: encoding, headers: headers) - } - - override open func execute(_ completion: @escaping (_ response: Response?, _ error: ErrorResponse?) -> Void) { - let managerId:String = UUID().uuidString - // Create a new manager for each request to customize its request header - let manager = createSessionManager() - managerStore[managerId] = manager - - let encoding:ParameterEncoding = isBody ? JSONEncodingWrapper(parameters: parameters) : URLEncoding() - - let xMethod = Alamofire.HTTPMethod(rawValue: method) - - let param = parameters as? Parameters - let fileKeys = param == nil ? [] : param!.filter { $1 is NSURL } - .map { $0.0 } - - if fileKeys.count > 0 { - manager.upload(multipartFormData: { mpForm in - for (k, v) in param! { - switch v { - case let fileURL as URL: - if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { - mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) - } - else { - mpForm.append(fileURL, withName: k) - } - case let string as String: - mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) - case let number as NSNumber: - mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) - default: - fatalError("Unprocessable value \(v) with key \(k)") - } - } - }, to: URLString, method: xMethod!, headers: nil, encodingCompletion: { encodingResult in - switch encodingResult { - case .success(let upload, _, _): - if let onProgressReady = self.onProgressReady { - onProgressReady(upload.uploadProgress) - } - self.processRequest(request: upload, managerId, completion) - case .failure(let encodingError): - completion(nil, ErrorResponse.HttpError(statusCode: 415, data: nil, error: encodingError)) - } - }) - } else { - let request = makeRequest(manager: manager, method: xMethod!, encoding: encoding, headers: headers) - if let onProgressReady = self.onProgressReady { - onProgressReady(request.progress) - } - processRequest(request: request, managerId, completion) - } - - } - - private func processRequest(request: DataRequest, _ managerId: String, _ completion: @escaping (_ response: Response?, _ error: ErrorResponse?) -> Void) { - if let credential = self.credential { - request.authenticate(usingCredential: credential) - } - - let cleanupRequest = { - managerStore[managerId] = nil - } - - let validatedRequest = request.validate() - - switch T.self { - case is String.Type: - validatedRequest.responseString(completionHandler: { (stringResponse) in - cleanupRequest() - - if stringResponse.result.isFailure { - completion( - nil, - ErrorResponse.HttpError(statusCode: stringResponse.response?.statusCode ?? 500, data: stringResponse.data, error: stringResponse.result.error as Error!) - ) - return - } - - completion( - Response( - response: stringResponse.response!, - body: ((stringResponse.result.value ?? "") as! T) - ), - nil - ) - }) - case is Void.Type: - validatedRequest.responseData(completionHandler: { (voidResponse) in - cleanupRequest() - - if voidResponse.result.isFailure { - completion( - nil, - ErrorResponse.HttpError(statusCode: voidResponse.response?.statusCode ?? 500, data: voidResponse.data, error: voidResponse.result.error!) - ) - return - } - - completion( - Response( - response: voidResponse.response!, - body: nil), - nil - ) - }) - case is Data.Type: - validatedRequest.responseData(completionHandler: { (dataResponse) in - cleanupRequest() - - if dataResponse.result.isFailure { - completion( - nil, - ErrorResponse.HttpError(statusCode: dataResponse.response?.statusCode ?? 500, data: dataResponse.data, error: dataResponse.result.error!) - ) - return - } - - completion( - Response( - response: dataResponse.response!, - body: (dataResponse.data as! T) - ), - nil - ) - }) - case is URL.Type: - validatedRequest.responseData(completionHandler: { (dataResponse) in - cleanupRequest() - - do { - - guard !dataResponse.result.isFailure else { - throw DownloadException.responseFailed - } - - guard let data = dataResponse.data else { - throw DownloadException.responseDataMissing - } - - guard let request = request.request else { - throw DownloadException.requestMissing - } - - let fileManager = FileManager.default - let urlRequest = try request.asURLRequest() - let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] - let requestURL = try self.getURL(from: urlRequest) - - var requestPath = try self.getPath(from: requestURL) - - if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) { - requestPath = requestPath.appending("/\(headerFileName)") - } - - let filePath = documentsDirectory.appendingPathComponent(requestPath) - let directoryPath = filePath.deletingLastPathComponent().path - - try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) - try data.write(to: filePath, options: .atomic) - - completion( - Response( - response: dataResponse.response!, - body: (filePath as! T) - ), - nil - ) - - } catch let requestParserError as DownloadException { - completion(nil, ErrorResponse.HttpError(statusCode: 400, data: dataResponse.data, error: requestParserError)) - } catch let error { - completion(nil, ErrorResponse.HttpError(statusCode: 400, data: dataResponse.data, error: error)) - } - return - }) - default: - validatedRequest.responseJSON(options: .allowFragments) { response in - cleanupRequest() - - if response.result.isFailure { - completion(nil, ErrorResponse.HttpError(statusCode: response.response?.statusCode ?? 500, data: response.data, error: response.result.error!)) - return - } - - // handle HTTP 204 No Content - // NSNull would crash decoders - if response.response?.statusCode == 204 && response.result.value is NSNull{ - completion(nil, nil) - return - } - - if () is T { - completion(Response(response: response.response!, body: (() as! T)), nil) - return - } - if let json: Any = response.result.value { - let decoded = Decoders.decode(clazz: T.self, source: json as AnyObject, instance: nil) - switch decoded { - case let .success(object): completion(Response(response: response.response!, body: object), nil) - case let .failure(error): completion(nil, ErrorResponse.DecodeError(response: response.data, decodeError: error)) - } - return - } else if "" is T { - // swagger-parser currently doesn't support void, which will be fixed in future swagger-parser release - // https://github.com/swagger-api/swagger-parser/pull/34 - completion(Response(response: response.response!, body: ("" as! T)), nil) - return - } - - completion(nil, ErrorResponse.HttpError(statusCode: 500, data: nil, error: NSError(domain: "localhost", code: 500, userInfo: ["reason": "unreacheable code"]))) - } - } - } - - open func buildHeaders() -> [String: String] { - var httpHeaders = SessionManager.defaultHTTPHeaders - for (key, value) in self.headers { - httpHeaders[key] = value - } - return httpHeaders - } - - fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? { - - guard let contentDisposition = contentDisposition else { - return nil - } - - let items = contentDisposition.components(separatedBy: ";") - - var filename : String? = nil - - for contentItem in items { - - let filenameKey = "filename=" - guard let range = contentItem.range(of: filenameKey) else { - break - } - - filename = contentItem - return filename? - .replacingCharacters(in: range, with:"") - .replacingOccurrences(of: "\"", with: "") - .trimmingCharacters(in: .whitespacesAndNewlines) - } - - return filename - - } - - fileprivate func getPath(from url : URL) throws -> String { - - guard var path = URLComponents(url: url, resolvingAgainstBaseURL: true)?.path else { - throw DownloadException.requestMissingPath - } - - if path.hasPrefix("/") { - path.remove(at: path.startIndex) - } - - return path - - } - - fileprivate func getURL(from urlRequest : URLRequest) throws -> URL { - - guard let url = urlRequest.url else { - throw DownloadException.requestMissingURL - } - - return url - } -} - -fileprivate enum DownloadException : Error { - case responseDataMissing - case responseFailed - case requestMissing - case requestMissingPath - case requestMissingURL -} diff --git a/src/main/resources/mustache/swift3/Cartfile.mustache b/src/main/resources/mustache/swift3/Cartfile.mustache deleted file mode 100644 index 523ab5db20..0000000000 --- a/src/main/resources/mustache/swift3/Cartfile.mustache +++ /dev/null @@ -1,3 +0,0 @@ -github "Alamofire/Alamofire" ~> 4.5{{#usePromiseKit}} -github "mxcl/PromiseKit" ~> 4.4{{/usePromiseKit}}{{#useRxSwift}} -github "ReactiveX/RxSwift" "rxswift-3.0"{{/useRxSwift}} \ No newline at end of file diff --git a/src/main/resources/mustache/swift3/Configuration.mustache b/src/main/resources/mustache/swift3/Configuration.mustache deleted file mode 100644 index 7f777932fe..0000000000 --- a/src/main/resources/mustache/swift3/Configuration.mustache +++ /dev/null @@ -1,15 +0,0 @@ -// Configuration.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -open class Configuration { - - // This value is used to configure the date formatter that is used to serialize dates into JSON format. - // You must set it prior to encoding any dates, and it will only be read once. - open static var dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" - -} diff --git a/src/main/resources/mustache/swift3/Extensions.mustache b/src/main/resources/mustache/swift3/Extensions.mustache deleted file mode 100644 index 4d91fa2e44..0000000000 --- a/src/main/resources/mustache/swift3/Extensions.mustache +++ /dev/null @@ -1,200 +0,0 @@ -// Extensions.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation -import Alamofire{{#usePromiseKit}} -import PromiseKit{{/usePromiseKit}} - -extension Bool: JSONEncodable { - func encodeToJSON() -> Any { return self as Any } -} - -extension Float: JSONEncodable { - func encodeToJSON() -> Any { return self as Any } -} - -extension Int: JSONEncodable { - func encodeToJSON() -> Any { return self as Any } -} - -extension Int32: JSONEncodable { - func encodeToJSON() -> Any { return NSNumber(value: self as Int32) } -} - -extension Int64: JSONEncodable { - func encodeToJSON() -> Any { return NSNumber(value: self as Int64) } -} - -extension Double: JSONEncodable { - func encodeToJSON() -> Any { return self as Any } -} - -extension String: JSONEncodable { - func encodeToJSON() -> Any { return self as Any } -} - -private func encodeIfPossible(_ object: T) -> Any { - if let encodableObject = object as? JSONEncodable { - return encodableObject.encodeToJSON() - } else { - return object as Any - } -} - -extension Array: JSONEncodable { - func encodeToJSON() -> Any { - return self.map(encodeIfPossible) - } -} - -extension Dictionary: JSONEncodable { - func encodeToJSON() -> Any { - var dictionary = [AnyHashable: Any]() - for (key, value) in self { - dictionary[key] = encodeIfPossible(value) - } - return dictionary as Any - } -} - -extension Data: JSONEncodable { - func encodeToJSON() -> Any { - return self.base64EncodedString(options: Data.Base64EncodingOptions()) - } -} - -private let dateFormatter: DateFormatter = { - let fmt = DateFormatter() - fmt.dateFormat = Configuration.dateFormat - fmt.locale = Locale(identifier: "en_US_POSIX") - return fmt -}() - -extension Date: JSONEncodable { - func encodeToJSON() -> Any { - return dateFormatter.string(from: self) as Any - } -} - -extension UUID: JSONEncodable { - func encodeToJSON() -> Any { - return self.uuidString - } -} - -/// Represents an ISO-8601 full-date (RFC-3339). -/// ex: 12-31-1999 -/// https://xml2rfc.tools.ietf.org/public/rfc/html/rfc3339.html#anchor14 -public final class ISOFullDate: CustomStringConvertible { - - public let year: Int - public let month: Int - public let day: Int - - public init(year: Int, month: Int, day: Int) { - self.year = year - self.month = month - self.day = day - } - - /** - Converts a Date to an ISOFullDate. Only interested in the year, month, day components. - - - parameter date: The date to convert. - - - returns: An ISOFullDate constructed from the year, month, day of the date. - */ - public static func from(date: Date) -> ISOFullDate? { - let calendar = Calendar(identifier: .gregorian) - - let components = calendar.dateComponents( - [ - .year, - .month, - .day, - ], - from: date - ) - - guard - let year = components.year, - let month = components.month, - let day = components.day - else { - return nil - } - - return ISOFullDate( - year: year, - month: month, - day: day - ) - } - - /** - Converts a ISO-8601 full-date string to an ISOFullDate. - - - parameter string: The ISO-8601 full-date format string to convert. - - - returns: An ISOFullDate constructed from the string. - */ - public static func from(string: String) -> ISOFullDate? { - let components = string - .characters - .split(separator: "-") - .map(String.init) - .flatMap { Int($0) } - guard components.count == 3 else { return nil } - - return ISOFullDate( - year: components[0], - month: components[1], - day: components[2] - ) - } - - /** - Converts the receiver to a Date, in the default time zone. - - - returns: A Date from the components of the receiver, in the default time zone. - */ - public func toDate() -> Date? { - var components = DateComponents() - components.year = year - components.month = month - components.day = day - components.timeZone = TimeZone.ReferenceType.default - let calendar = Calendar(identifier: .gregorian) - return calendar.date(from: components) - } - - // MARK: CustomStringConvertible - - public var description: String { - return "\(year)-\(month)-\(day)" - } - -} - -extension ISOFullDate: JSONEncodable { - public func encodeToJSON() -> Any { - return "\(year)-\(month)-\(day)" - } -} - -{{#usePromiseKit}}extension RequestBuilder { - public func execute() -> Promise> { - let deferred = Promise>.pending() - self.execute { (response: Response?, error: Error?) in - if let response = response { - deferred.fulfill(response) - } else { - deferred.reject(error!) - } - } - return deferred.promise - } -}{{/usePromiseKit}} diff --git a/src/main/resources/mustache/swift3/Models.mustache b/src/main/resources/mustache/swift3/Models.mustache deleted file mode 100644 index 5d0019f0f3..0000000000 --- a/src/main/resources/mustache/swift3/Models.mustache +++ /dev/null @@ -1,402 +0,0 @@ -// Models.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -protocol JSONEncodable { - func encodeToJSON() -> Any -} - -public enum ErrorResponse : Error { - case HttpError(statusCode: Int, data: Data?, error: Error) - case DecodeError(response: Data?, decodeError: DecodeError) -} - -open class Response { - open let statusCode: Int - open let header: [String: String] - open let body: T? - - public init(statusCode: Int, header: [String: String], body: T?) { - self.statusCode = statusCode - self.header = header - self.body = body - } - - public convenience init(response: HTTPURLResponse, body: T?) { - let rawHeader = response.allHeaderFields - var header = [String:String]() - for case let (key, value) as (String, String) in rawHeader { - header[key] = value - } - self.init(statusCode: response.statusCode, header: header, body: body) - } -} - -public enum Decoded { - case success(ValueType) - case failure(DecodeError) -} - -public extension Decoded { - var value: ValueType? { - switch self { - case let .success(value): - return value - case .failure: - return nil - } - } -} - -public enum DecodeError { - case typeMismatch(expected: String, actual: String) - case missingKey(key: String) - case parseError(message: String) -} - -private var once = Int() -class Decoders { - static fileprivate var decoders = Dictionary AnyObject)>() - - static func addDecoder(clazz: T.Type, decoder: @escaping ((AnyObject, AnyObject?) -> Decoded)) { - let key = "\(T.self)" - decoders[key] = { decoder($0, $1) as AnyObject } - } - - static func decode(clazz: T.Type, discriminator: String, source: AnyObject) -> Decoded { - let key = discriminator - if let decoder = decoders[key], let value = decoder(source, nil) as? Decoded { - return value - } else { - return .failure(.typeMismatch(expected: String(describing: clazz), actual: String(describing: source))) - } - } - - static func decode(clazz: [T].Type, source: AnyObject) -> Decoded<[T]> { - if let sourceArray = source as? [AnyObject] { - var values = [T]() - for sourceValue in sourceArray { - switch Decoders.decode(clazz: T.self, source: sourceValue, instance: nil) { - case let .success(value): - values.append(value) - case let .failure(error): - return .failure(error) - } - } - return .success(values) - } else { - return .failure(.typeMismatch(expected: String(describing: clazz), actual: String(describing: source))) - } - } - - static func decode(clazz: T.Type, source: AnyObject) -> Decoded { - switch Decoders.decode(clazz: T.self, source: source, instance: nil) { - case let .success(value): - return .success(value) - case let .failure(error): - return .failure(error) - } - } - - static open func decode(clazz: T.Type, source: AnyObject) -> Decoded { - if let value = source as? T.RawValue { - if let enumValue = T.init(rawValue: value) { - return .success(enumValue) - } else { - return .failure(.typeMismatch(expected: "A value from the enumeration \(T.self)", actual: "\(value)")) - } - } else { - return .failure(.typeMismatch(expected: "\(T.RawValue.self) matching a case from the enumeration \(T.self)", actual: String(describing: type(of: source)))) - } - } - - static func decode(clazz: [Key:T].Type, source: AnyObject) -> Decoded<[Key:T]> { - if let sourceDictionary = source as? [Key: AnyObject] { - var dictionary = [Key:T]() - for (key, value) in sourceDictionary { - switch Decoders.decode(clazz: T.self, source: value, instance: nil) { - case let .success(value): - dictionary[key] = value - case let .failure(error): - return .failure(error) - } - } - return .success(dictionary) - } else { - return .failure(.typeMismatch(expected: String(describing: clazz), actual: String(describing: source))) - } - } - - static func decodeOptional(clazz: T.Type, source: AnyObject?) -> Decoded { - guard !(source is NSNull), source != nil else { return .success(nil) } - if let value = source as? T.RawValue { - if let enumValue = T.init(rawValue: value) { - return .success(enumValue) - } else { - return .failure(.typeMismatch(expected: "A value from the enumeration \(T.self)", actual: "\(value)")) - } - } else { - return .failure(.typeMismatch(expected: "\(T.RawValue.self) matching a case from the enumeration \(T.self)", actual: String(describing: type(of: source)))) - } - } - - static func decode(clazz: T.Type, source: AnyObject, instance: AnyObject?) -> Decoded { - initialize() - if let sourceNumber = source as? NSNumber, let value = sourceNumber.int32Value as? T, T.self is Int32.Type { - return .success(value) - } - if let sourceNumber = source as? NSNumber, let value = sourceNumber.int32Value as? T, T.self is Int64.Type { - return .success(value) - } - if let intermediate = source as? String, let value = UUID(uuidString: intermediate) as? T, source is String, T.self is UUID.Type { - return .success(value) - } - if let value = source as? T { - return .success(value) - } - if let intermediate = source as? String, let value = Data(base64Encoded: intermediate) as? T { - return .success(value) - } - {{#lenientTypeCast}} - if T.self is Int32.Type && source is String { - return (source as! NSString).intValue as! T - } - if T.self is Int64.Type && source is String { - return (source as! NSString).intValue as! T - } - if T.self is Bool.Type && source is String { - return (source as! NSString).boolValue as! T - } - if T.self is String.Type && source is NSNumber { - return String(describing: source) as! T - } - {{/lenientTypeCast}} - - let key = "\(T.self)" - if let decoder = decoders[key], let value = decoder(source, instance) as? Decoded { - return value - } else { - return .failure(.typeMismatch(expected: String(describing: clazz), actual: String(describing: source))) - } - } - - //Convert a Decoded so that its value is optional. DO WE STILL NEED THIS? - static func toOptional(decoded: Decoded) -> Decoded { - return .success(decoded.value) - } - - static func decodeOptional(clazz: T.Type, source: AnyObject?) -> Decoded { - if let source = source, !(source is NSNull) { - switch Decoders.decode(clazz: clazz, source: source, instance: nil) { - case let .success(value): return .success(value) - case let .failure(error): return .failure(error) - } - } else { - return .success(nil) - } - } - - static func decodeOptional(clazz: [T].Type, source: AnyObject?) -> Decoded<[T]?> where T: RawRepresentable { - if let source = source as? [AnyObject] { - var values = [T]() - for sourceValue in source { - switch Decoders.decodeOptional(clazz: T.self, source: sourceValue) { - case let .success(value): if let value = value { values.append(value) } - case let .failure(error): return .failure(error) - } - } - return .success(values) - } else { - return .success(nil) - } - } - - static func decodeOptional(clazz: [T].Type, source: AnyObject?) -> Decoded<[T]?> { - if let source = source as? [AnyObject] { - var values = [T]() - for sourceValue in source { - switch Decoders.decode(clazz: T.self, source: sourceValue, instance: nil) { - case let .success(value): values.append(value) - case let .failure(error): return .failure(error) - } - } - return .success(values) - } else { - return .success(nil) - } - } - - static func decodeOptional(clazz: [Key:T].Type, source: AnyObject?) -> Decoded<[Key:T]?> { - if let sourceDictionary = source as? [Key: AnyObject] { - var dictionary = [Key:T]() - for (key, value) in sourceDictionary { - switch Decoders.decode(clazz: T.self, source: value, instance: nil) { - case let .success(value): dictionary[key] = value - case let .failure(error): return .failure(error) - } - } - return .success(dictionary) - } else { - return .success(nil) - } - } - - static func decodeOptional(clazz: T, source: AnyObject) -> Decoded where T.RawValue == U { - if let value = source as? U { - if let enumValue = T.init(rawValue: value) { - return .success(enumValue) - } else { - return .failure(.typeMismatch(expected: "A value from the enumeration \(T.self)", actual: "\(value)")) - } - } else { - return .failure(.typeMismatch(expected: "String", actual: String(describing: type(of: source)))) - } - } - - - private static var __once: () = { - let formatters = [ - "yyyy-MM-dd", - "yyyy-MM-dd'T'HH:mm:ssZZZZZ", - "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ", - "yyyy-MM-dd'T'HH:mm:ss'Z'", - "yyyy-MM-dd'T'HH:mm:ss.SSS", - "yyyy-MM-dd HH:mm:ss" - ].map { (format: String) -> DateFormatter in - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.dateFormat = format - return formatter - } - // Decoder for Date - Decoders.addDecoder(clazz: Date.self) { (source: AnyObject, instance: AnyObject?) -> Decoded in - if let sourceString = source as? String { - for formatter in formatters { - if let date = formatter.date(from: sourceString) { - return .success(date) - } - } - } - if let sourceInt = source as? Int { - // treat as a java date - return .success(Date(timeIntervalSince1970: Double(sourceInt / 1000) )) - } - if source is String || source is Int { - return .failure(.parseError(message: "Could not decode date")) - } else { - return .failure(.typeMismatch(expected: "String or Int", actual: "\(source)")) - } - } - - // Decoder for ISOFullDate - Decoders.addDecoder(clazz: ISOFullDate.self) { (source: AnyObject, instance: AnyObject?) -> Decoded in - if let string = source as? String, - let isoDate = ISOFullDate.from(string: string) { - return .success(isoDate) - } else { - return .failure(.typeMismatch(expected: "ISO date", actual: "\(source)")) - } - } - - {{#models}} - {{#model}} - {{^isArrayModel}} - // Decoder for [{{{classname}}}] - Decoders.addDecoder(clazz: [{{{classname}}}].self) { (source: AnyObject, instance: AnyObject?) -> Decoded<[{{{classname}}}]> in - return Decoders.decode(clazz: [{{{classname}}}].self, source: source) - } - - // Decoder for {{{classname}}} - Decoders.addDecoder(clazz: {{{classname}}}.self) { (source: AnyObject, instance: AnyObject?) -> Decoded<{{{classname}}}> in -{{#isEnum}} - //TODO: I don't think we need this anymore - return Decoders.decode(clazz: {{{classname}}}.self, source: source, instance: instance) -{{/isEnum}} -{{^isEnum}} -{{#allVars.isEmpty}} - if let source = source as? {{classname}} { - return .success(source) - } else { - return .failure(.typeMismatch(expected: "Typealias {{classname}}", actual: "\(source)")) - } -{{/allVars.isEmpty}} -{{^allVars.isEmpty}} - if let sourceDictionary = source as? [AnyHashable: Any] { - {{#discriminator}} - // Check discriminator to support inheritance - if let discriminator = sourceDictionary["{{discriminator.propertyName}}"] as? String, instance == nil && discriminator != "{{classname}}"{ - return Decoders.decode(clazz: {{classname}}.self, discriminator: discriminator, source: source) - } - {{/discriminator}} - {{#additionalPropertiesType}} - var propsDictionary = sourceDictionary - let keys : [AnyHashable] = [{{#allVars}}{{^-last}}"{{baseName}}", {{/-last}}{{#-last}}"{{baseName}}"{{/-last}}{{/allVars}}] - {{/additionalPropertiesType}} - {{#unwrapRequired}} - {{#requiredVars}} - guard let {{name}}Source = sourceDictionary["{{baseName}}"] as AnyObject? else { - return .failure(.missingKey(key: "{{baseName}}")) - } - guard let {{name}} = Decoders.decode(clazz: {{#isEnum}}{{^isListContainer}}{{classname}}.{{enumName}}.self{{/isListContainer}}{{#isListContainer}}Array<{{classname}}.{{enumName}}>.self{{/isListContainer}}{{/isEnum}}{{^isEnum}}{{{datatype}}}.self{{/isEnum}}.self, source: {{name}}Source).value else { - return .failure(.typeMismatch(expected: "{{classname}}", actual: "\({{name}}Source)")) - } - {{/requiredVars}} - let _result = {{classname}}({{#requiredVars}}{{^-first}}, {{/-first}}{{name}}: {{name}}{{/requiredVars}}) - {{#optionalVars}} - switch Decoders.decodeOptional(clazz: {{#isEnum}}{{^isListContainer}}{{classname}}.{{enumName}}.self{{/isListContainer}}{{#isListContainer}}Array<{{classname}}.{{enumName}}>.self{{/isListContainer}}{{/isEnum}}{{^isEnum}}{{{datatype}}}.self{{/isEnum}}, source: sourceDictionary["{{baseName}}"] as AnyObject?) { - case let .success(value): _result.{{name}} = value - case let .failure(error): break - } - {{/optionalVars}} - {{/unwrapRequired}} - {{^unwrapRequired}} - let _result = instance == nil ? {{classname}}() : instance as! {{classname}} - {{#parent}} - if decoders["\({{parent}}.self)"] != nil { - _ = Decoders.decode(clazz: {{parent}}.self, source: source, instance: _result) - } - {{/parent}} - {{#allVars}} - switch Decoders.decodeOptional(clazz: {{#isEnum}}{{^isListContainer}}{{classname}}.{{enumName}}.self{{/isListContainer}}{{#isListContainer}}Array<{{classname}}.{{enumName}}>.self{{/isListContainer}}{{/isEnum}}{{^isEnum}}{{{datatype}}}.self{{/isEnum}}, source: sourceDictionary["{{baseName}}"] as AnyObject?) { - {{#isEnum}}{{#isMapContainer}}/*{{/isMapContainer}}{{/isEnum}} - case let .success(value): _result.{{name}} = value - case let .failure(error): break - {{#isEnum}}{{#isMapContainer}}*/ default: break //TODO: handle enum map scenario{{/isMapContainer}}{{/isEnum}} - } - {{/allVars}} - {{/unwrapRequired}} - {{#additionalPropertiesType}} - - for key in keys { - propsDictionary.removeValue(forKey: key) - } - - for key in propsDictionary.keys { - switch Decoders.decodeOptional(clazz: String.self, source: propsDictionary[key] as AnyObject?) { - - case let .success(value): _result[key] = value - default: continue - - } - } - {{/additionalPropertiesType}} - return .success(_result) - } else { - return .failure(.typeMismatch(expected: "{{classname}}", actual: "\(source)")) - } -{{/allVars.isEmpty}} -{{/isEnum}} - } - {{/isArrayModel}} - {{/model}} - {{/models}} - }() - - static fileprivate func initialize() { - _ = Decoders.__once - } -} diff --git a/src/main/resources/mustache/swift3/Podspec.mustache b/src/main/resources/mustache/swift3/Podspec.mustache deleted file mode 100644 index de8b124198..0000000000 --- a/src/main/resources/mustache/swift3/Podspec.mustache +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |s| - s.name = '{{projectName}}'{{#projectDescription}} - s.summary = '{{projectDescription}}'{{/projectDescription}} - s.ios.deployment_target = '9.0' - s.osx.deployment_target = '10.11' - s.tvos.deployment_target = '9.0' - s.version = '{{#podVersion}}{{podVersion}}{{/podVersion}}{{^podVersion}}0.0.1{{/podVersion}}' - s.source = {{#podSource}}{{& podSource}}{{/podSource}}{{^podSource}}{ :git => 'git@github.com:swagger-api/swagger-mustache.git', :tag => 'v1.0.0' }{{/podSource}}{{#podAuthors}} - s.authors = '{{podAuthors}}'{{/podAuthors}}{{#podSocialMediaURL}} - s.social_media_url = '{{podSocialMediaURL}}'{{/podSocialMediaURL}}{{#podDocsetURL}} - s.docset_url = '{{podDocsetURL}}'{{/podDocsetURL}} - s.license = {{#podLicense}}{{& podLicense}}{{/podLicense}}{{^podLicense}}'Proprietary'{{/podLicense}}{{#podHomepage}} - s.homepage = '{{podHomepage}}'{{/podHomepage}}{{#podSummary}} - s.summary = '{{podSummary}}'{{/podSummary}}{{#podDescription}} - s.description = '{{podDescription}}'{{/podDescription}}{{#podScreenshots}} - s.screenshots = {{& podScreenshots}}{{/podScreenshots}}{{#podDocumentationURL}} - s.documentation_url = '{{podDocumentationURL}}'{{/podDocumentationURL}} - s.source_files = '{{projectName}}/Classes/**/*.swift'{{#usePromiseKit}} - s.dependency 'PromiseKit/CorePromise', '~> 4.4.0'{{/usePromiseKit}}{{#useRxSwift}} - s.dependency 'RxSwift', '3.6.1'{{/useRxSwift}} - s.dependency 'Alamofire', '~> 4.5.0' -end diff --git a/src/main/resources/mustache/swift3/api.mustache b/src/main/resources/mustache/swift3/api.mustache deleted file mode 100644 index dc836b214f..0000000000 --- a/src/main/resources/mustache/swift3/api.mustache +++ /dev/null @@ -1,175 +0,0 @@ -{{#operations}}// -// {{classname}}.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation -import Alamofire{{#usePromiseKit}} -import PromiseKit{{/usePromiseKit}}{{#useRxSwift}} -import RxSwift{{/useRxSwift}} - -{{#swiftUseApiNamespace}} -extension {{projectName}}API { -{{/swiftUseApiNamespace}} - -{{#description}} -/** {{description}} */ -{{/description}} -open class {{classname}}: APIBase { -{{#operation}} -{{#contents}} - {{#parameters}} - {{#isEnum}} - /** - * enum for parameter {{paramName}} - */ - public enum {{enumName}}_{{operationId}}: {{^isContainer}}{{{dataType}}}{{/isContainer}}{{#isContainer}}String{{/isContainer}} { {{#allowableValues}}{{#enumVars}} - case {{name}} = {{#isContainer}}"{{/isContainer}}{{#isString}}"{{/isString}}{{{value}}}{{#isString}}"{{/isString}}{{#isContainer}}"{{/isContainer}}{{/enumVars}}{{/allowableValues}} - } - - {{/isEnum}} - {{/parameters}} - /** - {{#summary}} - {{{summary}}} - {{/summary}} - {{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - - parameter completion: completion handler to receive the data and the error objects - */ - open class func {{operationId}}({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}{{#hasParams}}, {{/hasParams}}completion: @escaping ((_ {{#returnType}}data: {{{returnType}}}?, _ {{/returnType}}error: ErrorResponse?) -> Void)) { - {{operationId}}WithRequestBuilder({{#parameters}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}).execute { (response, error) -> Void in - completion({{#returnType}}response?.body, {{/returnType}}error) - } - } - -{{#usePromiseKit}} - /** - {{#summary}} - {{{summary}}} - {{/summary}} - {{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - - returns: Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> - */ - open class func {{operationId}}({{#parameters}} {{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) -> Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { - let deferred = Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>.pending() - {{operationId}}({{#parameters}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { {{#returnType}}data, {{/returnType}}error in - if let error = error { - deferred.reject(error) - } else { - deferred.fulfill({{#returnType}}data!{{/returnType}}) - } - } - return deferred.promise - } -{{/usePromiseKit}} -{{#useRxSwift}} - /** - {{#summary}} - {{{summary}}} - {{/summary}} - {{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - - returns: Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> - */ - open class func {{operationId}}({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) -> Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { - return Observable.create { observer -> Disposable in - {{operationId}}({{#parameters}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { {{#returnType}}data, {{/returnType}}error in - if let error = error { - observer.on(.error(error as Error)) - } else { - observer.on(.next({{#returnType}}data!{{/returnType}})) - } - observer.on(.completed) - } - return Disposables.create() - } - } -{{/useRxSwift}} - - /** - {{#summary}} - {{{summary}}} - {{/summary}} - - {{httpMethod}} {{{path}}} - {{#notes}} - - {{{notes}}} - {{/notes}} - {{#subresourceOperation}} - - subresourceOperation: {{subresourceOperation}} - {{/subresourceOperation}} - {{#defaultResponse}} - - defaultResponse: {{defaultResponse}} - {{/defaultResponse}} - {{#authMethods}} - - {{#isBasic}}BASIC{{/isBasic}}{{#isOAuth}}OAuth{{/isOAuth}}{{#isApiKey}}API Key{{/isApiKey}}: - - type: {{type}}{{#keyParamName}} {{keyParamName}} {{#isKeyInQuery}}(QUERY){{/isKeyInQuery}}{{#isKeyInHeaer}}(HEADER){{/isKeyInHeaer}}{{/keyParamName}} - - name: {{name}}{{/authMethods}}{{#responseHeaders}} - - responseHeaders: {{responseHeaders}}{{/responseHeaders}}{{#examples}} - - examples: {{{examples}}}{{/examples}}{{#externalDocs}} - - externalDocs: {{externalDocs}}{{/externalDocs}} - {{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/parameters}} - - returns: RequestBuilder<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{description}} - */ - open class func {{operationId}}WithRequestBuilder({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) -> RequestBuilder<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { - {{^pathParams}}let{{/pathParams}}{{#pathParams}}{{^secondaryParam}}var{{/secondaryParam}}{{/pathParams}} path = "{{{path}}}"{{#pathParams}} - let {{paramName}}PreEscape = "\({{paramName}}{{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}.rawValue{{/isContainer}}{{/isEnum}})" - let {{paramName}}PostEscape = {{paramName}}PreEscape.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "" - path = path.replacingOccurrences(of: "{{=<% %>=}}{<%baseName%>}<%={{ }}=%>", with: {{paramName}}PostEscape, options: .literal, range: nil){{/pathParams}} - let URLString = {{projectName}}API.basePath + path - {{#bodyParam}} - let parameters = {{paramName}}{{^required}}?{{/required}}.encodeToJSON() - {{/bodyParam}} - {{^bodyParam}} - {{#hasFormParams}} - let formParams: [String:Any?] = [ - {{#formParams}} - {{> _param}}{{#hasMore}},{{/hasMore}} - {{/formParams}} - ] - - let nonNullParameters = APIHelper.rejectNil(formParams) - let parameters = APIHelper.convertBoolToString(nonNullParameters) - {{/hasFormParams}} - {{^hasFormParams}} - let parameters: [String:Any]? = nil - {{/hasFormParams}} - {{/bodyParam}}{{#hasQueryParams}} - var url = URLComponents(string: URLString) - url?.queryItems = APIHelper.mapValuesToQueryItems(values:[ - {{#queryParams}} - {{> _param}}{{#hasMore}},{{/hasMore}} - {{/queryParams}} - ]){{/hasQueryParams}}{{^hasQueryParams}} - let url = URLComponents(string: URLString){{/hasQueryParams}} - {{#headerParams}} - {{^secondaryParam}} - let nillableHeaders: [String: Any?] = [ - {{/secondaryParam}} - {{> _param}}{{#hasMore}},{{/hasMore}} - {{^hasMore}} - ] - let headerParameters = APIHelper.rejectNilHeaders(nillableHeaders) - {{/hasMore}} - {{/headerParams}} - - let requestBuilder: RequestBuilder<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>.Type = {{projectName}}API.requestBuilderFactory.getBuilder() - - return requestBuilder.init(method: "{{httpMethod}}", URLString: (url?.string ?? URLString), parameters: parameters, isBody: {{hasBodyParam}}{{#headerParams}}{{^secondaryParam}}, headers: headerParameters{{/secondaryParam}}{{/headerParams}}) - } - -{{/contents}} -{{/operation}} -} -{{#swiftUseApiNamespace}} -} -{{/swiftUseApiNamespace}} -{{/operations}} diff --git a/src/main/resources/mustache/swift3/git_push.sh.mustache b/src/main/resources/mustache/swift3/git_push.sh.mustache deleted file mode 100755 index f65b794638..0000000000 --- a/src/main/resources/mustache/swift3/git_push.sh.mustache +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="{{{gitUserId}}}" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="{{{gitRepoId}}}" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="{{{releaseNote}}}" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/src/main/resources/mustache/swift3/gitignore.mustache b/src/main/resources/mustache/swift3/gitignore.mustache deleted file mode 100644 index fc4e330f8f..0000000000 --- a/src/main/resources/mustache/swift3/gitignore.mustache +++ /dev/null @@ -1,63 +0,0 @@ -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## Build generated -build/ -DerivedData - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata - -## Other -*.xccheckout -*.moved-aside -*.xcuserstate -*.xcscmblueprint - -## Obj-C/Swift specific -*.hmap -*.ipa - -## Playgrounds -timeline.xctimeline -playground.xcworkspace - -# Swift Package Manager -# -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -.build/ - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md - -fastlane/report.xml -fastlane/screenshots diff --git a/src/main/resources/mustache/swift3/model.mustache b/src/main/resources/mustache/swift3/model.mustache deleted file mode 100644 index 129ecc1527..0000000000 --- a/src/main/resources/mustache/swift3/model.mustache +++ /dev/null @@ -1,105 +0,0 @@ -{{#models}} -{{#model}} -// -// {{classname}}.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -{{#description}} - -/** {{description}} */{{/description}} -{{#isArrayModel}} -public typealias {{classname}} = [{{arrayModelType}}] -{{/isArrayModel}} -{{^isArrayModel}} -{{#isEnum}} -public enum {{classname}}: {{dataType}} { -{{#allowableValues}}{{#enumVars}} case {{name}} = "{{{value}}}" -{{/enumVars}}{{/allowableValues}} - func encodeToJSON() -> Any { return self.rawValue } -} -{{/isEnum}} -{{^isEnum}} -open class {{classname}}: {{#parent}}{{{parent}}}{{/parent}}{{^parent}}JSONEncodable{{/parent}} { - -{{#vars}} -{{#isEnum}} - public enum {{enumName}}: {{^isContainer}}{{datatype}}{{/isContainer}}{{#isContainer}}String{{/isContainer}} { {{#allowableValues}}{{#enumVars}} - case {{name}} = {{#isContainer}}"{{/isContainer}}{{#isString}}"{{/isString}}{{{value}}}{{#isString}}"{{/isString}}{{#isContainer}}"{{/isContainer}}{{/enumVars}}{{/allowableValues}} - } -{{/isEnum}} -{{/vars}} -{{#vars}} -{{#isEnum}} - {{#description}}/** {{description}} */ - {{/description}}public var {{name}}: {{{datatypeWithEnum}}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}} -{{/isEnum}} -{{^isEnum}} - {{#description}}/** {{description}} */ - {{/description}}public var {{name}}: {{{datatype}}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}{{#objcCompatible}}{{#vendorExtensions.x-swift-optional-scalar}} - public var {{name}}Num: NSNumber? { - get { - return {{name}}.map({ return NSNumber(value: $0) }) - } - }{{/vendorExtensions.x-swift-optional-scalar}}{{/objcCompatible}} -{{/isEnum}} -{{/vars}} - -{{#additionalPropertiesType}} - public var additionalProperties: [AnyHashable:{{{additionalPropertiesType}}}] = [:] - -{{/additionalPropertiesType}} -{{^unwrapRequired}} - {{^parent}}public init() {}{{/parent}}{{/unwrapRequired}} -{{#unwrapRequired}} - public init({{#allVars}}{{^-first}}, {{/-first}}{{name}}: {{#isEnum}}{{datatypeWithEnum}}{{/isEnum}}{{^isEnum}}{{datatype}}{{/isEnum}}{{^required}}?=nil{{/required}}{{/allVars}}) { - {{#vars}} - self.{{name}} = {{name}} - {{/vars}} - }{{/unwrapRequired}} -{{#additionalPropertiesType}} - public subscript(key: AnyHashable) -> {{{additionalPropertiesType}}}? { - get { - if let value = additionalProperties[key] { - return value - } - return nil - } - - set { - additionalProperties[key] = newValue - } - } -{{/additionalPropertiesType}} - // MARK: JSONEncodable - {{#parent}}override {{/parent}}open func encodeToJSON() -> Any { - var nillableDictionary = {{#parent}}super.encodeToJSON() as? [String:Any?] ?? {{/parent}}[String:Any?](){{#vars}}{{#isNotContainer}}{{#isPrimitiveType}}{{^isEnum}}{{#isInteger}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}.encodeToJSON(){{/isInteger}}{{#isLong}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}.encodeToJSON(){{/isLong}}{{^isLong}}{{^isInteger}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{/isInteger}}{{/isLong}}{{/isEnum}}{{/isPrimitiveType}}{{#isEnum}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}.rawValue{{/isEnum}}{{^isPrimitiveType}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}.encodeToJSON(){{/isPrimitiveType}}{{/isNotContainer}}{{#isContainer}}{{^isEnum}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}.encodeToJSON(){{/isEnum}}{{#isEnum}}{{#isListContainer}} - nillableDictionary["{{baseName}}"] = self.{{name}}{{^unwrapRequired}}?{{/unwrapRequired}}{{#unwrapRequired}}{{^required}}?{{/required}}{{/unwrapRequired}}.map({$0.rawValue}).encodeToJSON(){{/isListContainer}}{{#isMapContainer}}//TODO: handle enum map scenario{{/isMapContainer}}{{/isEnum}}{{/isContainer}}{{/vars}} - - {{#additionalPropertiesType}} - for (key, value) in additionalProperties { - if let key = key as? String { - nillableDictionary[key] = value - } - } - - {{/additionalPropertiesType}} - let dictionary: [String:Any] = APIHelper.rejectNil(nillableDictionary) ?? [:] - return dictionary - } -} - -{{/isEnum}} -{{/isArrayModel}} -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/swift4/APIs.mustache b/src/main/resources/mustache/swift4/APIs.mustache deleted file mode 100644 index fe88150cc1..0000000000 --- a/src/main/resources/mustache/swift4/APIs.mustache +++ /dev/null @@ -1,61 +0,0 @@ -// APIs.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -open class {{projectName}}API { - open static var basePath = "{{{basePath}}}" - open static var credential: URLCredential? - open static var customHeaders: [String:String] = [:] - open static var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory() -} - -open class RequestBuilder { - var credential: URLCredential? - var headers: [String:String] - public let parameters: [String:Any]? - public let isBody: Bool - public let method: String - public let URLString: String - - /// Optional block to obtain a reference to the request's progress instance when available. - public var onProgressReady: ((Progress) -> ())? - - required public init(method: String, URLString: String, parameters: [String:Any]?, isBody: Bool, headers: [String:String] = [:]) { - self.method = method - self.URLString = URLString - self.parameters = parameters - self.isBody = isBody - self.headers = headers - - addHeaders({{projectName}}API.customHeaders) - } - - open func addHeaders(_ aHeaders:[String:String]) { - for (header, value) in aHeaders { - headers[header] = value - } - } - - open func execute(_ completion: @escaping (_ response: Response?, _ error: Error?) -> Void) { } - - public func addHeader(name: String, value: String) -> Self { - if !value.isEmpty { - headers[name] = value - } - return self - } - - open func addCredential() -> Self { - self.credential = {{projectName}}API.credential - return self - } -} - -public protocol RequestBuilderFactory { - func getNonDecodableBuilder() -> RequestBuilder.Type - func getBuilder() -> RequestBuilder.Type -} diff --git a/src/main/resources/mustache/swift4/AlamofireImplementations.mustache b/src/main/resources/mustache/swift4/AlamofireImplementations.mustache deleted file mode 100644 index 381fddcc81..0000000000 --- a/src/main/resources/mustache/swift4/AlamofireImplementations.mustache +++ /dev/null @@ -1,413 +0,0 @@ -// AlamofireImplementations.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation -import Alamofire - -class AlamofireRequestBuilderFactory: RequestBuilderFactory { - func getNonDecodableBuilder() -> RequestBuilder.Type { - return AlamofireRequestBuilder.self - } - - func getBuilder() -> RequestBuilder.Type { - return AlamofireDecodableRequestBuilder.self - } -} - -// Store manager to retain its reference -private var managerStore: [String: Alamofire.SessionManager] = [:] - -open class AlamofireRequestBuilder: RequestBuilder { - required public init(method: String, URLString: String, parameters: [String : Any]?, isBody: Bool, headers: [String : String] = [:]) { - super.init(method: method, URLString: URLString, parameters: parameters, isBody: isBody, headers: headers) - } - - /** - May be overridden by a subclass if you want to control the session - configuration. - */ - open func createSessionManager() -> Alamofire.SessionManager { - let configuration = URLSessionConfiguration.default - configuration.httpAdditionalHeaders = buildHeaders() - return Alamofire.SessionManager(configuration: configuration) - } - - /** - May be overridden by a subclass if you want to control the Content-Type - that is given to an uploaded form part. - - Return nil to use the default behavior (inferring the Content-Type from - the file extension). Return the desired Content-Type otherwise. - */ - open func contentTypeForFormPart(fileURL: URL) -> String? { - return nil - } - - /** - May be overridden by a subclass if you want to control the request - configuration (e.g. to override the cache policy). - */ - open func makeRequest(manager: SessionManager, method: HTTPMethod, encoding: ParameterEncoding, headers: [String:String]) -> DataRequest { - return manager.request(URLString, method: method, parameters: parameters, encoding: encoding, headers: headers) - } - - override open func execute(_ completion: @escaping (_ response: Response?, _ error: Error?) -> Void) { - let managerId:String = UUID().uuidString - // Create a new manager for each request to customize its request header - let manager = createSessionManager() - managerStore[managerId] = manager - - let encoding:ParameterEncoding = isBody ? JSONDataEncoding() : URLEncoding() - - let xMethod = Alamofire.HTTPMethod(rawValue: method) - let fileKeys = parameters == nil ? [] : parameters!.filter { $1 is NSURL } - .map { $0.0 } - - if fileKeys.count > 0 { - manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters! { - switch v { - case let fileURL as URL: - if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { - mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) - } - else { - mpForm.append(fileURL, withName: k) - } - case let string as String: - mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) - case let number as NSNumber: - mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) - default: - fatalError("Unprocessable value \(v) with key \(k)") - } - } - }, to: URLString, method: xMethod!, headers: nil, encodingCompletion: { encodingResult in - switch encodingResult { - case .success(let upload, _, _): - if let onProgressReady = self.onProgressReady { - onProgressReady(upload.uploadProgress) - } - self.processRequest(request: upload, managerId, completion) - case .failure(let encodingError): - completion(nil, ErrorResponse.error(415, nil, encodingError)) - } - }) - } else { - let request = makeRequest(manager: manager, method: xMethod!, encoding: encoding, headers: headers) - if let onProgressReady = self.onProgressReady { - onProgressReady(request.progress) - } - processRequest(request: request, managerId, completion) - } - - } - - fileprivate func processRequest(request: DataRequest, _ managerId: String, _ completion: @escaping (_ response: Response?, _ error: Error?) -> Void) { - if let credential = self.credential { - request.authenticate(usingCredential: credential) - } - - let cleanupRequest = { - _ = managerStore.removeValue(forKey: managerId) - } - - let validatedRequest = request.validate() - - switch T.self { - case is String.Type: - validatedRequest.responseString(completionHandler: { (stringResponse) in - cleanupRequest() - - if stringResponse.result.isFailure { - completion( - nil, - ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.result.error as Error!) - ) - return - } - - completion( - Response( - response: stringResponse.response!, - body: ((stringResponse.result.value ?? "") as! T) - ), - nil - ) - }) - case is URL.Type: - validatedRequest.responseData(completionHandler: { (dataResponse) in - cleanupRequest() - - do { - - guard !dataResponse.result.isFailure else { - throw DownloadException.responseFailed - } - - guard let data = dataResponse.data else { - throw DownloadException.responseDataMissing - } - - guard let request = request.request else { - throw DownloadException.requestMissing - } - - let fileManager = FileManager.default - let urlRequest = try request.asURLRequest() - let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] - let requestURL = try self.getURL(from: urlRequest) - - var requestPath = try self.getPath(from: requestURL) - - if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) { - requestPath = requestPath.appending("/\(headerFileName)") - } - - let filePath = documentsDirectory.appendingPathComponent(requestPath) - let directoryPath = filePath.deletingLastPathComponent().path - - try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) - try data.write(to: filePath, options: .atomic) - - completion( - Response( - response: dataResponse.response!, - body: (filePath as! T) - ), - nil - ) - - } catch let requestParserError as DownloadException { - completion(nil, ErrorResponse.error(400, dataResponse.data, requestParserError)) - } catch let error { - completion(nil, ErrorResponse.error(400, dataResponse.data, error)) - } - return - }) - case is Void.Type: - validatedRequest.responseData(completionHandler: { (voidResponse) in - cleanupRequest() - - if voidResponse.result.isFailure { - completion( - nil, - ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.result.error!) - ) - return - } - - completion( - Response( - response: voidResponse.response!, - body: nil), - nil - ) - }) - default: - validatedRequest.responseData(completionHandler: { (dataResponse) in - cleanupRequest() - - if dataResponse.result.isFailure { - completion( - nil, - ErrorResponse.error(dataResponse.response?.statusCode ?? 500, dataResponse.data, dataResponse.result.error!) - ) - return - } - - completion( - Response( - response: dataResponse.response!, - body: (dataResponse.data as! T) - ), - nil - ) - }) - } - } - - open func buildHeaders() -> [String: String] { - var httpHeaders = SessionManager.defaultHTTPHeaders - for (key, value) in self.headers { - httpHeaders[key] = value - } - return httpHeaders - } - - fileprivate func getFileName(fromContentDisposition contentDisposition : String?) -> String? { - - guard let contentDisposition = contentDisposition else { - return nil - } - - let items = contentDisposition.components(separatedBy: ";") - - var filename : String? = nil - - for contentItem in items { - - let filenameKey = "filename=" - guard let range = contentItem.range(of: filenameKey) else { - break - } - - filename = contentItem - return filename? - .replacingCharacters(in: range, with:"") - .replacingOccurrences(of: "\"", with: "") - .trimmingCharacters(in: .whitespacesAndNewlines) - } - - return filename - - } - - fileprivate func getPath(from url : URL) throws -> String { - - guard var path = URLComponents(url: url, resolvingAgainstBaseURL: true)?.path else { - throw DownloadException.requestMissingPath - } - - if path.hasPrefix("/") { - path.remove(at: path.startIndex) - } - - return path - - } - - fileprivate func getURL(from urlRequest : URLRequest) throws -> URL { - - guard let url = urlRequest.url else { - throw DownloadException.requestMissingURL - } - - return url - } - -} - -fileprivate enum DownloadException : Error { - case responseDataMissing - case responseFailed - case requestMissing - case requestMissingPath - case requestMissingURL -} - -public enum AlamofireDecodableRequestBuilderError: Error { - case emptyDataResponse - case nilHTTPResponse - case jsonDecoding(DecodingError) - case generalError(Error) -} - -open class AlamofireDecodableRequestBuilder: AlamofireRequestBuilder { - - override fileprivate func processRequest(request: DataRequest, _ managerId: String, _ completion: @escaping (_ response: Response?, _ error: Error?) -> Void) { - if let credential = self.credential { - request.authenticate(usingCredential: credential) - } - - let cleanupRequest = { - _ = managerStore.removeValue(forKey: managerId) - } - - let validatedRequest = request.validate() - - switch T.self { - case is String.Type: - validatedRequest.responseString(completionHandler: { (stringResponse) in - cleanupRequest() - - if stringResponse.result.isFailure { - completion( - nil, - ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.result.error as Error!) - ) - return - } - - completion( - Response( - response: stringResponse.response!, - body: ((stringResponse.result.value ?? "") as! T) - ), - nil - ) - }) - case is Void.Type: - validatedRequest.responseData(completionHandler: { (voidResponse) in - cleanupRequest() - - if voidResponse.result.isFailure { - completion( - nil, - ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.result.error!) - ) - return - } - - completion( - Response( - response: voidResponse.response!, - body: nil), - nil - ) - }) - case is Data.Type: - validatedRequest.responseData(completionHandler: { (dataResponse) in - cleanupRequest() - - if dataResponse.result.isFailure { - completion( - nil, - ErrorResponse.error(dataResponse.response?.statusCode ?? 500, dataResponse.data, dataResponse.result.error!) - ) - return - } - - completion( - Response( - response: dataResponse.response!, - body: (dataResponse.data as! T) - ), - nil - ) - }) - default: - validatedRequest.responseData(completionHandler: { (dataResponse: DataResponse) in - cleanupRequest() - - guard dataResponse.result.isSuccess else { - completion(nil, ErrorResponse.error(dataResponse.response?.statusCode ?? 500, dataResponse.data, dataResponse.result.error!)) - return - } - - guard let data = dataResponse.data, !data.isEmpty else { - completion(nil, ErrorResponse.error(-1, nil, AlamofireDecodableRequestBuilderError.emptyDataResponse)) - return - } - - guard let httpResponse = dataResponse.response else { - completion(nil, ErrorResponse.error(-2, nil, AlamofireDecodableRequestBuilderError.nilHTTPResponse)) - return - } - - var responseObj: Response? = nil - - let decodeResult: (decodableObj: T?, error: Error?) = CodableHelper.decode(T.self, from: data) - if decodeResult.error == nil { - responseObj = Response(response: httpResponse, body: decodeResult.decodableObj) - } - - completion(responseObj, decodeResult.error) - }) - } - } - -} diff --git a/src/main/resources/mustache/swift4/Cartfile.mustache b/src/main/resources/mustache/swift4/Cartfile.mustache deleted file mode 100644 index b8548fc548..0000000000 --- a/src/main/resources/mustache/swift4/Cartfile.mustache +++ /dev/null @@ -1,3 +0,0 @@ -github "Alamofire/Alamofire" ~> 4.5.0{{#usePromiseKit}} -github "mxcl/PromiseKit" ~> 4.4{{/usePromiseKit}}{{#useRxSwift}} -github "ReactiveX/RxSwift" ~> 4.0{{/useRxSwift}} diff --git a/src/main/resources/mustache/swift4/CodableHelper.mustache b/src/main/resources/mustache/swift4/CodableHelper.mustache deleted file mode 100644 index 323715c5f9..0000000000 --- a/src/main/resources/mustache/swift4/CodableHelper.mustache +++ /dev/null @@ -1,67 +0,0 @@ -// -// CodableHelper.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -public typealias EncodeResult = (data: Data?, error: Error?) - -open class CodableHelper { - - open static var dateformatter: DateFormatter? - - open class func decode(_ type: T.Type, from data: Data) -> (decodableObj: T?, error: Error?) where T : Decodable { - var returnedDecodable: T? = nil - var returnedError: Error? = nil - - let decoder = JSONDecoder() - if let df = self.dateformatter { - decoder.dateDecodingStrategy = .formatted(df) - } else { - decoder.dataDecodingStrategy = .base64 - let formatter = DateFormatter() - formatter.calendar = Calendar(identifier: .iso8601) - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.timeZone = TimeZone(secondsFromGMT: 0) - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" - decoder.dateDecodingStrategy = .formatted(formatter) - } - - do { - returnedDecodable = try decoder.decode(type, from: data) - } catch { - returnedError = error - } - - return (returnedDecodable, returnedError) - } - - open class func encode(_ value: T, prettyPrint: Bool = false) -> EncodeResult where T : Encodable { - var returnedData: Data? - var returnedError: Error? = nil - - let encoder = JSONEncoder() - if prettyPrint { - encoder.outputFormatting = .prettyPrinted - } - encoder.dataEncodingStrategy = .base64 - let formatter = DateFormatter() - formatter.calendar = Calendar(identifier: .iso8601) - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.timeZone = TimeZone(secondsFromGMT: 0) - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" - encoder.dateEncodingStrategy = .formatted(formatter) - - do { - returnedData = try encoder.encode(value) - } catch { - returnedError = error - } - - return (returnedData, returnedError) - } - -} diff --git a/src/main/resources/mustache/swift4/Configuration.mustache b/src/main/resources/mustache/swift4/Configuration.mustache deleted file mode 100644 index c03a10b930..0000000000 --- a/src/main/resources/mustache/swift4/Configuration.mustache +++ /dev/null @@ -1,15 +0,0 @@ -// Configuration.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -open class Configuration { - - // This value is used to configure the date formatter that is used to serialize dates into JSON format. - // You must set it prior to encoding any dates, and it will only be read once. - open static var dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" - -} \ No newline at end of file diff --git a/src/main/resources/mustache/swift4/Models.mustache b/src/main/resources/mustache/swift4/Models.mustache deleted file mode 100644 index 4962405f02..0000000000 --- a/src/main/resources/mustache/swift4/Models.mustache +++ /dev/null @@ -1,36 +0,0 @@ -// Models.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation - -protocol JSONEncodable { - func encodeToJSON() -> Any -} - -public enum ErrorResponse : Error { - case error(Int, Data?, Error) -} - -open class Response { - open let statusCode: Int - open let header: [String: String] - open let body: T? - - public init(statusCode: Int, header: [String: String], body: T?) { - self.statusCode = statusCode - self.header = header - self.body = body - } - - public convenience init(response: HTTPURLResponse, body: T?) { - let rawHeader = response.allHeaderFields - var header = [String:String]() - for case let (key, value) as (String, String) in rawHeader { - header[key] = value - } - self.init(statusCode: response.statusCode, header: header, body: body) - } -} diff --git a/src/main/resources/mustache/swift4/Podspec.mustache b/src/main/resources/mustache/swift4/Podspec.mustache deleted file mode 100644 index 8c9689ea9e..0000000000 --- a/src/main/resources/mustache/swift4/Podspec.mustache +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |s| - s.name = '{{projectName}}'{{#projectDescription}} - s.summary = '{{projectDescription}}'{{/projectDescription}} - s.ios.deployment_target = '9.0' - s.osx.deployment_target = '10.11' - s.tvos.deployment_target = '9.0' - s.version = '{{#podVersion}}{{podVersion}}{{/podVersion}}{{^podVersion}}0.0.1{{/podVersion}}' - s.source = {{#podSource}}{{& podSource}}{{/podSource}}{{^podSource}}{ :git => 'git@github.com:swagger-api/swagger-mustache.git', :tag => 'v1.0.0' }{{/podSource}}{{#podAuthors}} - s.authors = '{{podAuthors}}'{{/podAuthors}}{{#podSocialMediaURL}} - s.social_media_url = '{{podSocialMediaURL}}'{{/podSocialMediaURL}}{{#podDocsetURL}} - s.docset_url = '{{podDocsetURL}}'{{/podDocsetURL}} - s.license = {{#podLicense}}{{& podLicense}}{{/podLicense}}{{^podLicense}}'Proprietary'{{/podLicense}}{{#podHomepage}} - s.homepage = '{{podHomepage}}'{{/podHomepage}}{{#podSummary}} - s.summary = '{{podSummary}}'{{/podSummary}}{{#podDescription}} - s.description = '{{podDescription}}'{{/podDescription}}{{#podScreenshots}} - s.screenshots = {{& podScreenshots}}{{/podScreenshots}}{{#podDocumentationURL}} - s.documentation_url = '{{podDocumentationURL}}'{{/podDocumentationURL}} - s.source_files = '{{projectName}}/Classes/**/*.swift'{{#usePromiseKit}} - s.dependency 'PromiseKit/CorePromise', '~> 4.4.0'{{/usePromiseKit}}{{#useRxSwift}} - s.dependency 'RxSwift', '~> 4.0'{{/useRxSwift}} - s.dependency 'Alamofire', '~> 4.5.0' -end diff --git a/src/main/resources/mustache/swift4/README.mustache b/src/main/resources/mustache/swift4/README.mustache deleted file mode 100644 index 933e46039a..0000000000 --- a/src/main/resources/mustache/swift4/README.mustache +++ /dev/null @@ -1,65 +0,0 @@ -# Swift4 API client for {{packageName}} - -{{#appDescription}} -{{{appDescription}}} -{{/appDescription}} - -## Overview -This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. - -- API version: {{appVersion}} -- Package version: {{packageVersion}} -{{^hideGenerationTimestamp}} -- Build date: {{generatedDate}} -{{/hideGenerationTimestamp}} -- Build package: {{generatorClass}} -{{#infoUrl}} -For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}}) -{{/infoUrl}} - -## Installation -Put the package under your project folder and add the following in import: -``` - "./{{packageName}}" -``` - -## Documentation for API Endpoints - -All URIs are relative to *{{basePath}}* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} -{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} - -## Documentation For Models - -{{#models}}{{#model}} - [{{{classname}}}]({{modelDocPath}}{{{classname}}}.md) -{{/model}}{{/models}} - -## Documentation For Authorization - -{{^authMethods}} All endpoints do not require authorization. -{{/authMethods}}{{#authMethods}}{{#last}} Authentication schemes defined for the API:{{/last}}{{/authMethods}} -{{#authMethods}}## {{{name}}} - -{{#isApiKey}}- **Type**: API key -- **API key parameter name**: {{{keyParamName}}} -- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} -{{/isApiKey}} -{{#isBasic}}- **Type**: HTTP basic authentication -{{/isBasic}} -{{#isOAuth}}- **Type**: OAuth -- **Flow**: {{{flow}}} -- **Authorization URL**: {{{authorizationUrl}}} -- **Scopes**: {{^scopes}}N/A{{/scopes}} -{{#scopes}} - **{{{scope}}}**: {{{description}}} -{{/scopes}} -{{/isOAuth}} - -{{/authMethods}} - -## Author - -{{#apiInfo}}{{#apis}}{{^hasMore}}{{infoEmail}} -{{/hasMore}}{{/apis}}{{/apiInfo}} diff --git a/src/main/resources/mustache/swift4/_param.mustache b/src/main/resources/mustache/swift4/_param.mustache deleted file mode 100644 index 5caacbc600..0000000000 --- a/src/main/resources/mustache/swift4/_param.mustache +++ /dev/null @@ -1 +0,0 @@ -"{{baseName}}": {{paramName}}{{^isEnum}}{{#isInteger}}{{^required}}?{{/required}}.encodeToJSON(){{/isInteger}}{{#isLong}}{{^required}}?{{/required}}.encodeToJSON(){{/isLong}}{{/isEnum}}{{#isEnum}}{{^isContainer}}{{^required}}?{{/required}}.rawValue{{/isContainer}}{{/isEnum}}{{#isDate}}{{^required}}?{{/required}}.encodeToJSON(){{/isDate}}{{#isDateTime}}{{^required}}?{{/required}}.encodeToJSON(){{/isDateTime}} \ No newline at end of file diff --git a/src/main/resources/mustache/swift4/api.mustache b/src/main/resources/mustache/swift4/api.mustache deleted file mode 100644 index e5492cf337..0000000000 --- a/src/main/resources/mustache/swift4/api.mustache +++ /dev/null @@ -1,164 +0,0 @@ -{{#operations}}// -// {{classname}}.swift -// -// Generated by swagger-codegen -// https://github.com/swagger-api/swagger-codegen -// - -import Foundation -import Alamofire{{#usePromiseKit}} -import PromiseKit{{/usePromiseKit}}{{#useRxSwift}} -import RxSwift{{/useRxSwift}} - -{{#swiftUseApiNamespace}} -extension {{projectName}}API { -{{/swiftUseApiNamespace}} - -{{#description}} -/** {{description}} */{{/description}} -open class {{classname}} { -{{#operation}} -{{#contents}} - {{#parameters}} - {{#isEnum}} - /** - * enum for parameter {{paramName}} - */ - public enum {{enumName}}_{{operationId}}: {{^isContainer}}{{{dataType}}}{{/isContainer}}{{#isContainer}}String{{/isContainer}} { {{#allowableValues}}{{#enumVars}} - case {{name}} = {{#isContainer}}"{{/isContainer}}{{#isString}}"{{/isString}}{{{value}}}{{#isString}}"{{/isString}}{{#isContainer}}"{{/isContainer}}{{/enumVars}}{{/allowableValues}} - } - - {{/isEnum}} - {{/parameters}} - /** - {{#summary}} - {{{summary}}} - {{/summary}}{{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} - - parameter completion: completion handler to receive the data and the error objects - */ - open class func {{operationId}}({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}{{#hasParams}}, {{/hasParams}}completion: @escaping ((_ data: {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}?,_ error: Error?) -> Void)) { - {{operationId}}WithRequestBuilder({{#parameters}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}).execute { (response, error) -> Void in - {{#returnType}} - completion(response?.body, error) - {{/returnType}} - {{^returnType}} - if error == nil { - completion((), error) - } else { - completion(nil, error) - } - {{/returnType}} - } - } - -{{#usePromiseKit}} - /** - {{#summary}} - {{{summary}}} - {{/summary}}{{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} - - returns: Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> - */ - open class func {{operationId}}({{#parameters}} {{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) -> Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { - let deferred = Promise<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>.pending() - {{operationId}}({{#parameters}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { data, error in - if let error = error { - deferred.reject(error) - } else { - deferred.fulfill(data!) - } - } - return deferred.promise - } -{{/usePromiseKit}} -{{#useRxSwift}} - /** - {{#summary}} - {{{summary}}} - {{/summary}}{{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} - - returns: Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> - */ - open class func {{operationId}}({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) -> Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { - return Observable.create { observer -> Disposable in - {{operationId}}({{#parameters}}{{paramName}}: {{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) { data, error in - if let error = error { - observer.on(.error(error)) - } else { - observer.on(.next(data!)) - } - observer.on(.completed) - } - return Disposables.create() - } - } -{{/useRxSwift}} - - /** - {{#summary}} - {{{summary}}} - {{/summary}} - - {{httpMethod}} {{{path}}}{{#notes}} - - {{{notes}}}{{/notes}}{{#subresourceOperation}} - - subresourceOperation: {{subresourceOperation}}{{/subresourceOperation}}{{#defaultResponse}} - - defaultResponse: {{defaultResponse}}{{/defaultResponse}}{{#authMethods}} - - {{#isBasic}}BASIC{{/isBasic}}{{#isOAuth}}OAuth{{/isOAuth}}{{#isApiKey}}API Key{{/isApiKey}}: - - type: {{type}}{{#keyParamName}} {{keyParamName}} {{#isKeyInQuery}}(QUERY){{/isKeyInQuery}}{{#isKeyInHeaer}}(HEADER){{/isKeyInHeaer}}{{/keyParamName}} - - name: {{name}}{{/authMethods}}{{#responseHeaders}} - - responseHeaders: {{responseHeaders}}{{/responseHeaders}}{{#examples}} - - examples: {{{examples}}}{{/examples}}{{#externalDocs}} - - externalDocs: {{externalDocs}}{{/externalDocs}}{{#hasParams}} - {{/hasParams}}{{#parameters}} - - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{/parameters}} - - - returns: RequestBuilder<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{description}} - */ - open class func {{operationId}}WithRequestBuilder({{#parameters}}{{paramName}}: {{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{#hasMore}}, {{/hasMore}}{{/parameters}}) -> RequestBuilder<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { - {{^pathParams}}let{{/pathParams}}{{#pathParams}}{{^secondaryParam}}var{{/secondaryParam}}{{/pathParams}} path = "{{{path}}}"{{#pathParams}} - let {{paramName}}PreEscape = "\({{paramName}}{{#isEnum}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}.rawValue{{/isContainer}}{{/isEnum}})" - let {{paramName}}PostEscape = {{paramName}}PreEscape.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "" - path = path.replacingOccurrences(of: "{{=<% %>=}}{<%baseName%>}<%={{ }}=%>", with: {{paramName}}PostEscape, options: .literal, range: nil){{/pathParams}} - let URLString = {{projectName}}API.basePath + path - {{#bodyParam}} - let parameters = JSONEncodingHelper.encodingParameters(forEncodableObject: {{paramName}}) - {{/bodyParam}} - {{^bodyParam}} - {{#hasFormParams}} - let formParams: [String:Any?] = [ - {{#formParams}} - {{> _param}}{{#hasMore}},{{/hasMore}} - {{/formParams}} - ] - - let nonNullParameters = APIHelper.rejectNil(formParams) - let parameters = APIHelper.convertBoolToString(nonNullParameters) - {{/hasFormParams}} - {{^hasFormParams}} - let parameters: [String:Any]? = nil - {{/hasFormParams}} - {{/bodyParam}}{{#hasQueryParams}} - var url = URLComponents(string: URLString) - url?.queryItems = APIHelper.mapValuesToQueryItems([ - {{#queryParams}} - {{> _param}}{{#hasMore}}, {{/hasMore}} - {{/queryParams}} - ]){{/hasQueryParams}}{{^hasQueryParams}} - let url = URLComponents(string: URLString){{/hasQueryParams}}{{#headerParams}}{{^secondaryParam}} - let nillableHeaders: [String: Any?] = [{{/secondaryParam}} - {{> _param}}{{#hasMore}},{{/hasMore}}{{^hasMore}} - ] - let headerParameters = APIHelper.rejectNilHeaders(nillableHeaders){{/hasMore}}{{/headerParams}} - - let requestBuilder: RequestBuilder<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}>.Type = {{projectName}}API.requestBuilderFactory.{{#returnType}}getBuilder(){{/returnType}}{{^returnType}}getNonDecodableBuilder(){{/returnType}} - - return requestBuilder.init(method: "{{httpMethod}}", URLString: (url?.string ?? URLString), parameters: parameters, isBody: {{hasBodyParam}}{{#headerParams}}{{^secondaryParam}}, headers: headerParameters{{/secondaryParam}}{{/headerParams}}) - } - -{{/contents}} -{{/operation}} -} -{{#swiftUseApiNamespace}} -} -{{/swiftUseApiNamespace}} -{{/operations}} diff --git a/src/main/resources/mustache/swift4/git_push.sh.mustache b/src/main/resources/mustache/swift4/git_push.sh.mustache deleted file mode 100755 index a2d7523483..0000000000 --- a/src/main/resources/mustache/swift4/git_push.sh.mustache +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="{{{gitUserId}}}" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="{{{gitRepoId}}}" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="{{{releaseNote}}}" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/src/main/resources/mustache/typescript-angular/README.mustache b/src/main/resources/mustache/typescript-angular/README.mustache deleted file mode 100644 index 7f7acecf7f..0000000000 --- a/src/main/resources/mustache/typescript-angular/README.mustache +++ /dev/null @@ -1,193 +0,0 @@ -## {{npmName}}@{{npmVersion}} - -### Building - -To install the required dependencies and to build the typescript sources run: -``` -npm install -npm run build -``` - -### publishing - -{{#useNgPackagr}} -First build the package than run ```npm publish dist``` (don't forget to specify the `dist` folder!) -{{/useNgPackagr}} -{{^useNgPackagr}} -First build the package than run ```npm publish``` -{{/useNgPackagr}} - -### consuming - -Navigate to the folder of your consuming project and run one of next commands. - -_published:_ - -``` -npm install {{npmName}}@{{npmVersion}} --save -``` - -_without publishing (not recommended):_ - -``` -{{#useNgPackagr}} -npm install PATH_TO_GENERATED_PACKAGE/dist --save -{{/useNgPackagr}} -{{^useNgPackagr}} -npm install PATH_TO_GENERATED_PACKAGE --save -{{/useNgPackagr}} -``` - -_using `npm link`:_ - -{{#useNgPackagr}} -In PATH_TO_GENERATED_PACKAGE/dist: -{{/useNgPackagr}} -{{^useNgPackagr}} -In PATH_TO_GENERATED_PACKAGE: -{{/useNgPackagr}} -``` -npm link -``` - -In your project: -``` -npm link {{npmName}} -``` - -__Note for Windows users:__ The Angular CLI has troubles to use linked npm packages. -Please refer to this issue https://github.com/angular/angular-cli/issues/8284 for a solution / workaround. -Published packages are not effected by this issue. - - -#### General usage - -In your Angular project: - - -``` -// without configuring providers -import { ApiModule } from '{{npmName}}'; -{{#useHttpClient}}import { HttpClientModule } from '@angular/common/http';{{/useHttpClient}} -{{^useHttpClient}}import { HttpModule } from '@angular/http';{{/useHttpClient}} - -@NgModule({ - imports: [ - ApiModule, - {{#useHttpClient}}// make sure to import the HttpClientModule in the AppModule only, - // see https://github.com/angular/angular/issues/20575 - HttpClientModule{{/useHttpClient}}{{^useHttpClient}}HttpModule{{/useHttpClient}} - ], - declarations: [ AppComponent ], - providers: [], - bootstrap: [ AppComponent ] -}) -export class AppModule {} -``` - -``` -// configuring providers -import { ApiModule, Configuration, ConfigurationParameters } from '{{npmName}}'; - -export function apiConfigFactory (): Configuration => { - const params: ConfigurationParameters = { - // set configuration parameters here. - } - return new Configuration(params); -} - -@NgModule({ - imports: [ ApiModule.forRoot(apiConfigFactory) ], - declarations: [ AppComponent ], - providers: [], - bootstrap: [ AppComponent ] -}) -export class AppModule {} -``` - -``` -import { DefaultApi } from '{{npmName}}'; - -export class AppComponent { - constructor(private apiGateway: DefaultApi) { } -} -``` - -Note: The ApiModule is restricted to being instantiated once app wide. -This is to ensure that all services are treated as singletons. - -#### Using multiple swagger files / APIs / ApiModules -In order to use multiple `ApiModules` generated from different swagger files, -you can create an alias name when importing the modules -in order to avoid naming conflicts: -``` -import { ApiModule } from 'my-api-path'; -import { ApiModule as OtherApiModule } from 'my-other-api-path'; -{{#useHttpClient}}import { HttpClientModule } from '@angular/common/http';{{/useHttpClient}} -{{^useHttpClient}}import { HttpModule } from '@angular/http';{{/useHttpClient}} - -@NgModule({ - imports: [ - ApiModule, - OtherApiModule, - {{#useHttpClient}}// make sure to import the HttpClientModule in the AppModule only, - // see https://github.com/angular/angular/issues/20575 - HttpClientModule{{/useHttpClient}}{{^useHttpClient}}HttpModule{{/useHttpClient}} - ] -}) -export class AppModule { - -} -``` - - -### Set service base path -If different than the generated base path, during app bootstrap, you can provide the base path to your service. - -``` -import { BASE_PATH } from '{{npmName}}'; - -bootstrap(AppComponent, [ - { provide: BASE_PATH, useValue: 'https://your-web-service.com' }, -]); -``` -or - -``` -import { BASE_PATH } from '{{npmName}}'; - -@NgModule({ - imports: [], - declarations: [ AppComponent ], - providers: [ provide: BASE_PATH, useValue: 'https://your-web-service.com' ], - bootstrap: [ AppComponent ] -}) -export class AppModule {} -``` - - -#### Using @angular/cli -First extend your `src/environments/*.ts` files by adding the corresponding base path: - -``` -export const environment = { - production: false, - API_BASE_PATH: 'http://127.0.0.1:8080' -}; -``` - -In the src/app/app.module.ts: -``` -import { BASE_PATH } from '{{npmName}}'; -import { environment } from '../environments/environment'; - -@NgModule({ - declarations: [ - AppComponent - ], - imports: [ ], - providers: [{ provide: BASE_PATH, useValue: environment.API_BASE_PATH }], - bootstrap: [ AppComponent ] -}) -export class AppModule { } -``` \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/api.module.mustache b/src/main/resources/mustache/typescript-angular/api.module.mustache deleted file mode 100644 index 06dad036e6..0000000000 --- a/src/main/resources/mustache/typescript-angular/api.module.mustache +++ /dev/null @@ -1,38 +0,0 @@ -import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; -import { Configuration } from './configuration'; -{{#useHttpClient}}import { HttpClient } from '@angular/common/http';{{/useHttpClient}} -{{^useHttpClient}}import { Http } from '@angular/http';{{/useHttpClient}} - -{{#apiInfo}} -{{#apis}} -import { {{classname}} } from './{{importPath}}'; -{{/apis}} -{{/apiInfo}} - -@NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ - {{#apiInfo}}{{#apis}}{{classname}}{{#hasMore}}, - {{/hasMore}}{{/apis}}{{/apiInfo}} ] -}) -export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [ { provide: Configuration, useFactory: configurationFactory } ] - }; - } - - constructor( @Optional() @SkipSelf() parentModule: ApiModule, - @Optional() http: {{#useHttpClient}}HttpClient{{/useHttpClient}}{{^useHttpClient}}Http{{/useHttpClient}}) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error('You need to import the {{#useHttpClient}}HttpClientModule{{/useHttpClient}}{{^useHttpClient}}HttpModule{{/useHttpClient}} in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575'); - } - } -} diff --git a/src/main/resources/mustache/typescript-angular/api.service.mustache b/src/main/resources/mustache/typescript-angular/api.service.mustache deleted file mode 100644 index e4c590828c..0000000000 --- a/src/main/resources/mustache/typescript-angular/api.service.mustache +++ /dev/null @@ -1,361 +0,0 @@ -{{>licenseInfo}} -/* tslint:disable:no-unused-variable member-ordering */ - -import { Inject, Injectable, Optional } from '@angular/core'; -{{#useHttpClient}} -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; -{{/useHttpClient}} -{{^useHttpClient}} -import { Http, Headers, URLSearchParams } from '@angular/http'; -import { RequestMethod, RequestOptions, RequestOptionsArgs } from '@angular/http'; -import { Response, ResponseContentType } from '@angular/http'; -import { CustomQueryEncoderHelper } from '../encoder'; -{{/useHttpClient}} - -{{^useRxJS6}} -import { Observable } from 'rxjs/Observable'; -{{/useRxJS6}} -{{#useRxJS6}} -import { Observable } from 'rxjs'; -{{/useRxJS6}} -{{^useHttpClient}} -import '../rxjs-operators'; -{{/useHttpClient}} - -{{#imports}} -import { {{classname}} } from '../{{filename}}'; -{{/imports}} - -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; -{{#withInterfaces}} -import { {{classname}}Interface } from './{{classFilename}}Interface'; -{{/withInterfaces}} - -{{#operations}} - -{{#description}} -/** - * {{&description}} - */ -{{/description}} -{{^providedInRoot}} -@Injectable() -{{/providedInRoot}} -{{#providedInRoot}} -@Injectable({ - providedIn: 'root' -}) -{{/providedInRoot}} -{{#withInterfaces}} -export class {{classname}} implements {{classname}}Interface { -{{/withInterfaces}} -{{^withInterfaces}} -export class {{classname}} { -{{/withInterfaces}} - - protected basePath = '{{{basePath}}}'; - public defaultHeaders = new {{#useHttpClient}}Http{{/useHttpClient}}Headers(); - public configuration = new Configuration(); - - constructor(protected {{#useHttpClient}}httpClient: HttpClient{{/useHttpClient}}{{^useHttpClient}}http: Http{{/useHttpClient}}, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - -{{^useHttpClient}} -{{! Before HttpClient implementation or method overloading we relied on 2 functions, 1 to return the straight body as json - and another to get the full response.}} -{{#operation}} -{{#contents}} - /** - * {{¬es}} - {{#summary}} - * @summary {{&summary}} - {{/summary}} - {{#parameters}}* @param {{paramName}} {{description}} - {{/parameters}}*/ - {{! if you change this method signature, also change the version below }} - public {{nickname}}({{#parameters}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}{{#hasMore}}, {{/hasMore}}{{/parameters}}{{^useHttpClient}}{{#hasParams}}, {{/hasParams}}extraHttpRequestParams?: RequestOptionsArgs{{/useHttpClient}}): Observable<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}{}{{/returnType}}> { - return this.{{nickname}}WithHttpInfo({{#parameters}}{{paramName}}, {{/parameters}}extraHttpRequestParams) - .map((response: Response) => { - if (response.status === 204) { - return undefined; - } else { -{{^isResponseFile}} - return response.json() || {}; -{{/isResponseFile}} -{{#isResponseFile}} - return response.blob(); -{{/isResponseFile}} - } - }); - } - -{{/contents}} -{{/operation}} -{{/useHttpClient}} - -{{#operation}} -{{#contents}} - /** - * {{summary}} - * {{notes}} - {{#parameters}}* @param {{paramName}} {{description}} - {{/parameters}}{{#useHttpClient}}* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress.{{/useHttpClient}} - */ - {{#useHttpClient}} - public {{nickname}}({{#parameters}}{{^isConstEnumParam}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/isConstEnumParam}}{{/parameters}}observe?: 'body', reportProgress?: boolean): Observable<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>; - public {{nickname}}({{#parameters}}{{^isConstEnumParam}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/isConstEnumParam}}{{/parameters}}observe?: 'response', reportProgress?: boolean): Observable>; - public {{nickname}}({{#parameters}}{{^isConstEnumParam}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/isConstEnumParam}}{{/parameters}}observe?: 'events', reportProgress?: boolean): Observable>; - public {{nickname}}({{#parameters}}{{^isConstEnumParam}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/isConstEnumParam}}{{/parameters}}observe: any = 'body', reportProgress: boolean = false ): Observable { - {{/useHttpClient}} - {{^useHttpClient}} - public {{nickname}}WithHttpInfo({{#parameters}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/parameters}}extraHttpRequestParams?: RequestOptionsArgs): Observable { - {{/useHttpClient}} -{{#parameters}} - -{{#required}} - {{#isConstEnumParam}} - let {{paramName}} = {{{dataType}}}; - {{/isConstEnumParam}} - {{^isConstEnumParam}} - if ({{paramName}} === null || {{paramName}} === undefined) { - throw new Error('Required parameter {{paramName}} was null or undefined when calling {{nickname}}.'); - } - {{/isConstEnumParam}} -{{/required}} -{{/parameters}} - -{{#hasQueryParams}} - {{#useHttpClient}} - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - {{/useHttpClient}} - {{^useHttpClient}} - let queryParameters = new URLSearchParams('', new CustomQueryEncoderHelper()); - {{/useHttpClient}} -{{#queryParams}} - {{#isListContainer}} - if ({{paramName}}) { - {{#isCollectionFormatMulti}} - {{paramName}}.forEach((element) => { - {{#useHttpClient}}queryParameters = {{/useHttpClient}}queryParameters.append('{{baseName}}', element); - }) - {{/isCollectionFormatMulti}} - {{^isCollectionFormatMulti}} - {{#useHttpClient}}queryParameters = {{/useHttpClient}}queryParameters.set('{{baseName}}', {{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}'])); - {{/isCollectionFormatMulti}} - } - {{/isListContainer}} - {{^isListContainer}} - if ({{paramName}} !== undefined && {{paramName}} !== null) { - {{#isDateTime}} - {{#useHttpClient}}queryParameters = {{/useHttpClient}}queryParameters.set('{{baseName}}', {{paramName}}.toISOString()); - {{/isDateTime}} - {{^isDateTime}} - {{#useHttpClient}}queryParameters = {{/useHttpClient}}queryParameters.set('{{baseName}}', {{paramName}}); - {{/isDateTime}} - } - {{/isListContainer}} -{{/queryParams}} - -{{/hasQueryParams}} - let headers = {{#useHttpClient}}this.defaultHeaders;{{/useHttpClient}}{{^useHttpClient}}new Headers(this.defaultHeaders.toJSON()); // https://github.com/angular/angular/issues/6845{{/useHttpClient}} -{{#headerParams}} - {{#isListContainer}} - if ({{paramName}}) { - {{#useHttpClient}}headers = {{/useHttpClient}}headers.set('{{baseName}}', {{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}'])); - } - {{/isListContainer}} - {{^isListContainer}} - if ({{paramName}} !== undefined && {{paramName}} !== null) { - {{#useHttpClient}}headers = {{/useHttpClient}}headers.set('{{baseName}}', String({{paramName}})); - } - {{/isListContainer}} -{{/headerParams}} - -{{#authMethods}} - // authentication ({{name}}) required -{{#isApiKey}} -{{#isKeyInHeader}} - if (this.configuration.apiKeys["{{keyParamName}}"]) { - {{#useHttpClient}}headers = {{/useHttpClient}}headers.set('{{keyParamName}}', this.configuration.apiKeys["{{keyParamName}}"]); - } - -{{/isKeyInHeader}} -{{#isKeyInQuery}} - if (this.configuration.apiKeys["{{keyParamName}}"]) { - {{#useHttpClient}}queryParameters = {{/useHttpClient}}queryParameters.set('{{keyParamName}}', this.configuration.apiKeys["{{keyParamName}}"]); - } - -{{/isKeyInQuery}} -{{/isApiKey}} -{{#isBasic}} - if (this.configuration.username || this.configuration.password) { - {{#useHttpClient}}headers = {{/useHttpClient}}headers.set('Authorization', 'Basic ' + btoa(this.configuration.username + ':' + this.configuration.password)); - } - -{{/isBasic}} -{{#isOAuth}} - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - {{#useHttpClient}}headers = {{/useHttpClient}}headers.set('Authorization', 'Bearer ' + accessToken); - } - -{{/isOAuth}} -{{/authMethods}} - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - {{#produces}} - '{{{mediaType}}}'{{#hasMore}},{{/hasMore}} - {{/produces}} - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { -{{^useHttpClient}} - headers.set('Accept', httpHeaderAcceptSelected); -{{/useHttpClient}} -{{#useHttpClient}} - headers = headers.set('Accept', httpHeaderAcceptSelected); -{{/useHttpClient}} - } - - // to determine the Content-Type header - const consumes: string[] = [ - {{#consumes}} - '{{{mediaType}}}'{{#hasMore}},{{/hasMore}} - {{/consumes}} - ]; -{{#bodyParam}} - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { -{{^useHttpClient}} - headers.set('Content-Type', httpContentTypeSelected); -{{/useHttpClient}} -{{#useHttpClient}} - headers = headers.set('Content-Type', httpContentTypeSelected); -{{/useHttpClient}} - } -{{/bodyParam}} - -{{#hasFormParams}} - const canConsumeForm = this.canConsumeForm(consumes); - - let formParams: { append(param: string, value: any): void; }; - let useForm = false; - let convertFormParamsToString = false; -{{#formParams}} -{{#isFile}} - // use FormData to transmit files using content-type "multipart/form-data" - // see https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data - useForm = canConsumeForm; -{{/isFile}} -{{/formParams}} - if (useForm) { - formParams = new FormData(); - } else { -{{#useHttpClient}} - formParams = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); -{{/useHttpClient}} -{{^useHttpClient}} - // TODO: this fails if a parameter is a file, the api can't consume "multipart/form-data" and a blob is passed. - convertFormParamsToString = true; - formParams = new URLSearchParams('', new CustomQueryEncoderHelper()); - // set the content-type explicitly to avoid having it set to 'text/plain' - headers.set('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8'); -{{/useHttpClient}} - } - -{{#formParams}} - {{#isListContainer}} - if ({{paramName}}) { - {{#isCollectionFormatMulti}} - {{paramName}}.forEach((element) => { - {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', element){{#useHttpClient}} || formParams{{/useHttpClient}}; - }) - {{/isCollectionFormatMulti}} - {{^isCollectionFormatMulti}} - {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', {{paramName}}.join(COLLECTION_FORMATS['{{collectionFormat}}'])){{#useHttpClient}} || formParams{{/useHttpClient}}; - {{/isCollectionFormatMulti}} - } - {{/isListContainer}} - {{^isListContainer}} - if ({{paramName}} !== undefined) { - {{#useHttpClient}}formParams = {{/useHttpClient}}formParams.append('{{baseName}}', {{paramName}}){{#useHttpClient}} || formParams{{/useHttpClient}}; - } - {{/isListContainer}} -{{/formParams}} - -{{/hasFormParams}} -{{#useHttpClient}} - return this.httpClient.{{httpMethod}}{{^isResponseFile}}<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>{{/isResponseFile}}(`${this.basePath}{{{path}}}`,{{#isBodyAllowed}} - {{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}{{#hasFormParams}}convertFormParamsToString ? formParams.toString() : formParams{{/hasFormParams}}{{^hasFormParams}}null{{/hasFormParams}}{{/bodyParam}},{{/isBodyAllowed}} - { -{{#hasQueryParams}} - params: queryParameters, -{{/hasQueryParams}} -{{#isResponseFile}} - responseType: "blob", -{{/isResponseFile}} - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); -{{/useHttpClient}} -{{^useHttpClient}} - let requestOptions: RequestOptionsArgs = new RequestOptions({ - method: {{httpMethod}}, - headers: headers, -{{#bodyParam}} - body: {{paramName}} == null ? '' : JSON.stringify({{paramName}}), // https://github.com/angular/angular/issues/10612 -{{/bodyParam}} -{{#hasFormParams}} - body: convertFormParamsToString ? formParams.toString() : formParams, -{{/hasFormParams}} -{{#isResponseFile}} - responseType: ResponseContentType.Blob, -{{/isResponseFile}} -{{#hasQueryParams}} - search: queryParameters, -{{/hasQueryParams}} - withCredentials:this.configuration.withCredentials - }); - // https://github.com/swagger-api/swagger-codegen/issues/4037 - if (extraHttpRequestParams) { - requestOptions = (Object).assign(requestOptions, extraHttpRequestParams); - } - - return this.http.request(`${this.basePath}{{{path}}}`, requestOptions); -{{/useHttpClient}} - } - -{{/contents}} -{{/operation}} -} -{{/operations}} diff --git a/src/main/resources/mustache/typescript-angular/apiInterface.mustache b/src/main/resources/mustache/typescript-angular/apiInterface.mustache deleted file mode 100644 index fb60c1a394..0000000000 --- a/src/main/resources/mustache/typescript-angular/apiInterface.mustache +++ /dev/null @@ -1,45 +0,0 @@ -{{>licenseInfo}} -{{#useHttpClient}} -import { HttpHeaders } from '@angular/common/http'; -{{/useHttpClient}} -{{^useHttpClient}} -import { Headers } from '@angular/http'; -{{/useHttpClient}} - -{{^useRxJS6}} -import { Observable } from 'rxjs/Observable'; -{{/useRxJS6}} -{{#useRxJS6}} -import { Observable } from 'rxjs'; -{{/useRxJS6}} - -{{#imports}} -import { {{classname}} } from '../{{filename}}'; -{{/imports}} - - -import { Configuration } from '../configuration'; - -{{#operations}} - -{{#description}} - /** - * {{&description}} - */ -{{/description}} -export interface {{classname}}Interface { - defaultHeaders: {{#useHttpClient}}Http{{/useHttpClient}}Headers; - configuration: Configuration; - {{^useHttpClient}}[others: string]: any;{{/useHttpClient}} - -{{#operation}} - /** - * {{summary}} - * {{notes}} - {{#allParams}}* @param {{paramName}} {{description}} - {{/allParams}}*/ - {{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}extraHttpRequestParams?: any): Observable<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}{}{{/returnType}}>; - -{{/operation}} -} -{{/operations}} diff --git a/src/main/resources/mustache/typescript-angular/apis.mustache b/src/main/resources/mustache/typescript-angular/apis.mustache deleted file mode 100644 index 514b5e0d10..0000000000 --- a/src/main/resources/mustache/typescript-angular/apis.mustache +++ /dev/null @@ -1,12 +0,0 @@ -{{#apiInfo}} -{{#apis}} -{{#operations}} -export * from './{{ classFilename }}'; -import { {{ classname }} } from './{{ classFilename }}'; -{{/operations}} -{{#withInterfaces}} -export * from './{{ classFilename }}Interface' -{{/withInterfaces}} -{{/apis}} -export const APIS = [{{#apis}}{{#operations}}{{ classname }}{{/operations}}{{^-last}}, {{/-last}}{{/apis}}]; -{{/apiInfo}} diff --git a/src/main/resources/mustache/typescript-angular/configuration.mustache b/src/main/resources/mustache/typescript-angular/configuration.mustache deleted file mode 100644 index 82e8458f39..0000000000 --- a/src/main/resources/mustache/typescript-angular/configuration.mustache +++ /dev/null @@ -1,79 +0,0 @@ -export interface ConfigurationParameters { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; -} - -export class Configuration { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; - - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } - - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType (contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } - - let type = contentTypes.find(x => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } - - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } - - let type = accepts.find(x => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } - - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } -} diff --git a/src/main/resources/mustache/typescript-angular/encoder.mustache b/src/main/resources/mustache/typescript-angular/encoder.mustache deleted file mode 100644 index c3ac784124..0000000000 --- a/src/main/resources/mustache/typescript-angular/encoder.mustache +++ /dev/null @@ -1,42 +0,0 @@ -{{#useHttpClient}} - import { HttpUrlEncodingCodec } from '@angular/common/http'; -{{/useHttpClient}} -{{^useHttpClient}} - import { QueryEncoder } from '@angular/http'; -{{/useHttpClient}} - -{{#useHttpClient}} -/** -* CustomHttpUrlEncodingCodec -* Fix plus sign (+) not encoding, so sent as blank space -* See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 -*/ -export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } -} -{{/useHttpClient}} -{{^useHttpClient}} -/** -* CustomQueryEncoderHelper -* Fix plus sign (+) not encoding, so sent as blank space -* See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 -*/ -export class CustomQueryEncoderHelper extends QueryEncoder { - encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } -} -{{/useHttpClient}} - diff --git a/src/main/resources/mustache/typescript-angular/git_push.sh.mustache b/src/main/resources/mustache/typescript-angular/git_push.sh.mustache deleted file mode 100755 index a2d7523483..0000000000 --- a/src/main/resources/mustache/typescript-angular/git_push.sh.mustache +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 - -if [ "$git_user_id" = "" ]; then - git_user_id="{{{gitUserId}}}" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="{{{gitRepoId}}}" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="{{{releaseNote}}}" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=`git remote` -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' - diff --git a/src/main/resources/mustache/typescript-angular/gitignore b/src/main/resources/mustache/typescript-angular/gitignore deleted file mode 100644 index 149b576547..0000000000 --- a/src/main/resources/mustache/typescript-angular/gitignore +++ /dev/null @@ -1,4 +0,0 @@ -wwwroot/*.js -node_modules -typings -dist diff --git a/src/main/resources/mustache/typescript-angular/index.mustache b/src/main/resources/mustache/typescript-angular/index.mustache deleted file mode 100644 index c312b70fa3..0000000000 --- a/src/main/resources/mustache/typescript-angular/index.mustache +++ /dev/null @@ -1,5 +0,0 @@ -export * from './api/api'; -export * from './model/models'; -export * from './variables'; -export * from './configuration'; -export * from './api.module'; \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/licenseInfo.mustache b/src/main/resources/mustache/typescript-angular/licenseInfo.mustache deleted file mode 100644 index 7d61c4ee05..0000000000 --- a/src/main/resources/mustache/typescript-angular/licenseInfo.mustache +++ /dev/null @@ -1,11 +0,0 @@ -/** - * {{{appName}}} - * {{{appDescription}}} - * - * {{#version}}OpenAPI spec version: {{{version}}}{{/version}} - * {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} - * - * NOTE: This class is auto generated by the swagger code generator program. - * https://github.com/swagger-api/swagger-codegen.git - * Do not edit the class manually. - */ \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/model.mustache b/src/main/resources/mustache/typescript-angular/model.mustache deleted file mode 100644 index 0b93ad2998..0000000000 --- a/src/main/resources/mustache/typescript-angular/model.mustache +++ /dev/null @@ -1,16 +0,0 @@ -{{>licenseInfo}} -{{#models}} -{{#model}} -{{#tsImports}} -import { {{classname}} } from './{{filename}}'; -{{/tsImports}} - - -{{#description}} -/** - * {{{description}}} - */ -{{/description}} -{{#isEnum}}{{>modelEnum}}{{/isEnum}}{{^isEnum}}{{#isAlias}}{{>modelAlias}}{{/isAlias}}{{^isAlias}}{{#taggedUnions}}{{>modelTaggedUnion}}{{/taggedUnions}}{{^taggedUnions}}{{>modelGeneric}}{{/taggedUnions}}{{/isAlias}}{{/isEnum}} -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/typescript-angular/modelAlias.mustache b/src/main/resources/mustache/typescript-angular/modelAlias.mustache deleted file mode 100644 index c1c6bf7a5d..0000000000 --- a/src/main/resources/mustache/typescript-angular/modelAlias.mustache +++ /dev/null @@ -1 +0,0 @@ -export type {{classname}} = {{dataType}}; \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/modelEnum.mustache b/src/main/resources/mustache/typescript-angular/modelEnum.mustache deleted file mode 100644 index 7ad77ac62a..0000000000 --- a/src/main/resources/mustache/typescript-angular/modelEnum.mustache +++ /dev/null @@ -1,9 +0,0 @@ -export type {{classname}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}}; - -export const {{classname}} = { -{{#allowableValues}} -{{#enumVars}} - {{name}}: {{{value}}} as {{classname}}{{^-last}},{{/-last}} -{{/enumVars}} -{{/allowableValues}} -}; \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/modelGeneric.mustache b/src/main/resources/mustache/typescript-angular/modelGeneric.mustache deleted file mode 100644 index a4248ea3da..0000000000 --- a/src/main/resources/mustache/typescript-angular/modelGeneric.mustache +++ /dev/null @@ -1,10 +0,0 @@ -export interface {{classname}} {{#parent}}extends {{{parent}}} {{/parent}}{ {{>modelGenericAdditionalProperties}} -{{#vars}} - {{#description}} - /** - * {{{description}}} - */ - {{/description}} - {{#isReadOnly}}readonly {{/isReadOnly}}{{name}}{{^required}}?{{/required}}: {{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}}; -{{/vars}} -}{{>modelGenericEnums}} \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/modelGenericAdditionalProperties.mustache b/src/main/resources/mustache/typescript-angular/modelGenericAdditionalProperties.mustache deleted file mode 100644 index e6499ce9d6..0000000000 --- a/src/main/resources/mustache/typescript-angular/modelGenericAdditionalProperties.mustache +++ /dev/null @@ -1,5 +0,0 @@ -{{#additionalPropertiesType}} - - [key: string]: {{{additionalPropertiesType}}}{{#hasVars}} | any{{/hasVars}}; - -{{/additionalPropertiesType}} \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/modelGenericEnums.mustache b/src/main/resources/mustache/typescript-angular/modelGenericEnums.mustache deleted file mode 100644 index eb450b57fc..0000000000 --- a/src/main/resources/mustache/typescript-angular/modelGenericEnums.mustache +++ /dev/null @@ -1,16 +0,0 @@ -{{#hasEnums}} - -export namespace {{classname}} { -{{#vars}} - {{#isEnum}} - export type {{enumName}} = {{#allowableValues}}{{#enumVars}}{{{value}}}{{^-last}} | {{/-last}}{{/enumVars}}{{/allowableValues}}; - export const {{enumName}} = { - {{#allowableValues}} - {{#enumVars}} - {{name}}: {{{value}}} as {{enumName}}{{^-last}},{{/-last}} - {{/enumVars}} - {{/allowableValues}} - }; - {{/isEnum}} -{{/vars}} -}{{/hasEnums}} \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/modelTaggedUnion.mustache b/src/main/resources/mustache/typescript-angular/modelTaggedUnion.mustache deleted file mode 100644 index cd7d1c8b93..0000000000 --- a/src/main/resources/mustache/typescript-angular/modelTaggedUnion.mustache +++ /dev/null @@ -1,21 +0,0 @@ -{{#discriminator}} -export type {{classname}} = {{#children}}{{^-first}} | {{/-first}}{{classname}}{{/children}}; -{{/discriminator}} -{{^discriminator}} -{{#parent}} -export interface {{classname}} { {{>modelGenericAdditionalProperties}} -{{#allVars}} - {{#description}} - /** - * {{{description}}} - */ - {{/description}} - {{name}}{{^required}}?{{/required}}: {{#discriminatorValue}}'{{discriminatorValue}}'{{/discriminatorValue}}{{^discriminatorValue}}{{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{{datatype}}}{{/isEnum}}{{/discriminatorValue}}; -{{/allVars}} -} -{{>modelGenericEnums}} -{{/parent}} -{{^parent}} -{{>modelGeneric}} -{{/parent}} -{{/discriminator}} \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-angular/models.mustache b/src/main/resources/mustache/typescript-angular/models.mustache deleted file mode 100644 index 02a39c248c..0000000000 --- a/src/main/resources/mustache/typescript-angular/models.mustache +++ /dev/null @@ -1,5 +0,0 @@ -{{#models}} -{{#model}} -export * from './{{{ classFilename }}}'; -{{/model}} -{{/models}} diff --git a/src/main/resources/mustache/typescript-angular/ng-package.mustache b/src/main/resources/mustache/typescript-angular/ng-package.mustache deleted file mode 100644 index 3b17900dc9..0000000000 --- a/src/main/resources/mustache/typescript-angular/ng-package.mustache +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "./node_modules/ng-packagr/ng-package.schema.json", - "lib": { - "entryFile": "index.ts" - } -} diff --git a/src/main/resources/mustache/typescript-angular/package.mustache b/src/main/resources/mustache/typescript-angular/package.mustache deleted file mode 100644 index 88f8b40e80..0000000000 --- a/src/main/resources/mustache/typescript-angular/package.mustache +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "{{{npmName}}}", - "version": "{{{npmVersion}}}", - "description": "swagger client for {{{npmName}}}", - "author": "Swagger Codegen Contributors", - "keywords": [ - "swagger-client" - ], - "license": "Unlicense", - {{#useNgPackagr}} - "scripts": { - "build": "ng-packagr -p ng-package.json" - }, - {{/useNgPackagr}} - {{^useNgPackagr}} - "main": "dist/index.js", - "module": "dist/index.js", - "typings": "dist/index.d.ts", - "scripts": { - "build": "ngc", - "postinstall": "npm run build" - }, - {{/useNgPackagr}} - "peerDependencies": { - "@angular/core": "^{{ngVersion}}", - "@angular/http": "^{{ngVersion}}", - "@angular/common": "^{{ngVersion}}", - "@angular/compiler": "^{{ngVersion}}", - "core-js": "^2.4.0", - "reflect-metadata": "^0.1.3", - "rxjs": "{{#useRxJS6}}^6.1.0{{/useRxJS6}}{{^useRxJS6}}^5.4.0{{/useRxJS6}}", - "zone.js": "^0.7.6" - }, - "devDependencies": { - "@angular/compiler-cli": "^{{ngVersion}}", - "@angular/core": "^{{ngVersion}}", - "@angular/http": "^{{ngVersion}}", - "@angular/common": "^{{ngVersion}}", - "@angular/compiler": "^{{ngVersion}}", - "@angular/platform-browser": "^{{ngVersion}}",{{#useNgPackagr}} - "ng-packagr": {{#useOldNgPackagr}}"^1.6.0"{{/useOldNgPackagr}}{{^useOldNgPackagr}}"^2.4.1"{{/useOldNgPackagr}},{{/useNgPackagr}} - "reflect-metadata": "^0.1.3", - "rxjs": "{{#useRxJS6}}^6.1.0{{/useRxJS6}}{{^useRxJS6}}^5.4.0{{/useRxJS6}}", - "zone.js": "^0.7.6", - "typescript": ">=2.1.5 <2.8" - }{{#npmRepository}},{{/npmRepository}} -{{#npmRepository}} - "publishConfig": { - "registry": "{{{npmRepository}}}" - } -{{/npmRepository}} -} diff --git a/src/main/resources/mustache/typescript-angular/rxjs-operators.mustache b/src/main/resources/mustache/typescript-angular/rxjs-operators.mustache deleted file mode 100644 index 5659cd0694..0000000000 --- a/src/main/resources/mustache/typescript-angular/rxjs-operators.mustache +++ /dev/null @@ -1,11 +0,0 @@ -// RxJS imports according to https://angular.io/docs/ts/latest/guide/server-communication.html#!#rxjs - -// See node_module/rxjs/Rxjs.js -// Import just the rxjs statics and operators we need for THIS app. - -// Statics -import 'rxjs/add/observable/throw'; - -// Operators -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/map'; diff --git a/src/main/resources/mustache/typescript-angular/tsconfig.mustache b/src/main/resources/mustache/typescript-angular/tsconfig.mustache deleted file mode 100644 index 930d403618..0000000000 --- a/src/main/resources/mustache/typescript-angular/tsconfig.mustache +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "noImplicitAny": false, - "suppressImplicitAnyIndexErrors": true, - "target": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}es5{{/supportsES6}}", - "module": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}commonjs{{/supportsES6}}", - "moduleResolution": "node", - "removeComments": true, - "sourceMap": true, - "outDir": "./dist", - "noLib": false, - "declaration": true, - "lib": [ "es6", "dom" ] - }, - "exclude": [ - "node_modules", - "dist" - ], - "filesGlob": [ - "./model/*.ts", - "./api/*.ts" - ]{{^useNgPackagr}}, - "angularCompilerOptions": { - "genDir": "dist", - "skipTemplateCodegen": true - }{{/useNgPackagr}} -} diff --git a/src/main/resources/mustache/typescript-angular/typings.mustache b/src/main/resources/mustache/typescript-angular/typings.mustache deleted file mode 100644 index 507c40e5cb..0000000000 --- a/src/main/resources/mustache/typescript-angular/typings.mustache +++ /dev/null @@ -1,5 +0,0 @@ -{ - "globalDependencies": { - "core-js": "registry:dt/core-js#0.0.0+20160725163759" - } -} diff --git a/src/main/resources/mustache/typescript-angular/variables.mustache b/src/main/resources/mustache/typescript-angular/variables.mustache deleted file mode 100644 index b3241fcebc..0000000000 --- a/src/main/resources/mustache/typescript-angular/variables.mustache +++ /dev/null @@ -1,9 +0,0 @@ -import { {{injectionToken}} } from '@angular/core'; - -export const BASE_PATH = new {{injectionToken}}{{#injectionTokenTyped}}{{/injectionTokenTyped}}('basePath'); -export const COLLECTION_FORMATS = { - 'csv': ',', - 'tsv': ' ', - 'ssv': ' ', - 'pipes': '|' -} diff --git a/src/main/resources/mustache/typescript-fetch/api_test.mustache b/src/main/resources/mustache/typescript-fetch/api_test.mustache new file mode 100644 index 0000000000..362da01a7d --- /dev/null +++ b/src/main/resources/mustache/typescript-fetch/api_test.mustache @@ -0,0 +1,29 @@ +{{>licenseInfo}} + +import * as api from "./api" +import { Configuration } from "./configuration" + +const config: Configuration = {} + +{{#apiInfo}} +{{#apis}} +{{#operations}} +describe("{{classname}}", () => { + let instance: api.{{classname}} + beforeEach(function() { + instance = new api.{{classname}}(config) + }); + +{{#operation}} + test("{{operationId}}", () => { + {{#allParams}} + const {{{paramName}}}: {{^isPrimitiveType}}api.{{/isPrimitiveType}}{{{dataType}}} = {{>api_test_default_value}} + {{/allParams}} + return expect(instance.{{operationId}}({{#allParams}}{{{paramName}}}, {{/allParams}}{})).resolves.toBe(null) + }) +{{/operation}} +}) + +{{/operations}} +{{/apis}} +{{/apiInfo}} \ No newline at end of file diff --git a/src/main/resources/mustache/typescript-fetch/licenseInfo.mustache b/src/main/resources/mustache/typescript-fetch/licenseInfo.mustache new file mode 100644 index 0000000000..1678b2e7ea --- /dev/null +++ b/src/main/resources/mustache/typescript-fetch/licenseInfo.mustache @@ -0,0 +1,11 @@ +/** + * {{{appName}}} + * {{{appDescription}}} + * + * {{#version}}OpenAPI spec version: {{{version}}}{{/version}} + * {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}} + * + * NOTE: This file is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the file manually. + */ diff --git a/src/main/resources/mustache/typescript-fetch/package.mustache b/src/main/resources/mustache/typescript-fetch/package.mustache new file mode 100644 index 0000000000..4246113a80 --- /dev/null +++ b/src/main/resources/mustache/typescript-fetch/package.mustache @@ -0,0 +1,41 @@ +{ + "name": "{{npmName}}", + "version": "{{npmVersion}}", + "description": "swagger client for {{npmName}}", + "author": "Swagger Codegen Contributors", + "keywords": [ + "fetch", + "typescript", + "swagger-client", + "{{npmName}}" + ], + "license": "Unlicense", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "scripts" : { + "build": "tsc --outDir dist/", + "test": "jest", + "prepublishOnly": "npm run build" + }, + "dependencies": { + "isomorphic-fetch": "^3.0.0" + }, + "devDependencies": { + "@types/jest": "^25.2.1", + "@types/node": "^13.13.0", + "jest": "^25.4.0", + "ts-jest": "^25.4.0", + "typescript": "^3.8.3" + }, + "jest": { + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", + "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"] + }{{#npmRepository}}, + "publishConfig":{ + "registry":"{{npmRepository}}" + } +{{/npmRepository}} +} diff --git a/src/main/resources/mustache/typescript-fetch/tsconfig.mustache b/src/main/resources/mustache/typescript-fetch/tsconfig.mustache new file mode 100644 index 0000000000..4e4cad5cec --- /dev/null +++ b/src/main/resources/mustache/typescript-fetch/tsconfig.mustache @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "{{#supportsES6}}es6{{/supportsES6}}{{^supportsES6}}es5{{/supportsES6}}", + "module": "commonjs", + "noImplicitAny": true, + "outDir": "dist", + "rootDir": "."{{^supportsES6}}, + "lib": [ + "es6", + "dom" + ] + {{/supportsES6}} + }, + "exclude": [ + "dist", + "node_modules", + "**/*.spec.ts" + ] +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/AbstractCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/AbstractCodegenTest.java new file mode 100644 index 0000000000..76fbb741d9 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/AbstractCodegenTest.java @@ -0,0 +1,76 @@ +package io.swagger.codegen.v3.generators; + +import io.swagger.codegen.v3.CodegenConfig; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenSchema; +import io.swagger.codegen.v3.CodegenType; +import io.swagger.codegen.v3.ISchemaHandler; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.parser.OpenAPIV3Parser; +import io.swagger.v3.parser.core.models.ParseOptions; +import io.swagger.v3.parser.core.models.SwaggerParseResult; + +import java.util.List; +import java.util.Map; + +public abstract class AbstractCodegenTest { + + protected OpenAPI getOpenAPI(String filePath) { + OpenAPIV3Parser openApiParser = new OpenAPIV3Parser(); + ParseOptions options = new ParseOptions(); + options.setResolve(true); + options.setFlatten(true); + SwaggerParseResult parseResult = openApiParser.readLocation(filePath, null, options); + + return parseResult.getOpenAPI(); + } + + protected DefaultCodegenConfig createConfig() { + return new DefaultCodegenConfig() { + @Override + public String getDefaultTemplateDir() { + return null; + } + + @Override + public CodegenType getTag() { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getHelp() { + return null; + } + }; + } + + protected CodegenWrapper processSchemas(CodegenConfig codegenConfig, OpenAPI openAPI) { + codegenConfig.preprocessOpenAPI(openAPI); + final Map schemaMap = openAPI.getComponents().getSchemas(); + + final CodegenWrapper codegenWrapper = new CodegenWrapper(((DefaultCodegenConfig)codegenConfig).getSchemaHandler()); + for (String name : schemaMap.keySet()) { + final Schema schema = schemaMap.get(name); + final CodegenModel codegenModel = codegenConfig.fromModel(name, schema, schemaMap); + codegenWrapper.addCodegenSchema(codegenModel, schema); + } + + generateComposedObjects(codegenWrapper.getSchemaHandler(), + codegenWrapper.getCodegenSchemas(), + codegenWrapper.getAllModels()); + + return codegenWrapper; + } + + protected void generateComposedObjects(ISchemaHandler schemaHandler, List codegenSchemas, Map allModels) { + for (CodegenSchema codegenSchema : codegenSchemas) { + schemaHandler.processComposedSchemas(codegenSchema.getCodegenModel(), codegenSchema.getSchema(), allModels); + } + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/CodegenWrapper.java b/src/test/java/io/swagger/codegen/v3/generators/CodegenWrapper.java new file mode 100644 index 0000000000..678fbc1ce5 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/CodegenWrapper.java @@ -0,0 +1,52 @@ +package io.swagger.codegen.v3.generators; + +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenSchema; +import io.swagger.codegen.v3.ISchemaHandler; +import io.swagger.v3.oas.models.media.Schema; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CodegenWrapper { + + private ISchemaHandler schemaHandler; + private List codegenSchemas; + private Map allModels; + + public CodegenWrapper(){} + + public CodegenWrapper(ISchemaHandler schemaHandler){ + this.schemaHandler = schemaHandler; + } + + public void addCodegenSchema(CodegenModel codegenModel, Schema schema) { + if (codegenSchemas == null) { + codegenSchemas = new ArrayList<>(); + } + codegenSchemas.add(new CodegenSchema(codegenModel, schema)); + addModel(codegenModel); + } + + public void addModel(CodegenModel codegenModel) { + if (allModels == null) { + allModels = new HashMap<>(); + } + allModels.put(codegenModel.classname, codegenModel); + } + + public ISchemaHandler getSchemaHandler() { + return schemaHandler; + } + + public List getCodegenSchemas() { + return codegenSchemas; + } + + public Map getAllModels() { + return allModels; + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java b/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java index 773c273146..fbecc43268 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/DefaultCodegenConfigTest.java @@ -5,10 +5,13 @@ import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.CodegenParameter; import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenResponse; import io.swagger.codegen.v3.CodegenType; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.headers.Header; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Content; import io.swagger.v3.oas.models.media.IntegerSchema; @@ -17,6 +20,7 @@ import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.parser.OpenAPIV3Parser; import org.testng.Assert; @@ -24,6 +28,9 @@ import org.testng.annotations.Test; import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -282,7 +289,71 @@ public void testOptionalFormParams() { List requiredParams = codegenOp.getRequiredParams(); Assert.assertTrue(requiredParams == null || requiredParams.size() == 0); } - + + @Test + public void testFromResponse_inlineHeaders() { + final String RESPONSE_CODE = "200"; + + ApiResponse apiResponse = new ApiResponse(); + Header inlineHeader = new Header().description("This is header1").schema(new Schema().type("string").example("header_val")); + apiResponse.addHeaderObject("header1", inlineHeader); + + OpenAPI openAPI = new OpenAPI().components(new Components().responses(new HashMap<>())); + openAPI.getComponents().addHeaders("ref-header1", inlineHeader); + + final DefaultCodegenConfig codegen = new P_DefaultCodegenConfig(); + codegen.preprocessOpenAPI(openAPI); + CodegenResponse codegenResponse = codegen.fromResponse(RESPONSE_CODE, apiResponse); + + Assert.assertEquals(codegenResponse.code, RESPONSE_CODE); + + CodegenProperty headerProperty = codegenResponse.headers.get(0); + Assert.assertNotNull(headerProperty); + Assert.assertEquals(headerProperty.description, inlineHeader.getSchema().getDescription()); + Assert.assertEquals(headerProperty.datatype, "String"); + Assert.assertEquals(headerProperty.example, inlineHeader.getSchema().getExample()); + } + + @Test + public void testFromResponse_referenceHeaders() { + final String RESPONSE_CODE = "200"; + + ApiResponse apiResponse = new ApiResponse(); + apiResponse.addHeaderObject("header1", new Header().$ref("#/components/ref-header1")); + + OpenAPI openAPI = new OpenAPI().components(new Components().responses(new HashMap<>())); + Header referencedHeader = new Header().schema(new Schema().description("This is header1").type("string").example("header_val")); + openAPI.getComponents().addHeaders("ref-header1", referencedHeader); + + final DefaultCodegenConfig codegen = new P_DefaultCodegenConfig(); + codegen.preprocessOpenAPI(openAPI); + CodegenResponse codegenResponse = codegen.fromResponse(RESPONSE_CODE, apiResponse); + + Assert.assertEquals(codegenResponse.code, RESPONSE_CODE); + + CodegenProperty headerProperty = codegenResponse.headers.get(0); + Assert.assertNotNull(headerProperty); + Assert.assertEquals(headerProperty.description, referencedHeader.getSchema().getDescription()); + Assert.assertEquals(headerProperty.datatype, "String"); + Assert.assertEquals(headerProperty.example, referencedHeader.getSchema().getExample()); + } + + @Test(dataProvider = "testCommonPrefixProvider") + public void testCommonPrefix(List vars, String expectedPrefix) { + DefaultCodegenConfig codegen = new P_DefaultCodegenConfig(); + Assert.assertEquals(codegen.findCommonPrefixOfVars(vars), expectedPrefix); + } + + @DataProvider(name = "testCommonPrefixProvider") + public Object[][] provideData_testCommonPrefix() { + return new Object[][]{ + {Collections.singletonList("FOO_BAR"), ""}, + {Arrays.asList("FOO_BAR", "FOO_BAZ"), "FOO_"}, + {Arrays.asList("FOO_BAR", "FOO_BAZ", "TEST"), ""}, + {Arrays.asList("STATUS-ON", "STATUS-OFF", "STATUS"), ""} + }; + } + private static class P_DefaultCodegenConfig extends DefaultCodegenConfig{ @Override public String getArgumentsLocation() { diff --git a/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java b/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java new file mode 100644 index 0000000000..73b15b0d63 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java @@ -0,0 +1,103 @@ +package io.swagger.codegen.v3.generators; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.codegen.v3.service.GenerationRequest; +import io.swagger.codegen.v3.service.GeneratorService; +import io.swagger.codegen.v3.service.Options; +import io.swagger.util.Json; +import io.swagger.util.Yaml; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.List; + +/** + * + * helper methods to test specific generator result (set of files) + * + */ +public abstract class GeneratorRunner { + + public static List runGenerator( + String name, + String specPath, + GenerationRequest.CodegenVersion codegenVersion, + boolean v2Spec, + boolean yaml, + boolean flattenInlineComposedSchema, + String outFolder + ) throws Exception { + + String path = outFolder; + if (StringUtils.isBlank(path)) { + path = getTmpFolder().getAbsolutePath(); + } + GenerationRequest request = new GenerationRequest(); + request + .codegenVersion(codegenVersion) // use V2 to target Swagger/OpenAPI 2.x Codegen version + .type(GenerationRequest.Type.CLIENT) + .lang(name) + .spec(loadSpecAsNode( specPath, + yaml, // YAML file, use false for JSON + v2Spec)) // OpenAPI 3.x - use true for Swagger/OpenAPI 2.x definitions + .options( + new Options() + .flattenInlineComposedSchema(flattenInlineComposedSchema) + .outputDir(path) + ); + + List files = new GeneratorService().generationRequest(request).generate(); + return files; + } + + public static File getOutFolder(String path, boolean delete) { + try { + File outputFolder = new File(path); + if (delete) { + // TODO delete.. + } + return outputFolder; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static File getTmpFolder() { + try { + File outputFolder = Files.createTempDirectory("codegentest-").toFile(); + outputFolder.deleteOnExit(); + return outputFolder; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static JsonNode loadSpecAsNode(final String file, boolean yaml, boolean v2) { + InputStream in = null; + + try { + in = GeneratorRunner.class.getClassLoader().getResourceAsStream(file); + if (yaml) { + if (v2) { + return Yaml.mapper().readTree(in); + } else { + return io.swagger.v3.core.util.Yaml.mapper().readTree(in); + } + } + if (v2) { + return Json.mapper().readTree(in); + } + return io.swagger.v3.core.util.Json.mapper().readTree(in); + } catch (Exception e) { + throw new RuntimeException("could not load file " + file); + } finally { + IOUtils.closeQuietly(in); + } + } + +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegenTest.java new file mode 100644 index 0000000000..707107c331 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/dotnet/AspNetCoreServerCodegenTest.java @@ -0,0 +1,35 @@ +package io.swagger.codegen.v3.generators.dotnet; + +import io.swagger.codegen.v3.CodegenConfig; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import io.swagger.codegen.v3.generators.CodegenWrapper; +import io.swagger.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class AspNetCoreServerCodegenTest extends AbstractCodegenTest { + + @Test(description = "Verify if List<> is fixed for array schema with composed items.") + public void checkArrayItemsSchemaParent() { + final OpenAPI openAPI = getOpenAPI("3_0_0/composed_schemas.yaml"); + final CodegenConfig config = new AspNetCoreServerCodegen(); + final CodegenWrapper codegenWrapper = processSchemas(config, openAPI); + CodegenModel codegenModel = codegenWrapper.getAllModels().get("AllPetsResponse"); + Assert.assertEquals(codegenModel.parent, "List"); + } + + @Test + public void checkArrayItemsSchemaProperty() { + final OpenAPI openAPI = getOpenAPI("3_0_0/composed_schemas.yaml"); + final CodegenConfig config = new AspNetCoreServerCodegen(); + final CodegenWrapper codegenWrapper = processSchemas(config, openAPI); + final CodegenModel codegenModel = codegenWrapper.getAllModels().get("House"); + + final CodegenProperty codegenProperty = codegenModel.vars.stream().filter(property -> property.baseName.equals("pets")).findFirst().get(); + Assert.assertEquals(codegenProperty.datatype, "List"); + + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegenTest.java new file mode 100644 index 0000000000..f0ac307148 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/dotnet/CSharpClientCodegenTest.java @@ -0,0 +1,61 @@ +package io.swagger.codegen.v3.generators.dotnet; + +import io.swagger.codegen.v3.CodegenConfig; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.ISchemaHandler; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import io.swagger.codegen.v3.generators.CodegenWrapper; +import io.swagger.v3.oas.models.OpenAPI; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class CSharpClientCodegenTest extends AbstractCodegenTest { + + @Test + public void checkOneOfModelCreation() { + final OpenAPI openAPI = getOpenAPI("3_0_0/composed_schemas.yaml"); + final CodegenConfig config = new CSharpClientCodegen(); + final CodegenWrapper codegenWrapper = processSchemas(config, openAPI); + + CodegenModel codegenModel = codegenWrapper.getAllModels().get("PartMaster"); + + boolean hasOneOfProperty = codegenModel.getVars() + .stream() + .anyMatch(codegenProperty -> codegenProperty.datatype.equals("OneOfPartMasterDestination")); + + Assert.assertTrue(hasOneOfProperty); + + hasOneOfProperty = codegenModel.getVars() + .stream() + .anyMatch(codegenProperty -> codegenProperty.datatype.equals("OneOfPartMasterOrigin")); + + Assert.assertTrue(hasOneOfProperty); + + final ISchemaHandler schemaHandler = codegenWrapper.getSchemaHandler(); + + boolean hasComposedModel = schemaHandler.getModels() + .stream() + .anyMatch(model -> model.name.equals("OneOfPartMasterDestination")); + + Assert.assertTrue(hasComposedModel); + + hasComposedModel = schemaHandler.getModels() + .stream() + .anyMatch(model -> model.name.equals("OneOfPartMasterOrigin")); + + Assert.assertTrue(hasComposedModel); + } + + @Test + public void renameReservedWordModel() { + final OpenAPI openAPI = getOpenAPI("3_0_0/composed_schemas.yaml"); + final CodegenConfig config = new CSharpClientCodegen(); + final CodegenWrapper codegenWrapper = processSchemas(config, openAPI); + + CodegenModel codegenModel = codegenWrapper.getAllModels().get("ModelClient"); + Assert.assertNotNull(codegenModel); + + codegenModel = codegenWrapper.getAllModels().get("ModelList"); + Assert.assertNotNull(codegenModel); + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/examples/ExampleGeneratorTest.java b/src/test/java/io/swagger/codegen/v3/generators/examples/ExampleGeneratorTest.java index d50f4fada3..52a8093ae7 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/examples/ExampleGeneratorTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/examples/ExampleGeneratorTest.java @@ -40,4 +40,16 @@ public void testExampleFromSchema() throws Exception { Assert.assertNotNull(example); Assert.assertTrue(example.contains("\"name\" : \"doggie\"")); } + + @Test + public void testExampleWithRecursiveNodes() throws Exception { + final Schema categorySchema = openAPI.getComponents().getSchemas().get("Category"); + final ExampleGenerator exampleGenerator = new ExampleGenerator(openAPI); + + final List> exampleList = exampleGenerator.generate(null, null, categorySchema); + Assert.assertEquals(exampleList.size(), 1); + final Map example = exampleList.get(0); + Assert.assertEquals(example.get("contentType"), "application/json"); + Assert.assertTrue(example.get("example").contains("\"name\" : \"Yinotheria\"")); + } } diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegenTest.java index d459d1e9ad..4adb76c9d0 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegenTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/AbstractJavaCodegenTest.java @@ -2,6 +2,8 @@ import io.swagger.codegen.v3.CodegenArgument; import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenProperty; import io.swagger.codegen.v3.CodegenType; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -10,7 +12,11 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class AbstractJavaCodegenTest { @@ -23,6 +29,11 @@ public void toEnumVarNameShouldNotShortenUnderScore() throws Exception { Assert.assertEquals("__", fakeJavaCodegen.toEnumVarName("_,.", "String")); } + @Test + public void toEnumVarNameShouldNotCreateSingleUnderscore() throws Exception { + Assert.assertEquals("_U", fakeJavaCodegen.toEnumVarName(",.", "String")); + } + @Test public void toVarNameShouldAvoidOverloadingGetClassMethod() throws Exception { Assert.assertEquals("propertyClass", fakeJavaCodegen.toVarName("class")); @@ -95,6 +106,8 @@ public void convertVarName() throws Exception { Assert.assertEquals(fakeJavaCodegen.toVarName("user-name"), "userName"); Assert.assertEquals(fakeJavaCodegen.toVarName("user_name"), "userName"); Assert.assertEquals(fakeJavaCodegen.toVarName("_user_name"), "_userName"); + Assert.assertEquals(fakeJavaCodegen.toVarName(":user_name"), "userName"); + Assert.assertEquals(fakeJavaCodegen.toVarName("_"), "u"); } @Test @@ -156,6 +169,194 @@ public void testPackageNamesSetWithAdditionalProperties() throws Exception { Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG), Boolean.TRUE); } + @Test + public void testFixUpParentAndInterfaces_propertyNameDifferent_getterSetterSame_typeDifferent() { + AbstractJavaCodegen codegen = new P_AbstractJavaCodegen(); + + CodegenModel parentModel = new CodegenModel(); + parentModel.name = "parent_type"; + CodegenModel childModel = new CodegenModel(); + childModel.name = "child_type"; + childModel.parentModel = parentModel; + parentModel.children = new ArrayList<>(); + + CodegenProperty parentValueProperty1 = new CodegenProperty(); + parentValueProperty1.name = "value"; + parentValueProperty1.baseName = "value"; + parentValueProperty1.getter = "getValue"; + parentValueProperty1.setter = "setValue"; + parentValueProperty1.datatype = "value_type"; + CodegenProperty parentValueProperty2 = new CodegenProperty(); + parentValueProperty2.name = "other_value"; + parentValueProperty2.baseName = "other_value"; + parentValueProperty2.getter = "getOtherValue"; + parentValueProperty2.setter = "setOtherValue"; + parentValueProperty2.datatype = "other_type"; + parentModel.vars = new ArrayList<>(); + parentModel.vars.add(parentValueProperty1); + parentModel.vars.add(parentValueProperty2); + + CodegenProperty childValueProperty1 = new CodegenProperty(); + childValueProperty1.name = "_value"; // different to parent "value" + childValueProperty1.baseName = "_value"; + childValueProperty1.getter = "getValue"; // same as parent "getValue" + childValueProperty1.setter = "setValue"; // same as parent "setValue" + childValueProperty1.datatype = "different_type"; // different to parent "value_type" + CodegenProperty childValueProperty2 = new CodegenProperty(); + childValueProperty2.name = "third_value"; + childValueProperty2.baseName = "third_value"; + childValueProperty2.getter = "getThirdValue"; + childValueProperty2.setter = "setThirdValue"; + childValueProperty2.datatype = "other_type"; + childModel.vars = new ArrayList<>(); + childModel.vars.add(childValueProperty1); + childModel.vars.add(childValueProperty2); + + Map allModels = new HashMap<>(); + allModels.put(parentModel.name, parentModel); + allModels.put(childModel.name, childModel); + + codegen.fixUpParentAndInterfaces(childModel, Collections.EMPTY_MAP); + Assert.assertEquals(childModel.vars.get(0).baseName, "_value"); + Assert.assertEquals(childModel.vars.get(0).name, "childTypeValue"); + Assert.assertEquals(childModel.vars.get(0).getter, "getChildTypeValue"); + Assert.assertEquals(childModel.vars.get(0).setter, "setChildTypeValue"); + + // unchanged + Assert.assertEquals(childModel.vars.get(1).baseName, childValueProperty2.baseName); + Assert.assertEquals(childModel.vars.get(1).name, childValueProperty2.name); + Assert.assertEquals(childModel.vars.get(1).getter, childValueProperty2.getter); + Assert.assertEquals(childModel.vars.get(1).setter, childValueProperty2.setter); + } + + @Test + public void testFixUpParentAndInterfaces_propertyNameSame_getterSetterSame_typeDifferent() { + AbstractJavaCodegen codegen = new P_AbstractJavaCodegen(); + + CodegenModel parentModel = new CodegenModel(); + parentModel.name = "parent_type"; + CodegenModel childModel = new CodegenModel(); + childModel.name = "child_type"; + childModel.parentModel = parentModel; + parentModel.children = new ArrayList<>(); + + CodegenProperty parentValueProperty1 = new CodegenProperty(); + parentValueProperty1.name = "value"; + parentValueProperty1.baseName = "value"; + parentValueProperty1.getter = "getValue"; + parentValueProperty1.setter = "setValue"; + parentValueProperty1.datatype = "value_type"; + CodegenProperty parentValueProperty2 = new CodegenProperty(); + parentValueProperty2.name = "other_value"; + parentValueProperty2.baseName = "other_value"; + parentValueProperty2.getter = "getOtherValue"; + parentValueProperty2.setter = "setOtherValue"; + parentValueProperty2.datatype = "other_type"; + parentModel.vars = new ArrayList<>(); + parentModel.vars.add(parentValueProperty1); + parentModel.vars.add(parentValueProperty2); + + CodegenProperty childValueProperty1 = new CodegenProperty(); + childValueProperty1.name = "value"; // same as parent "value" + childValueProperty1.baseName = "value"; + childValueProperty1.getter = "getValue"; // same as parent "getValue" + childValueProperty1.setter = "setValue"; // same as parent "setValue" + childValueProperty1.datatype = "different_type"; // different to parent "value_type" + CodegenProperty childValueProperty2 = new CodegenProperty(); + childValueProperty2.name = "third_value"; + childValueProperty2.baseName = "third_value"; + childValueProperty2.getter = "getThirdValue"; + childValueProperty2.setter = "setThirdValue"; + childValueProperty2.datatype = "other_type"; + childModel.vars = new ArrayList<>(); + childModel.vars.add(childValueProperty1); + childModel.vars.add(childValueProperty2); + + Map allModels = new HashMap<>(); + allModels.put(parentModel.name, parentModel); + allModels.put(childModel.name, childModel); + + codegen.fixUpParentAndInterfaces(childModel, Collections.EMPTY_MAP); + Assert.assertEquals(childModel.vars.get(0).baseName, "value"); + Assert.assertEquals(childModel.vars.get(0).name, "childTypeValue"); + Assert.assertEquals(childModel.vars.get(0).getter, "getChildTypeValue"); + Assert.assertEquals(childModel.vars.get(0).setter, "setChildTypeValue"); + + // unchanged + Assert.assertEquals(childModel.vars.get(1).baseName, childValueProperty2.baseName); + Assert.assertEquals(childModel.vars.get(1).name, childValueProperty2.name); + Assert.assertEquals(childModel.vars.get(1).getter, childValueProperty2.getter); + Assert.assertEquals(childModel.vars.get(1).setter, childValueProperty2.setter); + } + + /** + * Issue #1066 - testing case when the conflicting property is actually not the first one but the + * second + */ + @Test + public void testFixUpParentAndInterfaces_2ndproperty_propertyNameSame_getterSetterSame_typeDifferent() { + AbstractJavaCodegen codegen = new P_AbstractJavaCodegen(); + + CodegenModel parentModel = new CodegenModel(); + parentModel.name = "parent_type"; + CodegenModel childModel = new CodegenModel(); + childModel.name = "child_type"; + childModel.parentModel = parentModel; + parentModel.children = new ArrayList<>(); + + CodegenProperty parentValueProperty1 = new CodegenProperty(); + parentValueProperty1.name = "value"; + parentValueProperty1.baseName = "value"; + parentValueProperty1.getter = "getValue"; + parentValueProperty1.setter = "setValue"; + parentValueProperty1.datatype = "value_type"; + CodegenProperty parentValueProperty2 = new CodegenProperty(); + parentValueProperty2.name = "other_value"; + parentValueProperty2.baseName = "other_value"; + parentValueProperty2.getter = "getOtherValue"; + parentValueProperty2.setter = "setOtherValue"; + parentValueProperty2.datatype = "other_type"; + parentModel.vars = new ArrayList<>(); + parentModel.vars.add(parentValueProperty1); + parentModel.vars.add(parentValueProperty2); + + CodegenProperty childValueProperty1 = new CodegenProperty(); + childValueProperty1.name = "third_value"; + childValueProperty1.baseName = "third_value"; + childValueProperty1.nameInCamelCase = "ThirdValue"; + childValueProperty1.getter = "getThirdValue"; + childValueProperty1.setter = "setThirdValue"; + childValueProperty1.datatype = "other_type"; + CodegenProperty childValueProperty2 = new CodegenProperty(); + childValueProperty2.name = "value"; // same as parent "value" + childValueProperty2.baseName = "value"; + childValueProperty2.getter = "getValue"; // same as parent "getValue" + childValueProperty2.setter = "setValue"; // same as parent "setValue" + childValueProperty2.datatype = "different_type"; // different to parent "value_type" + + childModel.vars = new ArrayList<>(); + childModel.vars.add(childValueProperty1); + childModel.vars.add(childValueProperty2); + + Map allModels = new HashMap<>(); + allModels.put(parentModel.name, parentModel); + allModels.put(childModel.name, childModel); + + codegen.fixUpParentAndInterfaces(childModel, Collections.EMPTY_MAP); + Assert.assertEquals(childModel.vars.get(1).baseName, "value"); + Assert.assertEquals(childModel.vars.get(1).name, "childTypeValue"); + Assert.assertEquals(childModel.vars.get(1).nameInCamelCase, "ChildTypeValue"); + Assert.assertEquals(childModel.vars.get(1).getter, "getChildTypeValue"); + Assert.assertEquals(childModel.vars.get(1).setter, "setChildTypeValue"); + + // unchanged + Assert.assertEquals(childModel.vars.get(0).baseName, childValueProperty1.baseName); + Assert.assertEquals(childModel.vars.get(0).name, childValueProperty1.name); + Assert.assertEquals(childModel.vars.get(0).nameInCamelCase, childValueProperty1.nameInCamelCase); + Assert.assertEquals(childModel.vars.get(0).getter, childValueProperty1.getter); + Assert.assertEquals(childModel.vars.get(0).setter, childValueProperty1.setter); + } + public static class P_AbstractJavaCodegen extends AbstractJavaCodegen { @Override public String getArgumentsLocation() { diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java new file mode 100644 index 0000000000..58509df237 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java @@ -0,0 +1,39 @@ +package io.swagger.codegen.v3.generators.java; + +import io.swagger.codegen.v3.generators.GeneratorRunner; +import io.swagger.codegen.v3.service.GenerationRequest; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.List; + +public class GeneratorResultTestJava { + + + @Test + public void testJavaGenerator_OneOf() throws Exception { + + String name = "java"; + String specPath = "3_0_0/composedFlatten/allof_inline_ref.yaml"; + GenerationRequest.CodegenVersion codegenVersion = GenerationRequest.CodegenVersion.V3; + boolean v2Spec = false; // 3.0 spec + boolean yaml = true; + boolean flattenInlineComposedSchema = true; + String outFolder = null; // temporary folder + + List files = GeneratorRunner.runGenerator( + name, + specPath, + codegenVersion, + v2Spec, + yaml, + flattenInlineComposedSchema, + outFolder); + + Assert.assertFalse(files.isEmpty()); + for (File f: files) { + // TODO test stuff + } + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegenTest.java index 4779aca84e..31b9f8f61c 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegenTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaCXFClientCodegenTest.java @@ -2,14 +2,9 @@ import io.swagger.codegen.v3.CodegenOperation; import io.swagger.codegen.v3.CodegenResponse; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.media.ArraySchema; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.ObjectSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.oas.models.responses.ApiResponses; import org.testng.Assert; import org.testng.annotations.Test; @@ -17,23 +12,16 @@ import java.util.HashMap; import java.util.Map; -public class JavaCXFClientCodegenTest { +public class JavaCXFClientCodegenTest extends AbstractCodegenTest { @Test public void responseWithoutContent() throws Exception { - final Schema listOfPets = new ArraySchema() - .items(new Schema<>().$ref("#/components/schemas/Pet")); - Operation operation = new Operation().responses(new ApiResponses() - .addApiResponse("200", new ApiResponse() - .description("Return a list of pets") - .content(new Content().addMediaType("application/json", - new MediaType().schema(listOfPets)))) - .addApiResponse("400", new ApiResponse() - .description("Error"))); - final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); + final OpenAPI openAPI = getOpenAPI("3_0_0/response_without_content.yaml"); + final Operation operation = openAPI.getPaths().get("/pets").getGet(); final JavaCXFClientCodegen codegen = new JavaCXFClientCodegen(); - final CodegenOperation co = codegen.fromOperation("getAllPets", "GET", operation, allDefinitions); + codegen.preprocessOpenAPI(openAPI); + final CodegenOperation co = codegen.fromOperation("getAllPets", "GET", operation, openAPI.getComponents().getSchemas(), openAPI); Map objs = new HashMap<>(); objs.put("operations", Collections.singletonMap("operation", Collections.singletonList(co))); diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaClientCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaClientCodegenTest.java index ef89567049..d49b739dea 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/JavaClientCodegenTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaClientCodegenTest.java @@ -1,10 +1,21 @@ package io.swagger.codegen.v3.generators.java; +import io.swagger.codegen.v3.CodegenConfig; import io.swagger.codegen.v3.CodegenConstants; import io.swagger.codegen.v3.CodegenModel; import io.swagger.codegen.v3.CodegenModelFactory; import io.swagger.codegen.v3.CodegenModelType; import io.swagger.codegen.v3.CodegenParameter; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.CodegenSchema; +import io.swagger.codegen.v3.ISchemaHandler; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import io.swagger.codegen.v3.generators.CodegenWrapper; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.SchemaHandler; +import io.swagger.util.Json; +import io.swagger.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.ComposedSchema; import io.swagger.v3.oas.models.media.Content; @@ -14,6 +25,9 @@ import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.parser.OpenAPIV3Parser; +import io.swagger.v3.parser.core.models.ParseOptions; +import io.swagger.v3.parser.core.models.SwaggerParseResult; import io.swagger.v3.parser.util.SchemaTypeUtil; import org.testng.Assert; import org.testng.annotations.Test; @@ -26,7 +40,7 @@ import java.util.List; import java.util.Map; -public class JavaClientCodegenTest { +public class JavaClientCodegenTest extends AbstractCodegenTest { @Test public void modelInheritanceSupportInGson() throws Exception { @@ -142,7 +156,7 @@ public void arraysInRequestBody() throws Exception { RequestBody body1 = new RequestBody(); body1.setDescription("A list of ids"); body1.setContent(new Content().addMediaType("application/json", new MediaType().schema(new ArraySchema().items(new StringSchema())))); - CodegenParameter codegenParameter1 = codegen.fromRequestBody(body1 , null, null, new HashMap(), new HashSet()); + CodegenParameter codegenParameter1 = codegen.fromRequestBody(body1, null, null, new HashMap(), new HashSet()); Assert.assertEquals(codegenParameter1.description, "A list of ids"); Assert.assertEquals(codegenParameter1.dataType, "List"); Assert.assertEquals(codegenParameter1.baseType, "String"); @@ -150,11 +164,10 @@ public void arraysInRequestBody() throws Exception { RequestBody body2 = new RequestBody(); body2.setDescription("A list of list of values"); body2.setContent(new Content().addMediaType("application/json", new MediaType().schema(new ArraySchema().items(new ArraySchema().items(new IntegerSchema()))))); - CodegenParameter codegenParameter2 = codegen.fromRequestBody(body2 , null, null, new HashMap(), new HashSet()); + CodegenParameter codegenParameter2 = codegen.fromRequestBody(body2, null, null, new HashMap(), new HashSet()); Assert.assertEquals(codegenParameter2.description, "A list of list of values"); Assert.assertEquals(codegenParameter2.dataType, "List>"); Assert.assertEquals(codegenParameter2.baseType, "List"); - RequestBody body3 = new RequestBody(); body3.setDescription("A list of points"); body3.setContent(new Content().addMediaType("application/json", new MediaType().schema(new ArraySchema().items(new ObjectSchema().$ref("#/components/schemas/Point"))))); @@ -162,7 +175,7 @@ public void arraysInRequestBody() throws Exception { point.addProperties("message", new StringSchema()); point.addProperties("x", new IntegerSchema().format(SchemaTypeUtil.INTEGER32_FORMAT)); point.addProperties("y", new IntegerSchema().format(SchemaTypeUtil.INTEGER32_FORMAT)); - CodegenParameter codegenParameter3 = codegen.fromRequestBody(body3 , null, null, Collections.singletonMap("Point", point), new HashSet()); + CodegenParameter codegenParameter3 = codegen.fromRequestBody(body3, null, null, Collections.singletonMap("Point", point), new HashSet()); Assert.assertEquals(codegenParameter3.description, "A list of points"); Assert.assertEquals(codegenParameter3.dataType, "List"); Assert.assertEquals(codegenParameter3.baseType, "Point"); @@ -172,7 +185,7 @@ public void arraysInRequestBody() throws Exception { public void nullValuesInComposedSchema() throws Exception { final JavaClientCodegen codegen = new JavaClientCodegen(); CodegenModel result = codegen.fromModel("CompSche", - new ComposedSchema()); + new ComposedSchema()); Assert.assertEquals(result.name, "CompSche"); } @@ -210,7 +223,7 @@ public void testPackageNamesSetWithAdditionalProperties() throws Exception { final JavaClientCodegen codegen = new JavaClientCodegen(); codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "xxx.yyyyy.zzzzzzz.mmmmm.model"); codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "xxx.yyyyy.zzzzzzz.aaaaa.api"); - codegen.additionalProperties().put(CodegenConstants.INVOKER_PACKAGE,"xxx.yyyyy.zzzzzzz.iiii.invoker"); + codegen.additionalProperties().put(CodegenConstants.INVOKER_PACKAGE, "xxx.yyyyy.zzzzzzz.iiii.invoker"); codegen.processOpts(); Assert.assertEquals(codegen.modelPackage(), "xxx.yyyyy.zzzzzzz.mmmmm.model"); @@ -254,10 +267,80 @@ public void testPackageNamesSetInvokerDerivedFromModel() throws Exception { public void customTemplates() throws Exception { final JavaClientCodegen codegen = new JavaClientCodegen(); codegen.processOpts(); - Assert.assertEquals(codegen.templateDir(), "handlebars" + File.separator + "Java"); + Assert.assertEquals(codegen.templateDir(), "handlebars" + File.separator + "Java"); - codegen.additionalProperties().put(CodegenConstants.TEMPLATE_DIR, String.join(File.separator,"user", "custom", "location")); + codegen.additionalProperties().put(CodegenConstants.TEMPLATE_DIR, String.join(File.separator, "user", "custom", "location")); codegen.processOpts(); - Assert.assertEquals(codegen.templateDir(), String.join(File.separator,"user", "custom", "location")); + Assert.assertEquals(codegen.customTemplateDir(), String.join(File.separator, "user", "custom", "location")); + } + + @Test + public void testModelNamedFile() { + final OpenAPI openAPI = getOpenAPI("3_0_0/model_named_file.yaml"); + final DefaultCodegenConfig config = new JavaClientCodegen(); + config.setIgnoreImportMapping(true); + config.preprocessOpenAPI(openAPI); + + final Schema modelFile = openAPI.getComponents().getSchemas().get("File"); + final Schema modelSetting = openAPI.getComponents().getSchemas().get("Setting"); + + final CodegenModel codegenModelFile = config.fromModel("File", modelFile, openAPI.getComponents().getSchemas()); + final CodegenModel codegenModelSetting = config.fromModel("Setting", modelSetting, openAPI.getComponents().getSchemas()); + + Assert.assertEquals(codegenModelFile.name, "File"); + Assert.assertEquals(codegenModelSetting.name, "Setting"); + + final List codegenProperties = codegenModelSetting.getVars(); + + Assert.assertEquals(codegenProperties.size(), 4); + + CodegenProperty fileProperty = codegenProperties.stream().filter(property -> property.name.equals("file")).findAny().get(); + + Assert.assertEquals(fileProperty.name, "file"); + Assert.assertEquals(fileProperty.baseType, "File"); + Assert.assertEquals(fileProperty.datatype, "File"); + + CodegenProperty documentProperty = codegenProperties.stream().filter(property -> property.name.equals("document")).findAny().get(); + + Assert.assertEquals(documentProperty.name, "document"); + Assert.assertEquals(documentProperty.baseType, "File"); + Assert.assertEquals(documentProperty.datatype, "java.io.File"); + + Assert.assertFalse(codegenModelSetting.imports.stream().anyMatch(_import -> _import.equals("java.io.File"))); + } + + @Test + public void checkOneOfModelCreation() { + final OpenAPI openAPI = getOpenAPI("3_0_0/composed_schemas.yaml"); + final CodegenConfig config = new JavaClientCodegen(); + final CodegenWrapper codegenWrapper = processSchemas(config, openAPI); + + CodegenModel codegenModel = codegenWrapper.getAllModels().get("PartMaster"); + + boolean hasOneOfProperty = codegenModel.getVars() + .stream() + .anyMatch(codegenProperty -> codegenProperty.datatype.equals("OneOfPartMasterDestination")); + + Assert.assertTrue(hasOneOfProperty); + + hasOneOfProperty = codegenModel.getVars() + .stream() + .anyMatch(codegenProperty -> codegenProperty.datatype.equals("OneOfPartMasterOrigin")); + + Assert.assertTrue(hasOneOfProperty); + + final ISchemaHandler schemaHandler = codegenWrapper.getSchemaHandler(); + + boolean hasComposedModel = schemaHandler.getModels() + .stream() + .anyMatch(model -> model.name.equals("OneOfPartMasterDestination")); + + Assert.assertTrue(hasComposedModel); + + hasComposedModel = schemaHandler.getModels() + .stream() + .anyMatch(model -> model.name.equals("OneOfPartMasterOrigin")); + + Assert.assertTrue(hasComposedModel); } } diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelEnumTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelEnumTest.java index ca8c724cc2..1ebc9cfcac 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelEnumTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelEnumTest.java @@ -119,7 +119,7 @@ public void overrideEnumTest() { parentModel.setProperties(parentProperties); parentModel.name("parentModel"); - final ComposedSchema composedSchema = new ComposedSchema() + final ComposedSchema composedSchema = (ComposedSchema)new ComposedSchema() .addAllOfItem(new Schema().$ref(parentModel.getName())); final DefaultCodegenConfig codegen = new JavaClientCodegen(); diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelTest.java index 6e02a8a06e..e7041f4527 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaModelTest.java @@ -10,7 +10,10 @@ import io.swagger.codegen.v3.CodegenResponse; import io.swagger.codegen.v3.DefaultGenerator; import io.swagger.codegen.v3.config.CodegenConfigurator; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.BooleanSchema; @@ -43,7 +46,7 @@ import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; -public class JavaModelTest { +public class JavaModelTest extends AbstractCodegenTest { private TemporaryFolder folder = new TemporaryFolder(); @Test(description = "convert a simple java model") @@ -57,6 +60,7 @@ public void simpleModelTest() { .addRequiredItem("id") .addRequiredItem("name"); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", model); Assert.assertEquals(cm.name, "sample"); @@ -169,6 +173,7 @@ public void mapWithListPropertyTest() { .additionalProperties(new ArraySchema().items(new Schema().$ref("Pet")))) .addRequiredItem("id"); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -196,6 +201,7 @@ public void list2DPropertyTest() { .addProperties("list2D", new ArraySchema().items( new ArraySchema().items(new Schema().$ref("Pet")))); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", model); Assert.assertEquals(cm.vars.size(), 1); @@ -219,6 +225,7 @@ public void complexPropertiesTest() { .description("a sample model") .addProperties("children", new Schema().$ref("#/components/schemas/Children")); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -245,6 +252,7 @@ public void complexListPropertyTest() { .addProperties("children", new ArraySchema() .items(new Schema().$ref("#/components/schemas/Children"))); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -273,6 +281,7 @@ public void complexMapPropertyTest() { .addProperties("children", new MapSchema() .additionalProperties(new Schema().$ref("#/components/schemas/Children"))); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -310,6 +319,7 @@ public void arrayModelWithItemNameTest() { final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -344,6 +354,7 @@ public void arrayModelTest() { .name("arraySchema") .description("an array model"); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -354,7 +365,7 @@ public void arrayModelTest() { Assert.assertEquals(cm.imports.size(), 4); Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Schema", "List", "ArrayList", "Children")).size(), 4); } - + @Test(description = "convert an array model") public void arrayModelTestUsingOas2() { final Schema schema = new ArraySchema() @@ -362,6 +373,7 @@ public void arrayModelTestUsingOas2() { .name("arraySchema") .description("an array model"); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); codegen.setUseOas2(true); final CodegenModel cm = codegen.fromModel("sample", schema); @@ -380,6 +392,7 @@ public void mapModelTest() { .description("an map model") .additionalProperties(new Schema().$ref("#/components/schemas/Children")); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -390,13 +403,14 @@ public void mapModelTest() { Assert.assertEquals(cm.imports.size(), 4); Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Schema", "Map", "HashMap", "Children")).size(), 4); } - + @Test(description = "convert an map model") public void mapModelTestUsingOas2() { final Schema schema = new MapSchema() .description("an map model") .additionalProperties(new Schema().$ref("#/components/schemas/Children")); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); codegen.setUseOas2(true); final CodegenModel cm = codegen.fromModel("sample", schema); @@ -408,7 +422,7 @@ public void mapModelTestUsingOas2() { Assert.assertEquals(cm.imports.size(), 4); Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("ApiModel", "Map", "HashMap", "Children")).size(), 4); } - + @Test(description = "convert a model with upper-case property names") public void upperCaseNamesTest() { final Schema schema = new Schema() @@ -823,6 +837,7 @@ public void longPropertyInReferencedSchemaTest() { .addProperties("Long1", new Schema<>().$ref("#/components/schemas/LongProperty")) .addProperties("Long2", new IntegerSchema().format("int64")); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final Map allDefinitions = Collections.singletonMap("LongProperty", longProperty); final CodegenModel cm = codegen.fromModel("test", TestSchema, allDefinitions); @@ -851,6 +866,7 @@ public void integerPropertyInReferencedSchemaTest() { .addProperties("Integer2", new IntegerSchema().format("int32")); final Map allDefinitions = Collections.singletonMap("IntegerProperty", longProperty); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("test", testSchema, allDefinitions); Assert.assertEquals(cm.vars.size(), 2); @@ -877,6 +893,7 @@ public void arraySchemaTest() { .items(new Schema<>().$ref("#/components/schemas/Pet"))); final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("test", testSchema, allDefinitions); Assert.assertEquals(cm.vars.size(), 1); @@ -897,13 +914,14 @@ public void arraySchemaTestInRequestBody() { .items(new Schema<>().$ref("#/components/schemas/Pet")); Operation operation = new Operation() .requestBody(new RequestBody() - .content(new Content().addMediaType("application/json", + .content(new Content().addMediaType("application/json", new MediaType().schema(testSchema)))) .responses( new ApiResponses().addApiResponse("204", new ApiResponse() .description("Ok response"))); final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenOperation co = codegen.fromOperation("testSchema", "GET", operation, allDefinitions); Assert.assertEquals(co.bodyParams.size(), 1); @@ -926,10 +944,11 @@ public void arraySchemaTestInOperationResponse() { Operation operation = new Operation().responses( new ApiResponses().addApiResponse("200", new ApiResponse() .description("Ok response") - .content(new Content().addMediaType("application/json", + .content(new Content().addMediaType("application/json", new MediaType().schema(testSchema))))); final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenOperation co = codegen.fromOperation("testSchema", "GET", operation, allDefinitions); Assert.assertEquals(co.responses.size(), 1); @@ -949,6 +968,7 @@ public void arrayOfArraySchemaTest() { .items(new Schema<>().$ref("#/components/schemas/Pet")))); final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("test", testSchema, allDefinitions); Assert.assertEquals(cm.vars.size(), 1); @@ -970,13 +990,14 @@ public void arrayOfArraySchemaTestInRequestBody() { .items(new Schema<>().$ref("#/components/schemas/Pet"))); Operation operation = new Operation() .requestBody(new RequestBody() - .content(new Content().addMediaType("application/json", + .content(new Content().addMediaType("application/json", new MediaType().schema(testSchema)))) .responses( new ApiResponses().addApiResponse("204", new ApiResponse() .description("Ok response"))); final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenOperation co = codegen.fromOperation("testSchema", "GET", operation, allDefinitions); Assert.assertEquals(co.bodyParams.size(), 1); @@ -1000,10 +1021,11 @@ public void arrayOfArraySchemaTestInOperationResponse() { Operation operation = new Operation().responses( new ApiResponses().addApiResponse("200", new ApiResponse() .description("Ok response") - .content(new Content().addMediaType("application/json", + .content(new Content().addMediaType("application/json", new MediaType().schema(testSchema))))); final Map allDefinitions = Collections.singletonMap("Pet", new ObjectSchema()); final DefaultCodegenConfig codegen = new JavaClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenOperation co = codegen.fromOperation("testSchema", "GET", operation, allDefinitions); Assert.assertEquals(co.responses.size(), 1); @@ -1015,14 +1037,14 @@ public void arrayOfArraySchemaTestInOperationResponse() { Assert.assertTrue(co.imports.contains("Pet")); } - @Test(enabled = false, description = "disabled since templates have been moved.") + @Test public void generateModel() throws Exception { folder.create(); final File output = folder.getRoot(); final CodegenConfigurator configurator = new CodegenConfigurator() .setLang("java") - .setInputSpec("src/test/resources/3_0_0/petstore.json") + .setInputSpecURL("src/test/resources/3_0_0/petstore.yaml") .setOutputDir(output.getAbsolutePath()); final ClientOptInput clientOptInput = configurator.toClientOptInput(); @@ -1032,4 +1054,25 @@ public void generateModel() throws Exception { Assert.assertTrue(orderFile.exists()); folder.delete(); } + + @Test + public void generateModelDiscriminatorOrderSchemas() throws Exception { + TemporaryFolder temporaryFolder = new TemporaryFolder(); + + temporaryFolder.create(); + final File output = temporaryFolder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java") + .setInputSpecURL("src/test/resources/3_0_0/discriminator_order_schemas.yaml") + .setOutputDir(output.getAbsolutePath()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + File child = new File(output, "src/main/java/io/swagger/client/model/DSubSubSubBase.java"); + Assert.assertTrue(child.exists()); + temporaryFolder.delete(); + } + } diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java new file mode 100644 index 0000000000..d3ad04763c --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java @@ -0,0 +1,42 @@ +package io.swagger.codegen.v3.generators.java; + +import io.swagger.codegen.v3.ClientOptInput; +import io.swagger.codegen.v3.DefaultGenerator; +import io.swagger.codegen.v3.config.CodegenConfigurator; +import org.apache.commons.io.FileUtils; +import org.junit.rules.TemporaryFolder; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.File; + +public class JavaPolymorphicAnnotationCodegenTest { + + private TemporaryFolder folder = new TemporaryFolder(); + + @Test(description = "verify that jackson-polymorphism annotations are generated") + public void testParameterOrders() throws Exception { + this.folder.create(); + final File output = this.folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/polymorphicSchema.yaml") + .setOutputDir(output.getAbsolutePath()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, "/src/main/java/io/swagger/model/PolymorphicResponse.java"); + final String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = \"type\", visible = true )\n" + + "@JsonSubTypes({\n" + + " @JsonSubTypes.Type(value = Error.class, name = \"Error\"),\n" + + " @JsonSubTypes.Type(value = Success.class, name = \"Success\"),\n" + + "})")); + + this.folder.delete(); + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaVertxServerGeneratorCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaVertxServerGeneratorCodegenTest.java new file mode 100644 index 0000000000..0236082c7f --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaVertxServerGeneratorCodegenTest.java @@ -0,0 +1,706 @@ +package io.swagger.codegen.v3.generators.java; + +import static io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen.MOUNT_OPERATION_FROM_EXTENSIONS; +import static io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen.MOUNT_OPERATION_FROM_INTERFACE; +import static io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen.MOUNT_OPERATION_FROM_OPTION; +import static io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen.RX_INTERFACE_OPTION; +import static io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen.USE_DATAOBJECT_OPTION; +import static io.swagger.codegen.v3.generators.java.JavaVertXServerCodegen.USE_FUTURE_OPTION; + +import io.swagger.codegen.v3.ClientOptInput; +import io.swagger.codegen.v3.CodegenArgument; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.DefaultGenerator; +import io.swagger.codegen.v3.config.CodegenConfigurator; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.io.FileUtils; +import org.junit.Assert; +import org.junit.rules.TemporaryFolder; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class JavaVertxServerGeneratorCodegenTest extends AbstractCodegenTest { + + static final String PACKAGE_INFO = "package-info.java"; + + static final List SERVICE_AS_EXTENSION_FILENAMES = Arrays.asList("GetOrderByIdAddressApi.java", + "MyFeedPetAddressApi.java", "MyUploadFileAddressApi.java", "DeleteOrderAddressApi.java", + "MyFindPetsByStatusAddressApi.java", "PlaceOrderAddressApi.java", + "MyPetAddressApi.java", "UserAddressApi.java", "MyPetIdAddressApi.java", + "GetInventoryAddressApi.java", "PetAddressApi.java", "MyFindByTagsAddressApi.java", + "TestAddressApi.java", "MyGetPetByIdAddressApi.java" + ); + + static final Map SERVICE_AS_INTERFACE = new HashMap() {{ + put("DefaultApi.java", "DefaultApi"); + put("PetApi.java", "PetApi"); + put("StoreApi.java", "StoreApi"); + put("UserApi.java", "UserApi"); + }}; + + private TemporaryFolder folder = null; + + @BeforeMethod + public void setUp() throws Exception { + folder = new TemporaryFolder(); + folder.create(); + } + + @AfterMethod + public void tearDown() { + folder.delete(); + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 2.x & web-api-service & Future)") + public void testUseOas2AndWebApiServiceAndFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS) + .addAdditionalProperty(USE_FUTURE_OPTION, true); + + configurator.setCodegenArguments(Collections.singletonList( + new CodegenArgument() + .option(CodegenConstants.USE_OAS2_OPTION) + .type("boolean") + .value(Boolean.TRUE.toString()))); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue(content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = true)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("Future")); + Assert.assertTrue(content.contains("ServiceRequest request);")); + Assert.assertFalse(content.contains("Handler>")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 2.x & web-api-service and not future)") + public void testUseOas2AndWebApiServiceAndNotFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS); + + configurator.setCodegenArguments(Collections.singletonList( + new CodegenArgument() + .option(CodegenConstants.USE_OAS2_OPTION) + .type("boolean") + .value(Boolean.TRUE.toString()))); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue(content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = false)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertFalse(content.contains("Future")); + Assert.assertTrue(content.contains("ServiceRequest request,")); + Assert.assertTrue(content.contains("Handler> resultHandler);")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & web-api-service & Future)") + public void testUseOas3AndWebApiServiceAndFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS) + .addAdditionalProperty(USE_FUTURE_OPTION, true); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue( + content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = true)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("Future")); + Assert.assertTrue(content.contains("ServiceRequest request);")); + Assert.assertFalse(content.contains("Handler>")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & web-api-service and not future)") + public void testUseOas3AndWebApiServiceAndNotFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue( + content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = false)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("ServiceRequest request,")); + Assert.assertFalse(content.contains("Future")); + Assert.assertTrue(content.contains("Handler> resultHandler);")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & web-api-service & Future)") + public void testRxUseOas3AndWebApiServiceAndFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS) + .addAdditionalProperty(RX_INTERFACE_OPTION, true) + .addAdditionalProperty(USE_FUTURE_OPTION, true); + + final List arguments = new ArrayList<>(); + arguments.add(new CodegenArgument() + .option(RX_INTERFACE_OPTION) + .type("boolean") + .value(Boolean.TRUE.toString())); + configurator.setCodegenArguments(arguments); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.rxDeployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertFalse(content.contains("startPromise.fail(error);")); + Assert.assertFalse(content.contains("startPromise.complete();")); + Assert.assertTrue(content.contains("ignoreElement();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue(content.contains("return RouterBuilder.rxCreate(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertFalse(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertFalse(content.contains("onFailure(startPromise::fail);")); + Assert.assertTrue(content.contains("rxStart()")); + Assert.assertTrue(content.contains("rxStop()")); + Assert.assertTrue(content.contains("rxListen()")); + Assert.assertTrue(content.contains("ignoreElement();")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = true)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("Future")); + Assert.assertTrue(content.contains("ServiceRequest request);")); + } + + } + + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & web-api-service & not Future)") + public void testRxUseOas3AndWebApiServiceAndNotFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS) + .addAdditionalProperty(RX_INTERFACE_OPTION, true); + + final List arguments = new ArrayList<>(); + arguments.add(new CodegenArgument() + .option(RX_INTERFACE_OPTION) + .type("boolean") + .value(Boolean.TRUE.toString())); + configurator.setCodegenArguments(arguments); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.rxDeployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertFalse(content.contains("startPromise.fail(error);")); + Assert.assertFalse(content.contains("startPromise.complete();")); + Assert.assertTrue(content.contains("ignoreElement();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue(content.contains("return RouterBuilder.rxCreate(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertFalse(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertFalse(content.contains("onFailure(startPromise::fail);")); + Assert.assertTrue(content.contains("rxStart()")); + Assert.assertTrue(content.contains("rxStop()")); + Assert.assertTrue(content.contains("rxListen()")); + Assert.assertTrue(content.contains("ignoreElement();")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = false)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("ServiceRequest request,")); + Assert.assertFalse(content.contains("Future")); + Assert.assertTrue(content.contains("Handler> resultHandler);")); + } + + } + + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & mount from interface & future)") + public void testUseOas3AndMountFromInterfaceAndFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_INTERFACE) + .addAdditionalProperty(USE_FUTURE_OPTION, true); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains("vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue(content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertFalse(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("routerBuilder.mountServiceInterface")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_INTERFACE.containsKey(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = true)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + String api = SERVICE_AS_INTERFACE.getOrDefault(file.getName(), PACKAGE_INFO); + Assert.assertFalse(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_" + api.toUpperCase())); + Assert.assertTrue(content.contains("Future")); + Assert.assertTrue(content.contains("ServiceRequest request);")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & mount from interface & not future)") + public void testUseOas3AndMountFromInterfaceAndNotFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, true) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_INTERFACE); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains("vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue(content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertFalse(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("routerBuilder.mountServiceInterface")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + content = FileUtils.readFileToString(packageInfoModelFile); + Assert.assertTrue(content.contains("@ModuleGen(name = \"model\", groupPackage = \"io.swagger.server.api.model\")")); + Assert.assertTrue(content.contains("package io.swagger.server.api.model;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_INTERFACE.containsKey(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = false)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + String api = SERVICE_AS_INTERFACE.getOrDefault(file.getName(), PACKAGE_INFO); + Assert.assertFalse(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_" + api.toUpperCase())); + Assert.assertTrue(content.contains("ServiceRequest request,")); + Assert.assertFalse(content.contains("Future")); + Assert.assertTrue(content.contains("Handler> resultHandler);")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & web-api-service & not dataobject & Future)") + public void testUseOas3AndWebApiServiceAndNoDataobjectAndFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, false) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS) + .addAdditionalProperty(USE_FUTURE_OPTION, true); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue( + content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + Assert.assertFalse(packageInfoModelFile.exists()); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = true)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("Future")); + Assert.assertTrue(content.contains("RequestParameter body, ServiceRequest request);")); + } + } + } + + @Test(description = "verify that main verticle, openapi verticle and service are written as expected (OAS 3.x & web-api-service & not dataobject & not Future)") + public void testUseOas3AndWebApiServiceAndNoDataobjectAndNotFuture() throws Exception { + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("java-vertx") + .setInputSpecURL("src/test/resources/3_0_0/petstore-vertx.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(USE_DATAOBJECT_OPTION, false) + .addAdditionalProperty(MOUNT_OPERATION_FROM_OPTION, MOUNT_OPERATION_FROM_EXTENSIONS); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, + "/src/main/java/io/swagger/server/api/MainApiVerticle.java"); + String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains( + "vertx.deployVerticle(\"io.swagger.server.api.verticle.SwaggerPetstoreVerticle\")")); + Assert.assertTrue(content.contains("startPromise.fail(error);")); + Assert.assertTrue(content.contains("startPromise.complete();")); + + final File petVerticleFile = new File(output, + "/src/main/java/io/swagger/server/api/verticle/SwaggerPetstoreVerticle.java"); + content = FileUtils.readFileToString(petVerticleFile); + + Assert.assertTrue( + content.contains("RouterBuilder.create(this.vertx, \"openapi.yaml\")")); + Assert.assertTrue(content.contains("routerBuilder.mountServicesFromExtensions();")); + Assert.assertTrue(content.contains("router.route(\"/*\").subRouter(openapiRouter);")); + Assert.assertTrue(content.contains("onSuccess(server -> startPromise.complete())")); + Assert.assertTrue(content.contains("onFailure(startPromise::fail);")); + + final File packageInfoModelFile = new File(output, + "/src/main/java/io/swagger/server/api/model/" + PACKAGE_INFO); + Assert.assertFalse(packageInfoModelFile.exists()); + + final File petServiceFiles = new File(output, + "/src/main/java/io/swagger/server/api/service"); + for (File file : petServiceFiles.listFiles()) { + Assert.assertTrue(SERVICE_AS_EXTENSION_FILENAMES.contains(file.getName()) || PACKAGE_INFO.equals(file.getName())); + content = FileUtils.readFileToString(file); + + if (PACKAGE_INFO.equals(file.getName())) { + Assert.assertTrue(content.contains("@ModuleGen(name = \"service\", groupPackage = \"io.swagger.server.api.service\", useFutures = false)")); + Assert.assertTrue(content.contains("package io.swagger.server.api.service;")); + Assert.assertTrue(content.contains("import io.vertx.codegen.annotations.ModuleGen;")); + } else { + Assert.assertTrue(content.contains("@WebApiServiceGen")); + Assert.assertTrue(content.contains("String WEBSERVICE_ADDRESS_")); + Assert.assertTrue(content.contains("RequestParameter body, ServiceRequest request,")); + Assert.assertFalse(content.contains("Future")); + Assert.assertTrue(content.contains("Handler> resultHandler);")); + } + } + } + +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/MicronautGeneratorCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/MicronautGeneratorCodegenTest.java new file mode 100644 index 0000000000..db50d0e105 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/java/MicronautGeneratorCodegenTest.java @@ -0,0 +1,69 @@ +package io.swagger.codegen.v3.generators.java; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.junit.rules.TemporaryFolder; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; + +import io.swagger.codegen.v3.ClientOptInput; +import io.swagger.codegen.v3.DefaultGenerator; +import io.swagger.codegen.v3.config.CodegenConfigurator; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; + +public class MicronautGeneratorCodegenTest extends AbstractCodegenTest { + private final TemporaryFolder folder = new TemporaryFolder(); + private File output = null; + + @BeforeClass + public void generateCode() throws IOException { + this.folder.create(); + output = this.folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("micronaut") + .setInputSpecURL("src/test/resources/3_0_0/parameterValidation.yaml") + .setOutputDir(output.getAbsolutePath()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + } + + @AfterClass + public void cleanUp() { + this.folder.delete(); + } + + @Test(description = "verify that model classes are generated") + public void testModels() { + Assert.assertTrue(new File(output, "/src/main/java/io/swagger/model/LocalizedText.java").exists()); + } + + @Test(description = "verify that configuration classes are generated") + public void testConfigurations() { + Assert.assertTrue(new File(output, "/src/main/java/io/swagger/configuration/UnsupportedOperationExceptionHandler.java").exists()); + } + + @Test(description = "verify interface api generated") + public void testApiInterface() throws IOException { + final String expectedContent = "public interface AdminApi {"; + final File controllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String content = FileUtils.readFileToString(controllerFile); + Assert.assertTrue(content.contains(expectedContent)); + } + + @Test(description = "verify that parameters are listed as follows: header, path, query, cookie, body") + public void testApiParameters() throws IOException { + final String expectedContent = "default Single> updateTest(@NotNull @Valid @Parameter(description = \"Localized Text object.\") @Body LocalizedText body" + + ",@NotNull @Pattern(regexp=\"[0-9]+\") @Parameter(description = \"header description\") @Header(value = \"x-header\") String xHeader" + + ",@Parameter(description = \"path description\") @PathVariable(\"id\") Long id" + + ",@Nullable @Parameter(description = \"query description\") @QueryValue(value = \"name\") String name"; + final File controllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String content = FileUtils.readFileToString(controllerFile); + Assert.assertTrue(content.contains(expectedContent)); + } +} \ No newline at end of file diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/SpringGeneratorCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/SpringGeneratorCodegenTest.java new file mode 100644 index 0000000000..2717890eca --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/java/SpringGeneratorCodegenTest.java @@ -0,0 +1,200 @@ +package io.swagger.codegen.v3.generators.java; + +import static io.swagger.codegen.v3.generators.java.AbstractJavaCodegen.JAKARTA; +import static io.swagger.codegen.v3.generators.java.AbstractJavaCodegen.JAVA8_MODE; + +import io.swagger.codegen.v3.ClientOptInput; +import io.swagger.codegen.v3.CodegenArgument; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.DefaultGenerator; +import io.swagger.codegen.v3.config.CodegenConfigurator; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import org.apache.commons.io.FileUtils; +import org.junit.rules.TemporaryFolder; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.Collections; + +public class SpringGeneratorCodegenTest extends AbstractCodegenTest { + @Test(description = "verify that parameters are listed in following order: header, query, path, cookie, body (OAS 2.x)") + public void testParameterOrdersUseOas2() throws Exception { + final TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/parameterOrder.yaml") + .setOutputDir(output.getAbsolutePath()); + + configurator.setCodegenArguments(Collections.singletonList( + new CodegenArgument() + .option(CodegenConstants.USE_OAS2_OPTION) + .type("boolean") + .value(Boolean.TRUE.toString()))); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains("ResponseEntity updateTest(@ApiParam(value = \"description\", required=true) @PathVariable(\"id\") Long id")); + Assert.assertTrue(content.contains("@ApiParam(value = \"Localized Text object containing updated data.\", required=true ) @Valid @RequestBody LocalizedText body")); + + final File adminApiControllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApiController.java"); + final String contentAdminApiController = FileUtils.readFileToString(adminApiControllerFile); + + Assert.assertFalse(contentAdminApiController.contains("jakarta")); + Assert.assertTrue(contentAdminApiController.contains("javax")); + + folder.delete(); + } + + @Test(description = "verify that parameters are listed in following order: header, query, path, cookie, body (OAS 3.x)") + public void testParameterOrdersUseOas3() throws Exception { + final TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/parameterOrder.yaml") + .setOutputDir(output.getAbsolutePath()); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File petControllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String content = FileUtils.readFileToString(petControllerFile); + + Assert.assertTrue(content.contains("ResponseEntity updateTest(@Parameter(in = ParameterIn.PATH, description = \"description\", required=true, schema=@Schema()) @PathVariable(\"id\") Long id")); + Assert.assertTrue(content.contains("@Parameter(in = ParameterIn.DEFAULT, description = \"Localized Text object containing updated data.\", required=true, schema=@Schema()) @Valid @RequestBody LocalizedText body")); + + final File adminApiControllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApiController.java"); + final String contentAdminApiController = FileUtils.readFileToString(adminApiControllerFile); + + Assert.assertFalse(contentAdminApiController.contains("jakarta")); + Assert.assertTrue(contentAdminApiController.contains("javax")); + + folder.delete(); + } + + @Test(description = "verify oas2 & jakarta") + public void testOas2AndJakarta() throws Exception { + final TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/parameterOrder.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(JAKARTA, true); + + configurator.setCodegenArguments(Collections.singletonList( + new CodegenArgument() + .option(CodegenConstants.USE_OAS2_OPTION) + .type("boolean") + .value(Boolean.TRUE.toString()))); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File adminApiFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String contentAdminApi = FileUtils.readFileToString(adminApiFile); + + Assert.assertTrue(contentAdminApi.contains("ResponseEntity updateTest(@ApiParam(value = \"description\", required=true) @PathVariable(\"id\") Long id")); + Assert.assertTrue(contentAdminApi.contains("@ApiParam(value = \"Localized Text object containing updated data.\", required=true ) @Valid @RequestBody LocalizedText body")); + + final File adminApiControllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApiController.java"); + final String contentAdminApiController = FileUtils.readFileToString(adminApiControllerFile); + + Assert.assertTrue(contentAdminApiController.contains("jakarta")); + Assert.assertFalse(contentAdminApiController.contains("javax")); + + folder.delete(); + } + + @Test(description = "verify oas3 & jakarta") + public void testUseOas3AndJakarta() throws Exception { + final TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/parameterOrder.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(JAKARTA, true); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File adminApiFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String contentAdminApi = FileUtils.readFileToString(adminApiFile); + + Assert.assertTrue(contentAdminApi.contains("ResponseEntity updateTest(@Parameter(in = ParameterIn.PATH, description = \"description\", required=true, schema=@Schema()) @PathVariable(\"id\") Long id")); + Assert.assertTrue(contentAdminApi.contains("@Parameter(in = ParameterIn.DEFAULT, description = \"Localized Text object containing updated data.\", required=true, schema=@Schema()) @Valid @RequestBody LocalizedText body")); + + + final File adminApiControllerFile = new File(output, "/src/main/java/io/swagger/api/AdminApiController.java"); + final String contentAdminApiController = FileUtils.readFileToString(adminApiControllerFile); + + Assert.assertTrue(contentAdminApiController.contains("jakarta")); + Assert.assertFalse(contentAdminApiController.contains("javax")); + + folder.delete(); + } + + @Test(description = "verify java8 & jakarta") + public void testJava8Jakarta() throws Exception { + final TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/parameterOrder.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(JAKARTA, true) + .addAdditionalProperty(JAVA8_MODE, true); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File adminApiFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String contentAdminApi = FileUtils.readFileToString(adminApiFile); + + Assert.assertTrue(contentAdminApi.contains("import jakarta.servlet.http.HttpServletRequest;")); + + folder.delete(); + } + + @Test(description = "verify java8 & javax") + public void testJava8Javax() throws Exception { + final TemporaryFolder folder = new TemporaryFolder(); + folder.create(); + final File output = folder.getRoot(); + + final CodegenConfigurator configurator = new CodegenConfigurator() + .setLang("spring") + .setInputSpecURL("src/test/resources/3_0_0/parameterOrder.yaml") + .setOutputDir(output.getAbsolutePath()) + .addAdditionalProperty(JAKARTA, false) + .addAdditionalProperty(JAVA8_MODE, true); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + new DefaultGenerator().opts(clientOptInput).generate(); + + final File adminApiFile = new File(output, "/src/main/java/io/swagger/api/AdminApi.java"); + final String contentAdminApi = FileUtils.readFileToString(adminApiFile); + + Assert.assertTrue(contentAdminApi.contains("import javax.servlet.http.HttpServletRequest;")); + + folder.delete(); + } + +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegenModelTest.java b/src/test/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegenModelTest.java index 822d3f907f..e783e52c97 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegenModelTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/kotlin/KotlinClientCodegenModelTest.java @@ -4,6 +4,9 @@ import io.swagger.codegen.v3.CodegenConstants; import io.swagger.codegen.v3.CodegenModel; import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.DateTimeSchema; import io.swagger.v3.oas.models.media.IntegerSchema; @@ -17,6 +20,8 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.util.HashMap; + import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; @SuppressWarnings("static-method") @@ -24,14 +29,14 @@ public class KotlinClientCodegenModelTest { protected static final Logger LOGGER = LoggerFactory.getLogger(KotlinClientCodegenModelTest.class); - private Schema getArrayTestSchema() { + private Schema getArrayTestSchema() { final Schema propertySchema = new ArraySchema() - .items(new StringSchema()) - .description("an array property"); + .items(new StringSchema()) + .description("an array property"); return new Schema() - .type("object") - .description("a sample model") - .addProperties("examples", propertySchema); + .type("object") + .description("a sample model") + .addProperties("examples", propertySchema); } private Schema getSimpleSchema() { @@ -39,9 +44,9 @@ private Schema getSimpleSchema() { .type("object") .description("a sample model") .addProperties("id", new IntegerSchema() - .format(SchemaTypeUtil.INTEGER64_FORMAT)) + .format(SchemaTypeUtil.INTEGER64_FORMAT)) .addProperties("first-name", new StringSchema() - .example("Tony")) + .example("Tony")) .addProperties("createdAt", new DateTimeSchema()) .addRequiredItem("id") .addRequiredItem("first-name"); @@ -49,11 +54,11 @@ private Schema getSimpleSchema() { private Schema getMapSchema() { return new Schema() - .type("object") - .description("a sample model") - .addProperties("mapping", new MapSchema() - .additionalProperties(new StringSchema())) - .addRequiredItem("id"); + .type("object") + .description("a sample model") + .addProperties("mapping", new MapSchema() + .additionalProperties(new StringSchema())) + .addRequiredItem("id"); } private Schema getComplexSchema() { @@ -64,7 +69,7 @@ private Schema getComplexSchema() { } @Test(description = "convert a simple model") - public void simpleModelTest() { + public void simpleModelTest() { final Schema schema = getSimpleSchema(); final KotlinClientCodegen codegen = new KotlinClientCodegen(); final CodegenModel cm = codegen.fromModel("sample", schema); @@ -91,7 +96,7 @@ public void simpleModelTest() { Assert.assertEquals(property2.name, "firstName"); Assert.assertEquals(property2.defaultValue, "null"); Assert.assertEquals(property2.baseType, "kotlin.String"); - Assert.assertTrue(getBooleanValue(property2, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertTrue(getBooleanValue(property2, CodegenConstants.HAS_MORE_EXT_NAME)); Assert.assertTrue(property2.required); Assert.assertTrue(getBooleanValue(property2, CodegenConstants.IS_PRIMITIVE_TYPE_EXT_NAME)); Assert.assertTrue(getBooleanValue(property2, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); @@ -102,9 +107,9 @@ public void simpleModelTest() { Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); Assert.assertEquals(property3.baseType, "java.time.LocalDateTime"); - Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); Assert.assertFalse(property3.required); - Assert.assertTrue(getBooleanValue(property3, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + Assert.assertTrue(getBooleanValue(property3, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); } @Test(description = "convert a simple model: threetenbp") @@ -122,7 +127,7 @@ public void selectDateLibraryAsThreetenbp() { Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); Assert.assertEquals(property3.baseType, "org.threeten.bp.LocalDateTime"); - Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); Assert.assertFalse(property3.required); Assert.assertTrue(getBooleanValue(property3, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); } @@ -142,7 +147,7 @@ public void selectDateLibraryAsString() { Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); Assert.assertEquals(property3.baseType, "kotlin.String"); - Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); Assert.assertFalse(property3.required); Assert.assertTrue(getBooleanValue(property3, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); } @@ -162,7 +167,7 @@ public void selectDateLibraryAsJava8() { Assert.assertEquals(property3.name, "createdAt"); Assert.assertEquals(property3.defaultValue, "null"); Assert.assertEquals(property3.baseType, "java.time.LocalDateTime"); - Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); Assert.assertFalse(property3.required); Assert.assertTrue(getBooleanValue(property3, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); } @@ -218,6 +223,7 @@ public void mapPropertyTest() { public void complexPropertyTest() { final Schema schema = getComplexSchema(); final CodegenConfig codegen = new KotlinClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", schema); Assert.assertEquals(cm.name, "sample"); @@ -239,7 +245,10 @@ public static Object[][] modelNames() { return new Object[][]{ {"TestNs.TestClass", new ModelNameTest("TestNs.TestClass", "TestNsTestClass")}, {"$", new ModelNameTest("$", "Dollar")}, - {"for", new ModelNameTest("`for`", "`for`")}, + {"for", new ModelNameTest("`for`", "For")}, + {"package", new ModelNameTest("`package`", "Package")}, + {"abstract", new ModelNameTest("`abstract`", "Abstract")}, + {"companion", new ModelNameTest("`companion`", "_Companion")}, {"One createOptions() { .put(CodegenConstants.ARTIFACT_ID, ARTIFACT_ID) .put(CodegenConstants.GROUP_ID, GROUP_ID) .put(CodegenConstants.SOURCE_FOLDER, SOURCE_FOLDER) - .put(CodegenConstants.ENUM_PROPERTY_NAMING, ENUM_PROPERTY_NAMING) .put(KotlinClientCodegen.DATE_LIBRARY, DATE_LIBRARY) .build(); } diff --git a/src/test/java/io/swagger/codegen/v3/generators/options/RubyClientOptionsProvider.java b/src/test/java/io/swagger/codegen/v3/generators/options/RubyClientOptionsProvider.java new file mode 100644 index 0000000000..dfb13b391d --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/options/RubyClientOptionsProvider.java @@ -0,0 +1,55 @@ +package io.swagger.codegen.v3.generators.options; + +import io.swagger.codegen.CodegenConstants; +import io.swagger.codegen.languages.RubyClientCodegen; + +import com.google.common.collect.ImmutableMap; + +import java.util.Map; + +public class RubyClientOptionsProvider implements OptionsProvider { + public static final String GEM_NAME_VALUE = "swagger_client_ruby"; + public static final String MODULE_NAME_VALUE = "SwaggerClientRuby"; + public static final String GEM_VERSION_VALUE = "1.0.0-SNAPSHOT"; + public static final String SORT_PARAMS_VALUE = "false"; + public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; + public static final String GEM_LICENSE_VALUE = "MIT"; + public static final String GEM_REQUIRED_RUBY_VERSION_VALUE = ">= 1.9"; + public static final String GEM_HOMEPAGE_VALUE = "homepage"; + public static final String GEM_SUMMARY_VALUE = "summary"; + public static final String GEM_DESCRIPTION_VALUE = "description"; + public static final String GEM_AUTHOR_VALUE = "foo"; + public static final String GEM_AUTHOR_EMAIL_VALUE = "foo"; + public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; + + + @Override + public String getLanguage() { + return "ruby"; + } + + @Override + public Map createOptions() { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + return builder.put(RubyClientCodegen.GEM_NAME, GEM_NAME_VALUE) + .put(RubyClientCodegen.MODULE_NAME, MODULE_NAME_VALUE) + .put(RubyClientCodegen.GEM_VERSION, GEM_VERSION_VALUE) + .put(RubyClientCodegen.GEM_LICENSE, GEM_LICENSE_VALUE) + .put(RubyClientCodegen.GEM_REQUIRED_RUBY_VERSION, GEM_REQUIRED_RUBY_VERSION_VALUE) + .put(RubyClientCodegen.GEM_DESCRIPTION, GEM_DESCRIPTION_VALUE) + .put(RubyClientCodegen.GEM_HOMEPAGE, GEM_HOMEPAGE_VALUE) + .put(RubyClientCodegen.GEM_SUMMARY, GEM_SUMMARY_VALUE) + .put(RubyClientCodegen.GEM_AUTHOR, GEM_AUTHOR_VALUE) + .put(RubyClientCodegen.GEM_AUTHOR_EMAIL, GEM_AUTHOR_EMAIL_VALUE) + .put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE) + .put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE) + .put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, "true") + .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) + .build(); + } + + @Override + public boolean isServer() { + return false; + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptAngularClientOptionsProvider.java b/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptAngularClientOptionsProvider.java index 50bf189aca..8a85efc777 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptAngularClientOptionsProvider.java +++ b/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptAngularClientOptionsProvider.java @@ -15,6 +15,7 @@ public class TypeScriptAngularClientOptionsProvider implements OptionsProvider { private static final String NMP_VERSION = "1.1.2"; private static final String NPM_REPOSITORY = "https://registry.npmjs.org"; public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; + private static final String PROVIDED_IN_ROOT = "true"; public static final String NG_VERSION = "2"; @@ -36,6 +37,7 @@ public Map createOptions() { .put(TypeScriptAngularClientCodegen.WITH_INTERFACES, Boolean.FALSE.toString()) .put(TypeScriptAngularClientCodegen.NPM_REPOSITORY, NPM_REPOSITORY) .put(TypeScriptAngularClientCodegen.NG_VERSION, NG_VERSION) + .put(TypeScriptAngularClientCodegen.PROVIDED_IN_ROOT, PROVIDED_IN_ROOT) .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) .build(); } diff --git a/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptFetchClientOptionsProvider.java b/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptFetchClientOptionsProvider.java new file mode 100644 index 0000000000..23c9627a23 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/options/TypeScriptFetchClientOptionsProvider.java @@ -0,0 +1,45 @@ +package io.swagger.codegen.v3.generators.options; + +import com.google.common.collect.ImmutableMap; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.generators.typescript.TypeScriptAngularClientCodegen; + +import java.util.Map; + +public class TypeScriptFetchClientOptionsProvider implements OptionsProvider { + public static final String SUPPORTS_ES6_VALUE = "false"; + public static final String SORT_PARAMS_VALUE = "false"; + public static final String ENSURE_UNIQUE_PARAMS_VALUE = "true"; + public static final String MODEL_PROPERTY_NAMING_VALUE = "camelCase"; + private static final String NMP_NAME = "npmName"; + private static final String NMP_VERSION = "1.1.2"; + private static final String NPM_REPOSITORY = "https://registry.npmjs.org"; + public static final String ALLOW_UNICODE_IDENTIFIERS_VALUE = "false"; + private static final String PROVIDED_IN_ROOT = "true"; + public static final String NG_VERSION = "2"; + + @Override + public String getLanguage() { + return "typescript-fetch"; + } + + @Override + public Map createOptions() { + ImmutableMap.Builder builder = new ImmutableMap.Builder(); + return builder.put(CodegenConstants.SORT_PARAMS_BY_REQUIRED_FLAG, SORT_PARAMS_VALUE) + .put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE) + .put(CodegenConstants.MODEL_PROPERTY_NAMING, MODEL_PROPERTY_NAMING_VALUE) + .put(CodegenConstants.SUPPORTS_ES6, SUPPORTS_ES6_VALUE) + .put(TypeScriptAngularClientCodegen.NPM_NAME, NMP_NAME) + .put(TypeScriptAngularClientCodegen.NPM_VERSION, NMP_VERSION) + .put(TypeScriptAngularClientCodegen.SNAPSHOT, Boolean.FALSE.toString()) + .put(TypeScriptAngularClientCodegen.WITH_INTERFACES, Boolean.FALSE.toString()) + .put(TypeScriptAngularClientCodegen.NPM_REPOSITORY, NPM_REPOSITORY) + .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE).build(); + } + + @Override + public boolean isServer() { + return false; + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/php/PhpClientCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/php/PhpClientCodegenTest.java index 9f882a1d66..3bfb39f7e9 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/php/PhpClientCodegenTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/php/PhpClientCodegenTest.java @@ -75,7 +75,7 @@ public void testPutTemplateDirProperty() throws Exception { codegen.additionalProperties().put(CodegenConstants.TEMPLATE_DIR, "/absolute/path"); codegen.processOpts(); - Assert.assertEquals(codegen.templateDir(), "/absolute/path"); + Assert.assertEquals(codegen.customTemplateDir(), "/absolute/path"); Assert.assertEquals(codegen.embeddedTemplateDir(), "handlebars" + File.separator + "php"); } } \ No newline at end of file diff --git a/src/test/java/io/swagger/codegen/v3/generators/python/PythonClientCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/python/PythonClientCodegenTest.java new file mode 100644 index 0000000000..866f7ea714 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/python/PythonClientCodegenTest.java @@ -0,0 +1,41 @@ +package io.swagger.codegen.v3.generators.python; + +import io.swagger.codegen.v3.generators.AbstractCodegenTest; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class PythonClientCodegenTest extends AbstractCodegenTest { + @Test + public void testToModelName() { + PythonClientCodegen pythonClientCodegen = new PythonClientCodegen(); + + // no type - this is 'object' in Python + Assert.assertEquals(pythonClientCodegen.toModelName(null), "object"); + // assume this is a model type - "null" is not special in Python + Assert.assertEquals(pythonClientCodegen.toModelName("null"), "Null"); + // reserved word + Assert.assertEquals(pythonClientCodegen.toModelName("return"), "ModelReturn"); + Assert.assertEquals(pythonClientCodegen.toModelName("None"), "ModelNone"); + // $ + Assert.assertEquals(pythonClientCodegen.toModelName("my$result"), "Myresult"); + // Starts with number + Assert.assertEquals(pythonClientCodegen.toModelName("999Bad"), "Model999Bad"); + // Camel Case + Assert.assertEquals(pythonClientCodegen.toModelName("camel_case"), "CamelCase"); + } + + @Test + public void testToModelNamePrefixSuffix() { + PythonClientCodegen pythonClientCodegen = new PythonClientCodegen(); + pythonClientCodegen.setModelNamePrefix("xprefixx"); + + // Camel Case + Assert.assertEquals(pythonClientCodegen.toModelName("camel_case"), "XprefixxCamelCase"); + + pythonClientCodegen.setModelNamePrefix(null); + pythonClientCodegen.setModelNameSuffix("xsuffixx"); + + // Camel Case + Assert.assertEquals(pythonClientCodegen.toModelName("camel_case"), "CamelCaseXsuffixx"); + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/ruby/RubyClientCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/ruby/RubyClientCodegenTest.java new file mode 100644 index 0000000000..558e7a6092 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/ruby/RubyClientCodegenTest.java @@ -0,0 +1,101 @@ +package io.swagger.codegen.v3.generators.ruby; + +import io.swagger.codegen.v3.*; +import io.swagger.parser.OpenAPIParser; +import io.swagger.v3.oas.models.OpenAPI; +import org.apache.commons.io.FileUtils; +import org.junit.rules.TemporaryFolder; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.testng.Assert.*; + +/** + * Tests for RubyClientCodegen-generated templates + */ +public class RubyClientCodegenTest { + + private TemporaryFolder folder = null; + + @BeforeMethod + public void setUp() throws Exception { + folder = new TemporaryFolder(); + folder.create(); + } + + @AfterMethod + public void tearDown() { + folder.delete(); + } + + @Test + public void testGenerateRubyClientWithHtmlEntity() throws Exception { + final File output = folder.getRoot(); + + final OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/3_0_0/requiredFormParamsTest.yaml", null, null) + .getOpenAPI(); + CodegenConfig codegenConfig = new RubyClientCodegen(); + codegenConfig.setOutputDir(output.getAbsolutePath()); + + ClientOptInput clientOptInput = new ClientOptInput() + .opts(new ClientOpts()) + .openAPI(openAPI) + .config(codegenConfig); + + DefaultGenerator generator = new DefaultGenerator(); + List files = generator.opts(clientOptInput).generate(); + boolean apiFileGenerated = false; + for (File file : files) { + if (file.getName().equals("default_api.rb")) { + apiFileGenerated = true; + // Ruby client should set the path unescaped in the api file + assertTrue(FileUtils.readFileToString(file, StandardCharsets.UTF_8).contains("local_var_path = '/test_optional'")); + } + } + if (!apiFileGenerated) { + fail("Default api file is not generated!"); + } + } + + @Test + public void testInitialConfigValues() throws Exception { + final RubyClientCodegen codegen = new RubyClientCodegen(); + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.TRUE); + Assert.assertTrue(codegen.getHideGenerationTimestamp()); + Assert.assertEquals(codegen.modelPackage(), "models"); + Assert.assertEquals(codegen.apiPackage(), "api"); + } + + @Test + public void testSettersForConfigValues() throws Exception { + final RubyClientCodegen codegen = new RubyClientCodegen(); + codegen.setHideGenerationTimestamp(false); + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.FALSE); + Assert.assertFalse(codegen.getHideGenerationTimestamp()); + } + + @Test + public void testAdditionalPropertiesPutForConfigValues() throws Exception { + final RubyClientCodegen codegen = new RubyClientCodegen(); + codegen.additionalProperties().put(CodegenConstants.HIDE_GENERATION_TIMESTAMP, false); + codegen.additionalProperties().put(CodegenConstants.MODEL_PACKAGE, "ruby-models"); + codegen.additionalProperties().put(CodegenConstants.API_PACKAGE, "ruby-api"); + codegen.processOpts(); + + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.HIDE_GENERATION_TIMESTAMP), Boolean.FALSE); + Assert.assertFalse(codegen.getHideGenerationTimestamp()); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.MODEL_PACKAGE), "ruby-models"); + Assert.assertEquals(codegen.additionalProperties().get(CodegenConstants.API_PACKAGE), "ruby-api"); + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/ruby/RubyClientOptionsTest.java b/src/test/java/io/swagger/codegen/v3/generators/ruby/RubyClientOptionsTest.java new file mode 100644 index 0000000000..1d1d361165 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/ruby/RubyClientOptionsTest.java @@ -0,0 +1,50 @@ +package io.swagger.codegen.v3.generators.ruby; + +import io.swagger.codegen.v3.CodegenConfig; +import io.swagger.codegen.v3.generators.AbstractOptionsTest; +import io.swagger.codegen.v3.generators.options.RubyClientOptionsProvider; +import mockit.Expectations; +import mockit.Tested; + +public class RubyClientOptionsTest extends AbstractOptionsTest { + + @Tested + private RubyClientCodegen clientCodegen; + + public RubyClientOptionsTest() { + super(new RubyClientOptionsProvider()); + } + + @Override + protected CodegenConfig getCodegenConfig() { + return clientCodegen; + } + + @SuppressWarnings("unused") + @Override + protected void setExpectations() { + new Expectations(clientCodegen) {{ + clientCodegen.setGemName(RubyClientOptionsProvider.GEM_NAME_VALUE); + times = 1; + clientCodegen.setModuleName(RubyClientOptionsProvider.MODULE_NAME_VALUE); + times = 1; + clientCodegen.setGemVersion(RubyClientOptionsProvider.GEM_VERSION_VALUE); + times = 1; + clientCodegen.setGemLicense(RubyClientOptionsProvider.GEM_LICENSE_VALUE); + times = 1; + clientCodegen.setGemRequiredRubyVersion(RubyClientOptionsProvider.GEM_REQUIRED_RUBY_VERSION_VALUE); + times = 1; + clientCodegen.setGemHomepage(RubyClientOptionsProvider.GEM_HOMEPAGE_VALUE); + times = 1; + clientCodegen.setGemDescription(RubyClientOptionsProvider.GEM_DESCRIPTION_VALUE); + times = 1; + clientCodegen.setGemSummary(RubyClientOptionsProvider.GEM_SUMMARY_VALUE); + times = 1; + clientCodegen.setGemAuthor(RubyClientOptionsProvider.GEM_AUTHOR_VALUE); + times = 1; + clientCodegen.setGemAuthorEmail(RubyClientOptionsProvider.GEM_AUTHOR_EMAIL_VALUE); + times = 1; + + }}; + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegenTest.java index c3109de2c9..a659b1cb5e 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegenTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/scala/AkkaHttpServerCodegenTest.java @@ -259,7 +259,7 @@ public void testFileGeneration() throws IOException { Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/api/UserApi.scala").exists()); Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/ApiResponse.scala").exists()); - Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/Body.scala").exists()); + Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/Pet_petId_body.scala").exists()); Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/Category.scala").exists()); Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/Order.scala").exists()); Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/Pet.scala").exists()); @@ -269,4 +269,4 @@ public void testFileGeneration() throws IOException { Assert.assertTrue(new File(output, "src/main/scala/io/swagger/server/model/User.scala").exists()); folder.delete(); } -} \ No newline at end of file +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/swift/Swift3ModelTest.java b/src/test/java/io/swagger/codegen/v3/generators/swift/Swift3ModelTest.java index 0b9086d734..129e96c295 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/swift/Swift3ModelTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/swift/Swift3ModelTest.java @@ -31,7 +31,6 @@ public void simpleModelTest() { Assert.assertEquals(cm.classname, "Sample"); Assert.assertEquals(cm.description, "a sample model"); Assert.assertEquals(cm.vars.size(), 7); - Assert.assertEquals(cm.discriminator.getPropertyName(),"test"); final CodegenProperty property1 = cm.vars.get(0); Assert.assertEquals(property1.baseName, "id"); @@ -119,8 +118,7 @@ private Schema getSimpleSchema() { .addProperties("uuid", new UUIDSchema()) .addProperties("dateOfBirth", new DateSchema()) .addRequiredItem("id") - .addRequiredItem("name") - .discriminator(new Discriminator().propertyName("test")); + .addRequiredItem("name"); } } diff --git a/src/test/java/io/swagger/codegen/v3/generators/swift/Swift4ModelTest.java b/src/test/java/io/swagger/codegen/v3/generators/swift/Swift4ModelTest.java index 3948ab87f4..c4171fde4a 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/swift/Swift4ModelTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/swift/Swift4ModelTest.java @@ -31,7 +31,6 @@ public void simpleModelTest() { Assert.assertEquals(cm.classname, "Sample"); Assert.assertEquals(cm.description, "a sample model"); Assert.assertEquals(cm.vars.size(), 7); - Assert.assertEquals(cm.discriminator.getPropertyName(),"test"); final CodegenProperty property1 = cm.vars.get(0); Assert.assertEquals(property1.baseName, "id"); @@ -119,8 +118,7 @@ private Schema getSimpleSchema() { .addProperties("uuid", new UUIDSchema()) .addProperties("dateOfBirth", new DateSchema()) .addRequiredItem("id") - .addRequiredItem("name") - .discriminator(new Discriminator().propertyName("test")); + .addRequiredItem("name"); } } diff --git a/src/test/java/io/swagger/codegen/v3/generators/typescript/angular/TypeScriptAngularModelTest.java b/src/test/java/io/swagger/codegen/v3/generators/typescript/angular/TypeScriptAngularModelTest.java index 589d9f840f..57424fb3dd 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/typescript/angular/TypeScriptAngularModelTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/typescript/angular/TypeScriptAngularModelTest.java @@ -4,8 +4,11 @@ import io.swagger.codegen.v3.CodegenConstants; import io.swagger.codegen.v3.CodegenModel; import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.generators.AbstractCodegenTest; import io.swagger.codegen.v3.generators.DefaultCodegenConfig; import io.swagger.codegen.v3.generators.typescript.TypeScriptAngularClientCodegen; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.DateSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; @@ -20,7 +23,7 @@ import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; @SuppressWarnings("static-method") -public class TypeScriptAngularModelTest { +public class TypeScriptAngularModelTest /**extends AbstractCodegenTest*/ { @Test(description = "convert a simple TypeScript Angular model") public void simpleModelTest() { @@ -125,6 +128,7 @@ public void complexPropertyTest() { .description("a sample model") .addProperties("children", new Schema().$ref("#/components/schemas/Children")); final DefaultCodegenConfig codegen = new TypeScriptAngularClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", model); Assert.assertEquals(cm.name, "sample"); @@ -149,6 +153,7 @@ public void complexListPropertyTest() { .addProperties("children", new ArraySchema() .items(new Schema().$ref("#/components/schemas/Children"))); final DefaultCodegenConfig codegen = new TypeScriptAngularClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", model); Assert.assertEquals(cm.name, "sample"); @@ -172,6 +177,8 @@ public void arrayModelTest() { .items(new Schema().$ref("#/components/schemas/Children")) .description("an array model"); final DefaultCodegenConfig codegen = new TypeScriptAngularClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); + final CodegenModel cm = codegen.fromModel("sample", model); Assert.assertEquals(cm.name, "sample"); @@ -186,6 +193,7 @@ public void mapModelTest() { .description("a map model") .additionalProperties(new Schema().$ref("#/components/schemas/Children")); final DefaultCodegenConfig codegen = new TypeScriptAngularClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); final CodegenModel cm = codegen.fromModel("sample", model); Assert.assertEquals(cm.name, "sample"); diff --git a/src/test/java/io/swagger/codegen/v3/generators/typescript/fetch/TypeScriptFetchClientOptionsTest.java b/src/test/java/io/swagger/codegen/v3/generators/typescript/fetch/TypeScriptFetchClientOptionsTest.java new file mode 100644 index 0000000000..4aab89e28e --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/typescript/fetch/TypeScriptFetchClientOptionsTest.java @@ -0,0 +1,39 @@ +package io.swagger.codegen.v3.generators.typescript.fetch; + +import io.swagger.codegen.v3.CodegenConfig; +import io.swagger.codegen.v3.generators.AbstractOptionsTest; +import io.swagger.codegen.v3.generators.options.TypeScriptFetchClientOptionsProvider; +import io.swagger.codegen.v3.generators.typescript.TypeScriptFetchClientCodegen; +import mockit.Expectations; +import mockit.Tested; + +public class TypeScriptFetchClientOptionsTest extends AbstractOptionsTest { + + @Tested + private TypeScriptFetchClientCodegen clientCodegen; + + public TypeScriptFetchClientOptionsTest() { + super(new TypeScriptFetchClientOptionsProvider()); + } + + @Override + protected CodegenConfig getCodegenConfig() { + return clientCodegen; + } + + @SuppressWarnings("unused") + @Override + protected void setExpectations() { + new Expectations(clientCodegen) { + { + clientCodegen.setSortParamsByRequiredFlag( + Boolean.valueOf(TypeScriptFetchClientOptionsProvider.SORT_PARAMS_VALUE)); + times = 1; + clientCodegen.setModelPropertyNaming(TypeScriptFetchClientOptionsProvider.MODEL_PROPERTY_NAMING_VALUE); + times = 1; + clientCodegen.setSupportsES6(Boolean.valueOf(TypeScriptFetchClientOptionsProvider.SUPPORTS_ES6_VALUE)); + times = 1; + } + }; + } +} diff --git a/src/test/java/io/swagger/codegen/v3/generators/typescript/fetch/TypeScriptFetchModelTest.java b/src/test/java/io/swagger/codegen/v3/generators/typescript/fetch/TypeScriptFetchModelTest.java new file mode 100644 index 0000000000..e6f136c311 --- /dev/null +++ b/src/test/java/io/swagger/codegen/v3/generators/typescript/fetch/TypeScriptFetchModelTest.java @@ -0,0 +1,196 @@ +package io.swagger.codegen.v3.generators.typescript.fetch; + +import com.google.common.collect.Sets; +import io.swagger.codegen.v3.CodegenConstants; +import io.swagger.codegen.v3.CodegenModel; +import io.swagger.codegen.v3.CodegenProperty; +import io.swagger.codegen.v3.generators.DefaultCodegenConfig; +import io.swagger.codegen.v3.generators.typescript.TypeScriptFetchClientCodegen; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.DateSchema; +import io.swagger.v3.oas.models.media.DateTimeSchema; +import io.swagger.v3.oas.models.media.IntegerSchema; +import io.swagger.v3.oas.models.media.MapSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.parser.util.SchemaTypeUtil; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; + +@SuppressWarnings("static-method") +public class TypeScriptFetchModelTest /** extends AbstractCodegenTest */ +{ + + @Test(description = "convert a simple TypeScript Fetch model") + public void simpleModelTest() { + final Schema model = new Schema().description("a sample model") + .addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT)) + .addProperties("name", new StringSchema()).addProperties("createdAt", new DateTimeSchema()) + .addProperties("birthDate", new DateSchema()).addRequiredItem("id").addRequiredItem("name"); + final DefaultCodegenConfig codegen = new TypeScriptFetchClientCodegen(); + final CodegenModel cm = codegen.fromModel("sample", model); + + Assert.assertEquals(cm.name, "sample"); + Assert.assertEquals(cm.classname, "Sample"); + Assert.assertEquals(cm.description, "a sample model"); + Assert.assertEquals(cm.vars.size(), 4); + + final CodegenProperty property1 = cm.vars.get(0); + Assert.assertEquals(property1.baseName, "id"); + Assert.assertEquals(property1.datatype, "number"); + Assert.assertEquals(property1.name, "id"); + Assert.assertEquals(property1.defaultValue, "undefined"); + Assert.assertEquals(property1.baseType, "number"); + Assert.assertTrue(getBooleanValue(property1, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertTrue(property1.required); + Assert.assertTrue(getBooleanValue(property1, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + + final CodegenProperty property2 = cm.vars.get(1); + Assert.assertEquals(property2.baseName, "name"); + Assert.assertEquals(property2.datatype, "string"); + Assert.assertEquals(property2.name, "name"); + Assert.assertEquals(property2.defaultValue, "undefined"); + Assert.assertEquals(property2.baseType, "string"); + Assert.assertTrue(getBooleanValue(property2, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertTrue(property2.required); + Assert.assertTrue(getBooleanValue(property2, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + + final CodegenProperty property3 = cm.vars.get(2); + Assert.assertEquals(property3.baseName, "createdAt"); + Assert.assertEquals(property3.complexType, null); + Assert.assertEquals(property3.datatype, "Date"); + Assert.assertEquals(property3.name, "createdAt"); + Assert.assertEquals(property3.baseType, "Date"); + Assert.assertEquals(property3.defaultValue, "undefined"); + Assert.assertTrue(getBooleanValue(property3, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(property3.required); + Assert.assertTrue(getBooleanValue(property3, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + + final CodegenProperty property4 = cm.vars.get(3); + Assert.assertEquals(property4.baseName, "birthDate"); + Assert.assertEquals(property4.complexType, null); + Assert.assertEquals(property4.datatype, "string"); + Assert.assertEquals(property4.name, "birthDate"); + Assert.assertEquals(property4.baseType, "string"); + Assert.assertEquals(property4.defaultValue, "undefined"); + Assert.assertFalse(getBooleanValue(property4, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(property4.required); + Assert.assertTrue(getBooleanValue(property4, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + + } + + @Test(description = "convert a model with list property") + public void listPropertyTest() { + final Schema model = new Schema().description("a sample model") + .addProperties("id", new IntegerSchema().format(SchemaTypeUtil.INTEGER64_FORMAT)) + .addProperties("urls", new ArraySchema().items(new StringSchema())).addRequiredItem("id"); + final DefaultCodegenConfig codegen = new TypeScriptFetchClientCodegen(); + final CodegenModel cm = codegen.fromModel("sample", model); + + Assert.assertEquals(cm.name, "sample"); + Assert.assertEquals(cm.classname, "Sample"); + Assert.assertEquals(cm.description, "a sample model"); + Assert.assertEquals(cm.vars.size(), 2); + + final CodegenProperty property1 = cm.vars.get(0); + Assert.assertEquals(property1.baseName, "id"); + Assert.assertEquals(property1.datatype, "number"); + Assert.assertEquals(property1.name, "id"); + Assert.assertEquals(property1.defaultValue, "undefined"); + Assert.assertEquals(property1.baseType, "number"); + Assert.assertTrue(getBooleanValue(property1, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertTrue(property1.required); + Assert.assertTrue(getBooleanValue(property1, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + + final CodegenProperty property2 = cm.vars.get(1); + Assert.assertEquals(property2.baseName, "urls"); + Assert.assertEquals(property2.datatype, "Array"); + Assert.assertEquals(property2.name, "urls"); + Assert.assertEquals(property2.baseType, "Array"); + Assert.assertFalse(getBooleanValue(property2, CodegenConstants.HAS_MORE_EXT_NAME)); + Assert.assertFalse(property2.required); + Assert.assertFalse(getBooleanValue(property2, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + } + + @Test(description = "convert a model with complex property") + public void complexPropertyTest() { + final Schema model = new Schema().description("a sample model").addProperties("children", + new Schema().$ref("#/components/schemas/Children")); + final DefaultCodegenConfig codegen = new TypeScriptFetchClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); + final CodegenModel cm = codegen.fromModel("sample", model); + + Assert.assertEquals(cm.name, "sample"); + Assert.assertEquals(cm.classname, "Sample"); + Assert.assertEquals(cm.description, "a sample model"); + Assert.assertEquals(cm.vars.size(), 1); + + final CodegenProperty property1 = cm.vars.get(0); + Assert.assertEquals(property1.baseName, "children"); + Assert.assertEquals(property1.datatype, "Children"); + Assert.assertEquals(property1.name, "children"); + Assert.assertEquals(property1.defaultValue, "undefined"); + Assert.assertEquals(property1.baseType, "Children"); + Assert.assertFalse(property1.required); + Assert.assertTrue(getBooleanValue(property1, CodegenConstants.IS_NOT_CONTAINER_EXT_NAME)); + } + + @Test(description = "convert a model with complex list property") + public void complexListPropertyTest() { + final Schema model = new Schema().description("a sample model").addProperties("children", + new ArraySchema().items(new Schema().$ref("#/components/schemas/Children"))); + final DefaultCodegenConfig codegen = new TypeScriptFetchClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); + final CodegenModel cm = codegen.fromModel("sample", model); + + Assert.assertEquals(cm.name, "sample"); + Assert.assertEquals(cm.classname, "Sample"); + Assert.assertEquals(cm.description, "a sample model"); + Assert.assertEquals(cm.vars.size(), 1); + + final CodegenProperty property1 = cm.vars.get(0); + Assert.assertEquals(property1.baseName, "children"); + Assert.assertEquals(property1.complexType, "Children"); + Assert.assertEquals(property1.datatype, "Array"); + Assert.assertEquals(property1.name, "children"); + Assert.assertEquals(property1.baseType, "Array"); + Assert.assertFalse(property1.required); + Assert.assertTrue(getBooleanValue(property1, CodegenConstants.IS_CONTAINER_EXT_NAME)); + } + + @Test(description = "convert an array model") + public void arrayModelTest() { + final Schema model = new ArraySchema().items(new Schema().$ref("#/components/schemas/Children")) + .description("an array model"); + final DefaultCodegenConfig codegen = new TypeScriptFetchClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); + + final CodegenModel cm = codegen.fromModel("sample", model); + + Assert.assertEquals(cm.name, "sample"); + Assert.assertEquals(cm.classname, "Sample"); + Assert.assertEquals(cm.description, "an array model"); + Assert.assertEquals(cm.vars.size(), 0); + } + + @Test(description = "convert a map model") + public void mapModelTest() { + final Schema model = new MapSchema().description("a map model") + .additionalProperties(new Schema().$ref("#/components/schemas/Children")); + final DefaultCodegenConfig codegen = new TypeScriptFetchClientCodegen(); + codegen.preprocessOpenAPI(new OpenAPI().components(new Components())); + final CodegenModel cm = codegen.fromModel("sample", model); + + Assert.assertEquals(cm.name, "sample"); + Assert.assertEquals(cm.classname, "Sample"); + Assert.assertEquals(cm.description, "a map model"); + Assert.assertEquals(cm.vars.size(), 0); + Assert.assertEquals(cm.imports.size(), 1); + Assert.assertEquals(cm.additionalPropertiesType, "Children"); + Assert.assertEquals(Sets.intersection(cm.imports, Sets.newHashSet("Children")).size(), 1); + } +} diff --git a/src/test/resources/3_0_0/composedFlatten/allof_inline_ref.yaml b/src/test/resources/3_0_0/composedFlatten/allof_inline_ref.yaml new file mode 100644 index 0000000000..42d2d93f49 --- /dev/null +++ b/src/test/resources/3_0_0/composedFlatten/allof_inline_ref.yaml @@ -0,0 +1,48 @@ +openapi: 3.0.2 +info: + title: CC-20717 test - OAS3 + version: 1.0.0 +paths: + /something: + get: + responses: + 200: + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + properties: + foo: + type: string + Bar: + type: object + properties: + foo1: + description: An instance of Foo + allOf: + - $ref: '#/components/schemas/Foo' + foo2: + $ref: '#/components/schemas/Foo' + OneOfTest: + oneOf: + - $ref: "#/components/schemas/Foo" + - type: object + properties: + oneOfInlineBar: + type: string + SchemaTest: + allOf: + - type: object + properties: + schemaTestInline1Foo: + type: string + schemaTestInline1Ref: + type: array + items: + $ref: '#/components/schemas/Bar' + - $ref: '#/components/schemas/OneOfTest' diff --git a/src/test/resources/3_0_0/composedFlatten/allof_inline_ref_no_oneof.yaml b/src/test/resources/3_0_0/composedFlatten/allof_inline_ref_no_oneof.yaml new file mode 100644 index 0000000000..6549c80d0f --- /dev/null +++ b/src/test/resources/3_0_0/composedFlatten/allof_inline_ref_no_oneof.yaml @@ -0,0 +1,48 @@ +openapi: 3.0.2 +info: + title: CC-20717 test - OAS3 + version: 1.0.0 +paths: + /something: + get: + responses: + 200: + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + properties: + foo: + type: string + Bar: + type: object + properties: + foo1: + description: An instance of Foo + allOf: + - $ref: '#/components/schemas/Foo' + foo2: + $ref: '#/components/schemas/Foo' + OneOfTest: + oneOf: + - $ref: "#/components/schemas/Foo" + - type: object + properties: + oneOfInlineBar: + type: string + SchemaTest: + allOf: + - type: object + properties: + schemaTestInline1Foo: + type: string + schemaTestInline1Ref: + type: array + items: + $ref: '#/components/schemas/Bar' + - $ref: '#/components/schemas/Foo' diff --git a/src/test/resources/3_0_0/composedFlatten/allof_ref_inline.yaml b/src/test/resources/3_0_0/composedFlatten/allof_ref_inline.yaml new file mode 100644 index 0000000000..6e44d17b99 --- /dev/null +++ b/src/test/resources/3_0_0/composedFlatten/allof_ref_inline.yaml @@ -0,0 +1,48 @@ +openapi: 3.0.2 +info: + title: CC-20717 test - OAS3 + version: 1.0.0 +paths: + /something: + get: + responses: + 200: + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + properties: + foo: + type: string + Bar: + type: object + properties: + foo1: + description: An instance of Foo + allOf: + - $ref: '#/components/schemas/Foo' + foo2: + $ref: '#/components/schemas/Foo' + OneOfTest: + oneOf: + - $ref: "#/components/schemas/Foo" + - type: object + properties: + foo: + type: string + SchemaTest: + allOf: + - $ref: '#/components/schemas/OneOfTest' + - type: object + properties: + schemaTestInline1Foo: + type: string + schemaTestInline1Ref: + type: array + items: + $ref: '#/components/schemas/Bar' diff --git a/src/test/resources/3_0_0/composedFlatten/allof_ref_inline_inline.yaml b/src/test/resources/3_0_0/composedFlatten/allof_ref_inline_inline.yaml new file mode 100644 index 0000000000..1691ae611d --- /dev/null +++ b/src/test/resources/3_0_0/composedFlatten/allof_ref_inline_inline.yaml @@ -0,0 +1,56 @@ +openapi: 3.0.2 +info: + title: CC-20717 test - OAS3 + version: 1.0.0 +paths: + /something: + get: + responses: + 200: + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + properties: + foo: + type: string + Bar: + type: object + properties: + foo1: + description: An instance of Foo + allOf: + - $ref: '#/components/schemas/Foo' + foo2: + $ref: '#/components/schemas/Foo' + OneOfTest: + oneOf: + - $ref: "#/components/schemas/Foo" + - type: object + properties: + foo: + type: string + SchemaTest: + allOf: + - $ref: '#/components/schemas/OneOfTest' + - type: object + properties: + schemaTestInline1Foo: + type: string + schemaTestInline1Ref: + type: array + items: + $ref: '#/components/schemas/Bar' + - type: object + properties: + schemaTestInline2Foo: + type: string + schemaTestInline2Ref: + type: array + items: + $ref: '#/components/schemas/Bar' diff --git a/src/test/resources/3_0_0/composedFlatten/allof_ref_ref.yaml b/src/test/resources/3_0_0/composedFlatten/allof_ref_ref.yaml new file mode 100644 index 0000000000..3c0ae2d7d4 --- /dev/null +++ b/src/test/resources/3_0_0/composedFlatten/allof_ref_ref.yaml @@ -0,0 +1,41 @@ +openapi: 3.0.2 +info: + title: CC-20717 test - OAS3 + version: 1.0.0 +paths: + /something: + get: + responses: + 200: + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + properties: + foo: + type: string + Bar: + type: object + properties: + foo1: + description: An instance of Foo + allOf: + - $ref: '#/components/schemas/Foo' + foo2: + $ref: '#/components/schemas/Foo' + OneOfTest: + oneOf: + - $ref: "#/components/schemas/Foo" + - type: object + properties: + foo: + type: string + SchemaTest: + allOf: + - $ref: '#/components/schemas/OneOfTest' + - $ref: '#/components/schemas/Bar' diff --git a/src/test/resources/3_0_0/composedFlatten/allof_ref_ref_inverted.yaml b/src/test/resources/3_0_0/composedFlatten/allof_ref_ref_inverted.yaml new file mode 100644 index 0000000000..b955ca2ebc --- /dev/null +++ b/src/test/resources/3_0_0/composedFlatten/allof_ref_ref_inverted.yaml @@ -0,0 +1,41 @@ +openapi: 3.0.2 +info: + title: CC-20717 test - OAS3 + version: 1.0.0 +paths: + /something: + get: + responses: + 200: + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/Bar' +components: + schemas: + Foo: + type: object + properties: + foo: + type: string + Bar: + type: object + properties: + foo1: + description: An instance of Foo + allOf: + - $ref: '#/components/schemas/Foo' + foo2: + $ref: '#/components/schemas/Foo' + OneOfTest: + oneOf: + - $ref: "#/components/schemas/Foo" + - type: object + properties: + foo: + type: string + SchemaTest: + allOf: + - $ref: '#/components/schemas/Bar' + - $ref: '#/components/schemas/OneOfTest' diff --git a/src/test/resources/3_0_0/composed_schemas.yaml b/src/test/resources/3_0_0/composed_schemas.yaml new file mode 100644 index 0000000000..8e17aa4068 --- /dev/null +++ b/src/test/resources/3_0_0/composed_schemas.yaml @@ -0,0 +1,176 @@ +openapi: 3.0.0 +servers: [] +info: + description: This is a simple API + version: "1.0.0" + title: Simple Inventory API + contact: + email: you@your-company.com + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: admins + description: Secured Admin-only calls + - name: developers + description: Operations available to regular developers +paths: + /inventory: + get: + tags: + - developers + summary: searches inventory + operationId: searchInventory + description: | + By passing in the appropriate options, you can search for + available inventory in the system + parameters: + - in: query + name: searchString + description: pass an optional search string for looking up inventory + required: false + schema: + type: string + - in: query + name: skip + description: number of records to skip for pagination + schema: + type: integer + format: int32 + minimum: 0 + - in: query + name: limit + description: maximum number of records to return + schema: + type: integer + format: int32 + minimum: 0 + maximum: 50 + responses: + '200': + description: search results matching criteria + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PartMaster' + '400': + description: bad input parameter + +components: + schemas: + PartOne: + properties: + name: + type: string + description: A test description + PartTwo: + properties: + id: + type: string + PartThree: + properties: + otherId: + type: string + PartFour: + properties: + otherIdPart: + type: string + PartMaster: + properties: + destination: + oneOf: + - $ref: '#/components/schemas/PartOne' + - $ref: '#/components/schemas/PartTwo' + origin: + oneOf: + - $ref: '#/components/schemas/PartThree' + - $ref: '#/components/schemas/PartFour' + + Pet: + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + name: + type: string + example: doggie + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + part: + type: array + items: + oneOf: + - $ref: "#/components/schemas/Dog" + - $ref: "#/components/schemas/Cat" + xml: + name: Pet + + Pup: + oneOf: + - $ref: "#/components/schemas/Dog" + - $ref: "#/components/schemas/Cat" + properties: + id: + type: integer + format: int64 + AllPetsResponse: + type: array + items: + oneOf: + - $ref: "#/components/schemas/Dog" + - $ref: "#/components/schemas/Cat" + discriminator: + propertyName: pet_type + + Dog: + allOf: + - $ref: '#/components/schemas/Pet' + - type: object + properties: + bark: + type: boolean + breed: + type: string + enum: [Dingo, Husky, Retriever, Shepherd] + Cat: + allOf: + - $ref: '#/components/schemas/Pet' + - type: object + properties: + hunts: + type: boolean + age: + type: integer + + House: + type: object + properties: + pets: + items: + oneOf: + - "$ref": "#/components/schemas/Dog" + - "$ref": "#/components/schemas/Cat" + type: array + + Client: + type: object + properties: + name: + type: string + + List: + type: object + properties: + name: + type: string \ No newline at end of file diff --git a/src/test/resources/3_0_0/discriminator_order_schemas.yaml b/src/test/resources/3_0_0/discriminator_order_schemas.yaml new file mode 100644 index 0000000000..7e5f8eefb5 --- /dev/null +++ b/src/test/resources/3_0_0/discriminator_order_schemas.yaml @@ -0,0 +1,58 @@ +openapi: 3.0.2 +info: + title: OAI Specification example for NPE + version: 1.0.0 +paths: + /sampleObjectResponse: + get: + responses: + '200': + description: desc + content: + application/json: + schema: + $ref: '#/components/schemas/A_Base' +components: + schemas: + + A_Base: + type: object + properties: + relations: + type: string + + B_Sub_Base: + allOf: + - "$ref": '#/components/schemas/A_Base' + type: object + required: + - type + properties: + type: + type: string + discriminator: + propertyName: type + mapping: + aPersonalProperty: '#/components/schemas/APersonalProperty' + + C_Sub_Sub_Base: + allOf: + - "$ref": '#/components/schemas/B_Sub_Base' + - required: + - type + type: object + properties: + type: + type: string + discriminator: + propertyName: type + mapping: + motorVehicle: '#/components/schemas/D_Sub_Sub_Sub_Base' + + D_Sub_Sub_Sub_Base: + allOf: + - "$ref": '#/components/schemas/C_Sub_Sub_Base' + - type: object + properties: + bark: + type: string diff --git a/src/test/resources/3_0_0/model_named_file.yaml b/src/test/resources/3_0_0/model_named_file.yaml new file mode 100644 index 0000000000..de35d6d78f --- /dev/null +++ b/src/test/resources/3_0_0/model_named_file.yaml @@ -0,0 +1,62 @@ +openapi: 3.0.0 +servers: + - description: test definition + url: / +info: + description: This is a simple API + version: "1.0.0" + title: Simple Inventory API + +paths: + /inventory: + post: + tags: + - Inventory + summary: adds an inventory item + operationId: addInventory + description: Adds an item to the system + responses: + '201': + description: item created + '400': + description: 'invalid input, object invalid' + '409': + description: an existing item already exists + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Setting' + description: Inventory item to add +components: + schemas: + Archive: + type: string + format: binary + + File: + description: File. + type: object + properties: + prop1: + type: string + + Date: + type: object + properties: + place: + type: string + + Setting: + description: Setting. + properties: + file: + $ref: '#/components/schemas/File' + date: + $ref: '#/components/schemas/Date' + document: + type: string + format: binary + time: + type: string + format: date-time diff --git a/src/test/resources/3_0_0/parameterOrder.yaml b/src/test/resources/3_0_0/parameterOrder.yaml new file mode 100644 index 0000000000..d27265a188 --- /dev/null +++ b/src/test/resources/3_0_0/parameterOrder.yaml @@ -0,0 +1,309 @@ +openapi: 3.0.3 +info: + title: Title + version: "2.0.0" + description: test + contact: + name: test contact + url: 'http://www.contact.com' +security: + - OAuth2: [] +paths: + '/admin/texts/{id}': + parameters: + - name: id + in: path + description: description + required: true + schema: + type: integer + format: int64 + put: + summary: Update + description: description + operationId: updateTest + responses: + 200: + description: Successfully updated + content: + application/json: + schema: + $ref: '#/components/schemas/LocalizedText' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LocalizedText' + description: Localized Text object containing updated data. + required: true + x-ecc-validate: + validated: [Update] +servers: + - url: 'http://localhost:8082/v1' + - url: 'https://localhost:8082/v1' +components: + schemas: + Paging: + type: object + description: Paging data. + required: + - totalItems + - totalPages + - pageSize + - currentPage + properties: + totalItems: + type: integer + totalPages: + type: integer + pageSize: + type: integer + currentPage: + type: integer + ObjectAsMap: + type: object + additionalProperties: + type: object + description: > + Localized text data to be updated. + + Tree is represented by `Map` where String is field name + and object is field value. + BaseAudit: + type: object + description: Base audit fields + properties: + created: + type: string + format: date-time + description: Indicates time of creation. + modified: + type: string + format: date-time + description: Indicates time of last modification. + createdBy: + type: string + description: Identification of creator. + modifiedBy: + type: string + description: Identification of modifier. + BaseRecordVersion: + type: object + description: BaseRecordVersion + properties: + recordVersion: + type: integer + x-ecc-validate: + check-null: [Create] + check-not-null: [Update] + check-required: [Patch, BulkPatch] + description: 'Timestamp from last update, not to be updated directly' + format: int64 + PagedLocalizedTexts: + description: Paged LocalizedText. + allOf: + - $ref: '#/components/schemas/Paging' + - properties: + data: + type: array + items: + $ref: '#/components/schemas/LocalizedText' + BulkDelete: + type: object + required: + - id + description: List of objects ids to be deleted with bulk operation + properties: + id: + type: string + BulkDeleteList: + type: object + description: List of Ids of object to be removed + properties: + bulkDeleteList: + type: array + items: + $ref: '#/components/schemas/BulkDelete' + LocalizedText: + type: object + required: + - module + - locale + - key + - defaultValue + allOf: + - $ref: '#/components/schemas/BaseRecordVersion' + - $ref: '#/components/schemas/BaseAudit' + - properties: + id: + type: integer + format: int64 + x-ecc-validate: + check-null: [Create, Update] + check-not-valid: [Patch] + description: ID of the Localized text + example: 1 + module: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-not-valid: [Patch] + description: Module name to be used for key value to be loaded + example: COMMONS + locale: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-not-valid: [Patch] + description: Localization to be retrieved + example: en + key: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-not-valid: [Patch] + description: Localized text key value normally used for retrieval + example: LocalizedTextToBeRetrieved + defaultValue: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-valid: [Patch] + description: Default Text to be used + example: Default Localized Text + customValue: + type: string + x-ecc-validate: + check-valid: [Create, Update, Patch] + description: Alternative Text to be used + example: Alternative Localized Text + Failures: + type: object + description: 'Contains list of failures, which had occured.' + properties: + failures: + type: array + items: + $ref: '#/components/schemas/Failure' + Failure: + type: object + description: >- + Response object containing further information about reason, why request + had failed + required: + - code + - module + - happened + - detail + properties: + code: + type: integer + format: int32 + description: Internal code of the error + example: 100 + default: 0 + key: + type: string + module: + type: string + description: 'Internal name of the module, when error happened' + example: localized-text + happened: + type: string + format: date-time + description: 'Timestamp, when the error happened' + example: '2018-06-05T12:58:44.953+0000' + detail: + type: string + description: Further text description about error occured. + example: 'LocalizedTextDto recordVersion: cannot be null or missing' + localizedDescription: + type: string + description: Localized description for the problem. + contextData: + type: object + description: >- + List of key-value pairs with additional info about the error (for + example input value which caused the error) + additionalProperties: + type: string + stackTrace: + type: array + description: Optional stack trace available for development purposes only. + items: + type: string + ResponseEntity: + type: object + properties: + body: + type: object + statusCode: + type: string + enum: + - '100' + - '101' + - '102' + - '103' + - '200' + - '201' + - '202' + - '203' + - '204' + - '205' + - '206' + - '207' + - '208' + - '226' + - '300' + - '301' + - '302' + - '303' + - '304' + - '305' + - '307' + - '308' + - '400' + - '401' + - '402' + - '403' + - '404' + - '405' + - '406' + - '407' + - '408' + - '409' + - '410' + - '411' + - '412' + - '413' + - '414' + - '415' + - '416' + - '417' + - '418' + - '419' + - '420' + - '421' + - '422' + - '423' + - '424' + - '426' + - '428' + - '429' + - '431' + - '451' + - '500' + - '501' + - '502' + - '503' + - '504' + - '505' + - '506' + - '507' + - '508' + - '509' + - '510' + - '511' + statusCodeValue: + type: integer + format: int32 \ No newline at end of file diff --git a/src/test/resources/3_0_0/parameterValidation.yaml b/src/test/resources/3_0_0/parameterValidation.yaml new file mode 100644 index 0000000000..1093b5b729 --- /dev/null +++ b/src/test/resources/3_0_0/parameterValidation.yaml @@ -0,0 +1,140 @@ +openapi: 3.0.3 +info: + title: Title + version: "2.0.0" + description: test + contact: + name: test contact + url: 'http://www.contact.com' +security: + - OAuth2: [] +paths: + '/admin/texts/{id}': + parameters: + - name: x-header + in: header + description: header description + required: true + schema: + type: string + pattern: "[0-9]+" + - name: name + in: query + description: query description + schema: + type: string + - name: id + in: path + description: path description + required: true + schema: + type: integer + format: int64 + put: + summary: Update + description: description + operationId: updateTest + responses: + 200: + description: Successfully updated + content: + application/json: + schema: + $ref: '#/components/schemas/LocalizedText' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LocalizedText' + description: Localized Text object. + required: true + x-ecc-validate: + validated: [Update] +servers: + - url: 'http://localhost:8082/v1' + - url: 'https://localhost:8082/v1' +components: + schemas: + BaseAudit: + type: object + description: Base audit fields + properties: + created: + type: string + format: date-time + description: Indicates time of creation. + modified: + type: string + format: date-time + description: Indicates time of last modification. + createdBy: + type: string + description: Identification of creator. + modifiedBy: + type: string + description: Identification of modifier. + BaseRecordVersion: + type: object + description: BaseRecordVersion + properties: + recordVersion: + type: integer + x-ecc-validate: + check-null: [Create] + check-not-null: [Update] + check-required: [Patch, BulkPatch] + description: 'Timestamp from last update, not to be updated directly' + format: int64 + LocalizedText: + type: object + required: + - module + - locale + - key + - defaultValue + allOf: + - $ref: '#/components/schemas/BaseRecordVersion' + - $ref: '#/components/schemas/BaseAudit' + - properties: + id: + type: integer + format: int64 + x-ecc-validate: + check-null: [Create, Update] + check-not-valid: [Patch] + description: ID of the Localized text + example: 1 + module: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-not-valid: [Patch] + description: Module name to be used for key value to be loaded + example: COMMONS + locale: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-not-valid: [Patch] + description: Localization to be retrieved + example: en + key: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-not-valid: [Patch] + description: Localized text key value normally used for retrieval + example: LocalizedTextToBeRetrieved + defaultValue: + type: string + x-ecc-validate: + check-not-empty: [Create, Update] + check-valid: [Patch] + description: Default Text to be used + example: Default Localized Text + customValue: + type: string + x-ecc-validate: + check-valid: [Create, Update, Patch] + description: Alternative Text to be used + example: Alternative Localized Text \ No newline at end of file diff --git a/src/test/resources/3_0_0/petstore-vertx.yaml b/src/test/resources/3_0_0/petstore-vertx.yaml new file mode 100644 index 0000000000..73ffa78fbc --- /dev/null +++ b/src/test/resources/3_0_0/petstore-vertx.yaml @@ -0,0 +1,798 @@ +openapi: 3.0.1 +servers: + - url: 'http://localhost:8080' + - url: 'https://localhost:8080' +info: + description: | + This is a sample Petstore server. You can find + out more about Swagger at + [http://swagger.io](http://swagger.io) or on + [irc.freenode.net, #swagger](http://swagger.io/irc/). + version: "1.0.0" + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet: + x-vertx-event-bus: "pet.address" + post: + tags: + - pet + summary: Add a new pet to the store + operationId: addPet + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + x-vertx-event-bus: "myPet.address" + put: + tags: + - pet + summary: Update an existing pet + operationId: updatePet + responses: + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + x-vertx-event-bus: + method: "myUpdatePet" + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + x-vertx-event-bus: "myFindPetsByStatus.address" + /pet/findByTags: + x-vertx-event-bus: + address: "myFindByTags.address" + get: + tags: + - pet + x-vertx-event-bus: "overrided" + summary: Finds Pets by tags + description: >- + Muliple tags can be provided with comma separated strings. Use\ \ tag1, + tag2, tag3 for testing. + operationId: findPetsByTags + parameters: + - name: tags + in: query + description: Tags to filter by + required: true + explode: true + schema: + type: array + items: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid tag value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + deprecated: true + '/pet/{petId}': + x-vertx-event-bus: + address: "myPetId.address" + get: + tags: + - pet + x-vertx-event-bus: + address: "myGetPetById.address" + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + post: + tags: + - pet + x-vertx-event-bus: "overrided" + summary: Updates a pet in the store with form data + operationId: updatePetWithForm + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: integer + format: int64 + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + name: + description: Updated name of the pet + type: string + status: + description: Updated status of the pet + type: string + delete: + tags: + - pet + x-vertx-event-bus: "overrided" + summary: Deletes a pet + operationId: deletePet + parameters: + - name: api_key + in: header + required: false + schema: + type: string + - name: petId + in: path + description: Pet id to delete + required: true + schema: + type: integer + format: int64 + responses: + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + + /pet/feed/{petId}: + post: + tags: + - pet + x-vertx-event-bus: "myFeedPet.address" + summary: Find pet by ID + description: schedule pet feeding + operationId: feedPet + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + - name: petType + in: query + description: type of food + required: true + schema: + type: string + - name: status + in: query + description: status + required: true + schema: + type: string + - name: sessionId + in: cookie + description: session id + required: true + schema: + type: string + - name: token + in: header + description: status + required: true + schema: + type: string + requestBody: + description: Pet object that needs to be added to the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + 200: + description: successful operation + + '/pet/{petId}/uploadImage': + post: + tags: + - pet + x-vertx-event-bus: "myUploadFile.address" + summary: uploads an image + operationId: uploadFile + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + application/octet-stream: + schema: + type: string + format: binary + /store/inventory: + get: + tags: + - store + x-vertx-event-bus: "getInventory.address" + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + x-vertx-event-bus: "placeOrder.address" + summary: Place an order for a pet + operationId: placeOrder + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + application/xml: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid Order + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + description: order placed for purchasing the pet + required: true + '/store/order/{orderId}': + get: + tags: + - store + x-vertx-event-bus: "getOrderById.address" + summary: Find purchase order by ID + description: >- + For valid response try integer IDs with value >= 1 and <= 10.\ \ Other + values will generated exceptions + operationId: getOrderById + parameters: + - name: orderId + in: path + description: ID of pet that needs to be fetched + required: true + schema: + type: integer + format: int64 + minimum: 1 + maximum: 10 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + application/xml: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + x-vertx-event-bus: "deleteOrder.address" + summary: Delete purchase order by ID + description: >- + For valid response try integer IDs with positive integer value.\ \ + Negative or non-integer values will generate API errors + operationId: deleteOrder + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + schema: + type: integer + format: int64 + minimum: 1 + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + responses: + default: + description: successful operation + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Created user object + required: true + /user/createWithArray: + post: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Creates list of users with given input array + operationId: createUsersWithArrayInput + responses: + default: + description: successful operation + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/createWithList: + post: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Creates list of users with given input array + operationId: createUsersWithListInput + responses: + default: + description: successful operation + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/login: + get: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Logs user into the system + operationId: loginUser + parameters: + - name: username + in: query + description: The user name for login + required: true + schema: + type: string + - name: password + in: query + description: The password for login in clear text + required: true + schema: + type: string + responses: + '200': + description: successful operation + headers: + X-Rate-Limit: + description: calls per hour allowed by the user + schema: + type: integer + format: int32 + X-Expires-After: + description: date in UTC when token expires + schema: + type: string + format: date-time + content: + application/json: + schema: + type: string + application/xml: + schema: + type: string + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Logs out current logged in user session + operationId: logoutUser + responses: + default: + description: successful operation + '/user/{username}': + get: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Get user by user name + operationId: getUserByName + parameters: + - name: username + in: path + description: The name that needs to be fetched. Use user1 for testing. + required: true + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/User' + application/xml: + schema: + $ref: '#/components/schemas/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + parameters: + - name: username + in: path + description: name that need to be updated + required: true + schema: + type: string + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Updated user object + required: true + delete: + tags: + - user + x-vertx-event-bus: "user.address" + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found + /test: + get: + security: + - bearer: [] + operationId: testMethod + x-vertx-event-bus: "test.address" + responses: + 200: + description: peticion realizada con exito + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Test' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + schemas: + Order: + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + subcategories: + type: array + items: + $ref: '#/components/schemas/Category' + example: + id: 100 + name: Mammal + subcategories: + - id: 110 + name: Yinotheria + - id: 120 + name: Theriiformes + xml: + name: Category + User: + type: object + properties: + id: + type: integer + format: int64 + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + category: + $ref: '#/components/schemas/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: Pet + ApiResponse: + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string + Test: + type: string + example: "" + requestBodies: + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + description: Pet object that needs to be added to the store + required: true + UserArray: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + description: List of user object + required: true + securitySchemes: + bearer: + type: http + scheme: bearer + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header diff --git a/src/test/resources/3_0_0/petstore.yaml b/src/test/resources/3_0_0/petstore.yaml index 765afd90a7..18f9b9371d 100644 --- a/src/test/resources/3_0_0/petstore.yaml +++ b/src/test/resources/3_0_0/petstore.yaml @@ -233,6 +233,60 @@ paths: - petstore_auth: - 'write:pets' - 'read:pets' + + /pet/feed/{petId}: + post: + tags: + - pet + summary: Find pet by ID + description: schedule pet feeding + operationId: feedPet + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + - name: petType + in: query + description: type of food + required: true + schema: + type: string + - name: status + in: query + description: status + required: true + schema: + type: string + - name: sessionId + in: cookie + description: session id + required: true + schema: + type: string + - name: token + in: header + description: status + required: true + schema: + type: string + requestBody: + description: Pet object that needs to be added to the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + 200: + description: successful operation + '/pet/{petId}/uploadImage': post: tags: @@ -576,6 +630,18 @@ components: format: int64 name: type: string + subcategories: + type: array + items: + $ref: '#/components/schemas/Category' + example: + - id: 100 + name: Mammal + subcategories: + - id: 110 + name: Yinotheria + - id: 120 + name: Theriiformes xml: name: Category User: diff --git a/src/test/resources/3_0_0/polymorphicSchema.yaml b/src/test/resources/3_0_0/polymorphicSchema.yaml new file mode 100644 index 0000000000..b5a284bc9a --- /dev/null +++ b/src/test/resources/3_0_0/polymorphicSchema.yaml @@ -0,0 +1,63 @@ +openapi: 3.0.3 +info: + description: This is a simple API + version: "1.0.0" + title: Simple Inventory API +servers: + - description: test definition + url: / +paths: + /provision: + get: + tags: + - provision + summary: inheritanceTest + operationId: provision + description: inheritanceTest + responses: + 200: + description: default response + content: + application/json: + schema: + $ref: '#/components/schemas/PolymorphicResponse' + +components: + schemas: + PolymorphicResponse: + type: object + required: + - type + properties: + type: + type: string + enum: + - Success + - Error + description: the descriminator + discriminator: + propertyName: type + Success: + allOf: + - $ref: '#/components/schemas/PolymorphicResponse' + - type: object + required: + - target + properties: + target: + type: string + description: some target value + dialogId: + type: string + format: uuid + description: some dialogId + Error: + allOf: + - $ref: '#/components/schemas/PolymorphicResponse' + - type: object + required: + - message + properties: + message: + type: string + description: the message describing the error \ No newline at end of file diff --git a/src/test/resources/3_0_0/response_without_content.yaml b/src/test/resources/3_0_0/response_without_content.yaml new file mode 100644 index 0000000000..fe79c5890a --- /dev/null +++ b/src/test/resources/3_0_0/response_without_content.yaml @@ -0,0 +1,33 @@ +openapi: 3.0.0 +servers: + - description: test definition + url: / +info: + description: This is a simple API + version: "1.0.0" + title: Simple API + +paths: + /pets: + get: + tags: + - Pet + summary: get all pets + operationId: getAllPets + description: get all existing pets + responses: + 200: + description: 'Return a list of pets' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + 400: + description: 'Error' + +components: + schemas: + Pet: + type: 'object' \ No newline at end of file