[Kotlin] Add name, parameter mapping support (#16193)

* add name, parameter mapping support to abstract kotlin

* remove files
This commit is contained in:
William Cheng 2023-07-28 09:42:08 +08:00 committed by GitHub
parent 86cf4f1eb1
commit 184dfd2edd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1370 additions and 0 deletions

View File

@ -59,6 +59,7 @@ jobs:
- samples/client/petstore/kotlin-jvm-spring-2-webclient
- samples/client/petstore/kotlin-jvm-spring-3-webclient
- samples/client/petstore/kotlin-spring-cloud
- samples/client/petstore/kotlin-name-parameter-mappings
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3

View File

@ -0,0 +1,14 @@
generatorName: kotlin
outputDir: samples/client/petstore/kotlin-name-parameter-mappings
inputSpec: modules/openapi-generator/src/test/resources/3_0/name-parameter-mappings.yaml
templateDir: modules/openapi-generator/src/main/resources/kotlin-client
nameMappings:
_type: underscoreType
type_: typeWithUnderscore
http_debug_operation: httpDebugOperation
parameterNameMappings:
_type: underscoreType
type_: typeWithUnderscore
http_debug_operation: httpDebugOperation
additionalProperties:
artifactId: kotlin-petstore-client

View File

@ -937,6 +937,11 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
@Override
public String toParamName(String name) {
// obtain the name from parameterNameMapping directly if provided
if (parameterNameMapping.containsKey(name)) {
return parameterNameMapping.get(name);
}
// to avoid conflicts with 'callback' parameter for async call
if ("callback".equals(name)) {
return "paramCallback";
@ -948,6 +953,11 @@ public abstract class AbstractKotlinCodegen extends DefaultCodegen implements Co
@Override
public String toVarName(String name) {
// obtain the name from nameMapping directly if provided
if (nameMapping.containsKey(name)) {
return nameMapping.get(name);
}
name = toVariableName(name);
if (propertyAdditionalKeywords.contains(name)) {
return camelize("property_" + name, LOWERCASE_FIRST_LETTER);

View File

@ -0,0 +1,56 @@
openapi: 3.0.0
info:
description: To test name, parameter mapping options
version: 1.0.0
title: Dummy
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
paths:
/fake/parameter-name-mapping:
get:
tags:
- fake
summary: parameter name mapping test
operationId: getParameterNameMapping
parameters:
- name: _type
in: header
description: _type
required: true
schema:
type: integer
format: int64
- name: type
in: query
description: type
required: true
schema:
type: string
- name: type_
in: header
description: type_
required: true
schema:
type: string
- name: http_debug_option
in: query
description: http debug option (to test parameter naming option)
required: true
schema:
type: string
responses:
200:
description: OK
components:
schemas:
PropertyNameMapping:
properties:
http_debug_operation:
type: string
_type:
type: string
type:
type: string
type_:
type: string

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,28 @@
README.md
build.gradle
docs/FakeApi.md
docs/PropertyNameMapping.md
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
gradlew
gradlew.bat
settings.gradle
src/main/kotlin/org/openapitools/client/apis/FakeApi.kt
src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
src/main/kotlin/org/openapitools/client/infrastructure/ApiResponse.kt
src/main/kotlin/org/openapitools/client/infrastructure/BigDecimalAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/BigIntegerAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/ByteArrayAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/Errors.kt
src/main/kotlin/org/openapitools/client/infrastructure/LocalDateAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/LocalDateTimeAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/OffsetDateTimeAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
src/main/kotlin/org/openapitools/client/infrastructure/ResponseExtensions.kt
src/main/kotlin/org/openapitools/client/infrastructure/Serializer.kt
src/main/kotlin/org/openapitools/client/infrastructure/URIAdapter.kt
src/main/kotlin/org/openapitools/client/infrastructure/UUIDAdapter.kt
src/main/kotlin/org/openapitools/client/models/PropertyNameMapping.kt

View File

@ -0,0 +1 @@
7.0.0-SNAPSHOT

View File

@ -0,0 +1,60 @@
# org.openapitools.client - Kotlin client library for Dummy
To test name, parameter mapping options
## Overview
This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [openapi-spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate an API client.
- API version: 1.0.0
- Package version:
- Build package: org.openapitools.codegen.languages.KotlinClientCodegen
## Requires
* Kotlin 1.7.21
* Gradle 7.5
## 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 OpenAPI definitions.
* Implementation of ApiClient is intended to reduce method counts, specifically to benefit Android targets.
<a id="documentation-for-api-endpoints"></a>
## Documentation for API Endpoints
All URIs are relative to *http://localhost*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*FakeApi* | [**getParameterNameMapping**](docs/FakeApi.md#getparameternamemapping) | **GET** /fake/parameter-name-mapping | parameter name mapping test
<a id="documentation-for-models"></a>
## Documentation for Models
- [org.openapitools.client.models.PropertyNameMapping](docs/PropertyNameMapping.md)
<a id="documentation-for-authorization"></a>
## Documentation for Authorization
Endpoints do not require authorization.

View File

@ -0,0 +1,38 @@
group 'org.openapitools'
version '1.0.0'
wrapper {
gradleVersion = '7.5'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
buildscript {
ext.kotlin_version = '1.7.21'
repositories {
maven { url "https://repo1.maven.org/maven2" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
repositories {
maven { url "https://repo1.maven.org/maven2" }
}
test {
useJUnitPlatform()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
implementation "com.squareup.okhttp3:okhttp:4.10.0"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
}

View File

@ -0,0 +1,59 @@
# FakeApi
All URIs are relative to *http://localhost*
Method | HTTP request | Description
------------- | ------------- | -------------
[**getParameterNameMapping**](FakeApi.md#getParameterNameMapping) | **GET** /fake/parameter-name-mapping | parameter name mapping test
<a id="getParameterNameMapping"></a>
# **getParameterNameMapping**
> getParameterNameMapping(underscoreType, type, typeWithUnderscore, httpDebugOption)
parameter name mapping test
### Example
```kotlin
// Import classes:
//import org.openapitools.client.infrastructure.*
//import org.openapitools.client.models.*
val apiInstance = FakeApi()
val underscoreType : kotlin.Long = 789 // kotlin.Long | _type
val type : kotlin.String = type_example // kotlin.String | type
val typeWithUnderscore : kotlin.String = typeWithUnderscore_example // kotlin.String | type_
val httpDebugOption : kotlin.String = httpDebugOption_example // kotlin.String | http debug option (to test parameter naming option)
try {
apiInstance.getParameterNameMapping(underscoreType, type, typeWithUnderscore, httpDebugOption)
} catch (e: ClientException) {
println("4xx response calling FakeApi#getParameterNameMapping")
e.printStackTrace()
} catch (e: ServerException) {
println("5xx response calling FakeApi#getParameterNameMapping")
e.printStackTrace()
}
```
### Parameters
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**underscoreType** | **kotlin.Long**| _type |
**type** | **kotlin.String**| type |
**typeWithUnderscore** | **kotlin.String**| type_ |
**httpDebugOption** | **kotlin.String**| http debug option (to test parameter naming option) |
### Return type
null (empty response body)
### Authorization
No authorization required
### HTTP request headers
- **Content-Type**: Not defined
- **Accept**: Not defined

View File

@ -0,0 +1,13 @@
# PropertyNameMapping
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**httpDebugOperation** | **kotlin.String** | | [optional]
**underscoreType** | **kotlin.String** | | [optional]
**type** | **kotlin.String** | | [optional]
**typeWithUnderscore** | **kotlin.String** | | [optional]

View File

@ -0,0 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -0,0 +1,245 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# 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
#
# 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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
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" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@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
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@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="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
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 execute
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
: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 %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 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!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,2 @@
rootProject.name = 'kotlin-petstore-client'

View File

@ -0,0 +1,133 @@
/**
*
* Please note:
* This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* Do not edit this file manually.
*
*/
@file:Suppress(
"ArrayInDataClass",
"EnumEntryName",
"RemoveRedundantQualifierName",
"UnusedImport"
)
package org.openapitools.client.apis
import java.io.IOException
import okhttp3.OkHttpClient
import okhttp3.HttpUrl
import com.squareup.moshi.Json
import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ApiResponse
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.PartConfig
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class FakeApi(basePath: kotlin.String = defaultBasePath, client: OkHttpClient = ApiClient.defaultClient) : ApiClient(basePath, client) {
companion object {
@JvmStatic
val defaultBasePath: String by lazy {
System.getProperties().getProperty(ApiClient.baseUrlKey, "http://localhost")
}
}
/**
* parameter name mapping test
*
* @param underscoreType _type
* @param type type
* @param typeWithUnderscore type_
* @param httpDebugOption http debug option (to test parameter naming option)
* @return void
* @throws IllegalStateException If the request is not correctly configured
* @throws IOException Rethrows the OkHttp execute method exception
* @throws UnsupportedOperationException If the API returns an informational or redirection response
* @throws ClientException If the API returns a client error response
* @throws ServerException If the API returns a server error response
*/
@Throws(IllegalStateException::class, IOException::class, UnsupportedOperationException::class, ClientException::class, ServerException::class)
fun getParameterNameMapping(underscoreType: kotlin.Long, type: kotlin.String, typeWithUnderscore: kotlin.String, httpDebugOption: kotlin.String) : Unit {
val localVarResponse = getParameterNameMappingWithHttpInfo(underscoreType = underscoreType, type = type, typeWithUnderscore = typeWithUnderscore, httpDebugOption = httpDebugOption)
return when (localVarResponse.responseType) {
ResponseType.Success -> Unit
ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
ResponseType.ClientError -> {
val localVarError = localVarResponse as ClientError<*>
throw ClientException("Client error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
}
ResponseType.ServerError -> {
val localVarError = localVarResponse as ServerError<*>
throw ServerException("Server error : ${localVarError.statusCode} ${localVarError.message.orEmpty()}", localVarError.statusCode, localVarResponse)
}
}
}
/**
* parameter name mapping test
*
* @param underscoreType _type
* @param type type
* @param typeWithUnderscore type_
* @param httpDebugOption http debug option (to test parameter naming option)
* @return ApiResponse<Unit?>
* @throws IllegalStateException If the request is not correctly configured
* @throws IOException Rethrows the OkHttp execute method exception
*/
@Throws(IllegalStateException::class, IOException::class)
fun getParameterNameMappingWithHttpInfo(underscoreType: kotlin.Long, type: kotlin.String, typeWithUnderscore: kotlin.String, httpDebugOption: kotlin.String) : ApiResponse<Unit?> {
val localVariableConfig = getParameterNameMappingRequestConfig(underscoreType = underscoreType, type = type, typeWithUnderscore = typeWithUnderscore, httpDebugOption = httpDebugOption)
return request<Unit, Unit>(
localVariableConfig
)
}
/**
* To obtain the request config of the operation getParameterNameMapping
*
* @param underscoreType _type
* @param type type
* @param typeWithUnderscore type_
* @param httpDebugOption http debug option (to test parameter naming option)
* @return RequestConfig
*/
fun getParameterNameMappingRequestConfig(underscoreType: kotlin.Long, type: kotlin.String, typeWithUnderscore: kotlin.String, httpDebugOption: kotlin.String) : RequestConfig<Unit> {
val localVariableBody = null
val localVariableQuery: MultiValueMap = mutableMapOf<kotlin.String, kotlin.collections.List<kotlin.String>>()
.apply {
put("type", listOf(type.toString()))
put("http_debug_option", listOf(httpDebugOption.toString()))
}
val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
underscoreType.apply { localVariableHeaders["_type"] = this.toString() }
typeWithUnderscore.apply { localVariableHeaders["type_"] = this.toString() }
return RequestConfig(
method = RequestMethod.GET,
path = "/fake/parameter-name-mapping",
query = localVariableQuery,
headers = localVariableHeaders,
requiresAuthentication = false,
body = localVariableBody
)
}
private fun encodeURIComponent(uriComponent: kotlin.String): kotlin.String =
HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments[0]
}

View File

@ -0,0 +1,23 @@
package org.openapitools.client.infrastructure
typealias MultiValueMap = MutableMap<String,List<String>>
fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) {
"csv" -> ","
"tsv" -> "\t"
"pipe" -> "|"
"space" -> " "
else -> ""
}
val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" }
fun <T : Any?> toMultiValue(items: Array<T>, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter)
= toMultiValue(items.asIterable(), collectionFormat, map)
fun <T : Any?> toMultiValue(items: Iterable<T>, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List<String> {
return when(collectionFormat) {
"multi" -> items.map(map)
else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map))
}
}

View File

@ -0,0 +1,245 @@
package org.openapitools.client.infrastructure
import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.ResponseBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request
import okhttp3.Headers
import okhttp3.Headers.Companion.toHeaders
import okhttp3.MultipartBody
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
import okhttp3.internal.EMPTY_REQUEST
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
import java.net.URLConnection
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.OffsetDateTime
import java.time.OffsetTime
import java.util.Locale
import com.squareup.moshi.adapter
open class ApiClient(val baseUrl: String, val client: OkHttpClient = defaultClient) {
companion object {
protected const val ContentType = "Content-Type"
protected const val Accept = "Accept"
protected const val Authorization = "Authorization"
protected const val JsonMediaType = "application/json"
protected const val FormDataMediaType = "multipart/form-data"
protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded"
protected const val XmlMediaType = "application/xml"
val apiKey: MutableMap<String, String> = mutableMapOf()
val apiKeyPrefix: MutableMap<String, String> = mutableMapOf()
var username: String? = null
var password: String? = null
var accessToken: String? = null
const val baseUrlKey = "org.openapitools.client.baseUrl"
@JvmStatic
val defaultClient: OkHttpClient by lazy {
builder.build()
}
@JvmStatic
val builder: OkHttpClient.Builder = OkHttpClient.Builder()
}
/**
* Guess Content-Type header from the given file (defaults to "application/octet-stream").
*
* @param file The given file
* @return The guessed Content-Type
*/
protected fun guessContentTypeFromFile(file: File): String {
val contentType = URLConnection.guessContentTypeFromName(file.name)
return contentType ?: "application/octet-stream"
}
protected inline fun <reified T> requestBody(content: T, mediaType: String?): RequestBody =
when {
content is File -> content.asRequestBody((mediaType ?: guessContentTypeFromFile(content)).toMediaTypeOrNull())
mediaType == FormDataMediaType ->
MultipartBody.Builder()
.setType(MultipartBody.FORM)
.apply {
// content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) ->
if (part.body is File) {
val partHeaders = part.headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"")
val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull()
addPart(
partHeaders.toHeaders(),
part.body.asRequestBody(fileMediaType)
)
} else {
val partHeaders = part.headers.toMutableMap() +
("Content-Disposition" to "form-data; name=\"$name\"")
addPart(
partHeaders.toHeaders(),
parameterToString(part.body).toRequestBody(null)
)
}
}
}.build()
mediaType == FormUrlEncMediaType -> {
FormBody.Builder().apply {
// content's type *must* be Map<String, PartConfig<*>>
@Suppress("UNCHECKED_CAST")
(content as Map<String, PartConfig<*>>).forEach { (name, part) ->
add(name, parameterToString(part.body))
}
}.build()
}
mediaType == null || mediaType.startsWith("application/") && mediaType.endsWith("json") ->
if (content == null) {
EMPTY_REQUEST
} else {
Serializer.moshi.adapter(T::class.java).toJson(content)
.toRequestBody((mediaType ?: JsonMediaType).toMediaTypeOrNull())
}
mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.")
// TODO: this should be extended with other serializers
else -> throw UnsupportedOperationException("requestBody currently only supports JSON body and File body.")
}
@OptIn(ExperimentalStdlibApi::class)
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
if(body == null) {
return null
}
if (T::class.java == File::class.java) {
// return tempFile
// Attention: if you are developing an android app that supports API Level 25 and bellow, please check flag supportAndroidApiLevel25AndBelow in https://openapi-generator.tech/docs/generators/kotlin#config-options
val tempFile = java.nio.file.Files.createTempFile("tmp.org.openapitools.client", null).toFile()
tempFile.deleteOnExit()
body.byteStream().use { inputStream ->
tempFile.outputStream().use { tempFileOutputStream ->
inputStream.copyTo(tempFileOutputStream)
}
}
return tempFile as T
}
val bodyContent = body.string()
if (bodyContent.isEmpty()) {
return null
}
return when {
mediaType==null || (mediaType.startsWith("application/") && mediaType.endsWith("json")) ->
Serializer.moshi.adapter<T>().fromJson(bodyContent)
else -> throw UnsupportedOperationException("responseBody currently only supports JSON body.")
}
}
protected inline fun <reified I, reified T: Any?> request(requestConfig: RequestConfig<I>): ApiResponse<T?> {
val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.")
val url = httpUrl.newBuilder()
.addEncodedPathSegments(requestConfig.path.trimStart('/'))
.apply {
requestConfig.query.forEach { query ->
query.value.forEach { queryValue ->
addQueryParameter(query.key, queryValue)
}
}
}.build()
// take content-type/accept from spec or set to default (application/json) if not defined
if (requestConfig.body != null && requestConfig.headers[ContentType].isNullOrEmpty()) {
requestConfig.headers[ContentType] = JsonMediaType
}
if (requestConfig.headers[Accept].isNullOrEmpty()) {
requestConfig.headers[Accept] = JsonMediaType
}
val headers = requestConfig.headers
if (headers[Accept].isNullOrEmpty()) {
throw kotlin.IllegalStateException("Missing Accept header. This is required.")
}
val contentType = if (headers[ContentType] != null) {
// TODO: support multiple contentType options here.
(headers[ContentType] as String).substringBefore(";").lowercase(Locale.US)
} else {
null
}
val request = when (requestConfig.method) {
RequestMethod.DELETE -> Request.Builder().url(url).delete(requestBody(requestConfig.body, contentType))
RequestMethod.GET -> Request.Builder().url(url)
RequestMethod.HEAD -> Request.Builder().url(url).head()
RequestMethod.PATCH -> Request.Builder().url(url).patch(requestBody(requestConfig.body, contentType))
RequestMethod.PUT -> Request.Builder().url(url).put(requestBody(requestConfig.body, contentType))
RequestMethod.POST -> Request.Builder().url(url).post(requestBody(requestConfig.body, contentType))
RequestMethod.OPTIONS -> Request.Builder().url(url).method("OPTIONS", null)
}.apply {
headers.forEach { header -> addHeader(header.key, header.value) }
}.build()
val response = client.newCall(request).execute()
val accept = response.header(ContentType)?.substringBefore(";")?.lowercase(Locale.US)
// TODO: handle specific mapping types. e.g. Map<int, Class<?>>
return when {
response.isRedirect -> Redirection(
response.code,
response.headers.toMultimap()
)
response.isInformational -> Informational(
response.message,
response.code,
response.headers.toMultimap()
)
response.isSuccessful -> Success(
responseBody(response.body, accept),
response.code,
response.headers.toMultimap()
)
response.isClientError -> ClientError(
response.message,
response.body?.string(),
response.code,
response.headers.toMultimap()
)
else -> ServerError(
response.message,
response.body?.string(),
response.code,
response.headers.toMultimap()
)
}
}
protected fun parameterToString(value: Any?): String = when (value) {
null -> ""
is Array<*> -> toMultiValue(value, "csv").toString()
is Iterable<*> -> toMultiValue(value, "csv").toString()
is OffsetDateTime, is OffsetTime, is LocalDateTime, is LocalDate, is LocalTime ->
parseDateToQueryString(value)
else -> value.toString()
}
protected inline fun <reified T: Any> parseDateToQueryString(value : T): String {
/*
.replace("\"", "") converts the json object string to an actual string for the query parameter.
The moshi or gson adapter allows a more generic solution instead of trying to use a native
formatter. It also easily allows to provide a simple way to define a custom date format pattern
inside a gson/moshi adapter.
*/
return Serializer.moshi.adapter(T::class.java).toJson(value).replace("\"", "")
}
}

View File

@ -0,0 +1,43 @@
package org.openapitools.client.infrastructure
enum class ResponseType {
Success, Informational, Redirection, ClientError, ServerError
}
interface Response
abstract class ApiResponse<T>(val responseType: ResponseType): Response {
abstract val statusCode: Int
abstract val headers: Map<String,List<String>>
}
class Success<T>(
val data: T,
override val statusCode: Int = -1,
override val headers: Map<String, List<String>> = mapOf()
): ApiResponse<T>(ResponseType.Success)
class Informational<T>(
val statusText: String,
override val statusCode: Int = -1,
override val headers: Map<String, List<String>> = mapOf()
) : ApiResponse<T>(ResponseType.Informational)
class Redirection<T>(
override val statusCode: Int = -1,
override val headers: Map<String, List<String>> = mapOf()
) : ApiResponse<T>(ResponseType.Redirection)
class ClientError<T>(
val message: String? = null,
val body: Any? = null,
override val statusCode: Int = -1,
override val headers: Map<String, List<String>> = mapOf()
) : ApiResponse<T>(ResponseType.ClientError)
class ServerError<T>(
val message: String? = null,
val body: Any? = null,
override val statusCode: Int = -1,
override val headers: Map<String, List<String>>
): ApiResponse<T>(ResponseType.ServerError)

View File

@ -0,0 +1,17 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.math.BigDecimal
class BigDecimalAdapter {
@ToJson
fun toJson(value: BigDecimal): String {
return value.toPlainString()
}
@FromJson
fun fromJson(value: String): BigDecimal {
return BigDecimal(value)
}
}

View File

@ -0,0 +1,17 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.math.BigInteger
class BigIntegerAdapter {
@ToJson
fun toJson(value: BigInteger): String {
return value.toString()
}
@FromJson
fun fromJson(value: String): BigInteger {
return BigInteger(value)
}
}

View File

@ -0,0 +1,12 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
class ByteArrayAdapter {
@ToJson
fun toJson(data: ByteArray): String = String(data)
@FromJson
fun fromJson(data: String): ByteArray = data.toByteArray()
}

View File

@ -0,0 +1,18 @@
@file:Suppress("unused")
package org.openapitools.client.infrastructure
import java.lang.RuntimeException
open class ClientException(message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) {
companion object {
private const val serialVersionUID: Long = 123L
}
}
open class ServerException(message: kotlin.String? = null, val statusCode: Int = -1, val response: Response? = null) : RuntimeException(message) {
companion object {
private const val serialVersionUID: Long = 456L
}
}

View File

@ -0,0 +1,19 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.time.LocalDate
import java.time.format.DateTimeFormatter
class LocalDateAdapter {
@ToJson
fun toJson(value: LocalDate): String {
return DateTimeFormatter.ISO_LOCAL_DATE.format(value)
}
@FromJson
fun fromJson(value: String): LocalDate {
return LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE)
}
}

View File

@ -0,0 +1,19 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class LocalDateTimeAdapter {
@ToJson
fun toJson(value: LocalDateTime): String {
return DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(value)
}
@FromJson
fun fromJson(value: String): LocalDateTime {
return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
}
}

View File

@ -0,0 +1,19 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
class OffsetDateTimeAdapter {
@ToJson
fun toJson(value: OffsetDateTime): String {
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(value)
}
@FromJson
fun fromJson(value: String): OffsetDateTime {
return OffsetDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE_TIME)
}
}

View File

@ -0,0 +1,11 @@
package org.openapitools.client.infrastructure
/**
* Defines a config object for a given part of a multi-part request.
* NOTE: Headers is a Map<String,String> because rfc2616 defines
* multi-valued headers as csv-only.
*/
data class PartConfig<T>(
val headers: MutableMap<String, String> = mutableMapOf(),
val body: T? = null
)

View File

@ -0,0 +1,18 @@
package org.openapitools.client.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<String,String> because rfc2616 defines
* multi-valued headers as csv-only.
*/
data class RequestConfig<T>(
val method: RequestMethod,
val path: String,
val headers: MutableMap<String, String> = mutableMapOf(),
val query: MutableMap<String, List<String>> = mutableMapOf(),
val requiresAuthentication: Boolean,
val body: T? = null
)

View File

@ -0,0 +1,8 @@
package org.openapitools.client.infrastructure
/**
* Provides enumerated HTTP verbs
*/
enum class RequestMethod {
GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT
}

View File

@ -0,0 +1,24 @@
package org.openapitools.client.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
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
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

View File

@ -0,0 +1,23 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
object Serializer {
@JvmStatic
val moshiBuilder: Moshi.Builder = Moshi.Builder()
.add(OffsetDateTimeAdapter())
.add(LocalDateTimeAdapter())
.add(LocalDateAdapter())
.add(UUIDAdapter())
.add(ByteArrayAdapter())
.add(URIAdapter())
.add(KotlinJsonAdapterFactory())
.add(BigDecimalAdapter())
.add(BigIntegerAdapter())
@JvmStatic
val moshi: Moshi by lazy {
moshiBuilder.build()
}
}

View File

@ -0,0 +1,13 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.net.URI
class URIAdapter {
@ToJson
fun toJson(uri: URI) = uri.toString()
@FromJson
fun fromJson(s: String): URI = URI.create(s)
}

View File

@ -0,0 +1,13 @@
package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import java.util.UUID
class UUIDAdapter {
@ToJson
fun toJson(uuid: UUID) = uuid.toString()
@FromJson
fun fromJson(s: String): UUID = UUID.fromString(s)
}

View File

@ -0,0 +1,47 @@
/**
*
* Please note:
* This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* Do not edit this file manually.
*
*/
@file:Suppress(
"ArrayInDataClass",
"EnumEntryName",
"RemoveRedundantQualifierName",
"UnusedImport"
)
package org.openapitools.client.models
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
*
*
* @param httpDebugOperation
* @param underscoreType
* @param type
* @param typeWithUnderscore
*/
data class PropertyNameMapping (
@Json(name = "http_debug_operation")
val httpDebugOperation: kotlin.String? = null,
@Json(name = "_type")
val underscoreType: kotlin.String? = null,
@Json(name = "type")
val type: kotlin.String? = null,
@Json(name = "type_")
val typeWithUnderscore: kotlin.String? = null
)