Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for square brackets in the operation name #32

Merged
merged 6 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ You can find some **examples** in this repository to help you set up your genera

* [samples/kotlin-android](/samples/kotlin-android) Contains an example of an Android Library configured with a `build.gradle.kts` file, using Kotlin as scripting language.

* [samples/junit-tests](/samples/junit-tests) This sample contains specs used to test edge cases and scenarios that have been reported in the issue tracker or that are worth testing.

## How the generated code will look like

[Here](/SAMPLES.md) you can find some examples of how the generated code will look like in your project.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@file:Suppress("Unused")

object PublishingVersions {
const val PLUGIN_VERSION = "1.0.0"
const val PLUGIN_VERSION = "1.1.0-SNAPSHOT"
const val PLUGIN_GROUP = "com.yelp.codegen"
const val PLUGIN_ARTIFACT = "plugin"
}
11 changes: 11 additions & 0 deletions plugin/src/main/java/com/yelp/codegen/KotlinGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,15 @@ class KotlinGenerator : SharedCodegen() {
// Override the swagger version with the one provided from command line.
swagger.info.version = additionalProperties[SPEC_VERSION] as String
}

/**
* Function used to sanitize the name for operation generations.
* The superclass is not providing the correct string pattern (See #31).
*
* Here we override the provided pattern to include also square brackets in during the
* parameter name generation.
*/
override fun removeNonNameElementToCamelCase(name: String?): String {
return super.removeNonNameElementToCamelCase(name, "[-_:;#\\[\\]]")
}
}
10 changes: 10 additions & 0 deletions plugin/src/test/java/com/yelp/codegen/KotlinGeneratorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,14 @@ class KotlinGeneratorTest {
assert(KotlinGenerator().toModelName("model with dot.s") == "ModelWithDotS")
assert(KotlinGenerator().toModelName("model with userscore_s") == "ModelWithUserscoreS")
}

@Test
fun removeNonNameElementToCamelCase_withSquareBrackets() {
assert(KotlinGenerator().removeNonNameElementToCamelCase("type[]") == "type")
assert(KotlinGenerator().removeNonNameElementToCamelCase("type[value]") == "typeValue")
assert(KotlinGenerator().removeNonNameElementToCamelCase("type[") == "type")
assert(KotlinGenerator().removeNonNameElementToCamelCase("type]") == "type")
assert(KotlinGenerator().removeNonNameElementToCamelCase("[type]") == "type")
assert(KotlinGenerator().removeNonNameElementToCamelCase("[type]key") == "typeKey")
}
}
65 changes: 65 additions & 0 deletions samples/junit-tests/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
buildscript {
repositories {
mavenLocal()
gradlePluginPortal()
google()
mavenCentral()
jcenter()
}

dependencies {
classpath "com.android.tools.build:gradle:3.2.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21"
classpath "com.yelp.codegen:plugin:1.1.0-SNAPSHOT"
}
}

apply plugin: "com.android.library"
apply plugin: "kotlin-android"
apply plugin: "com.yelp.codegen.plugin"

android {
compileSdkVersion = 28
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
versionCode = 1
versionName = "1.0"
}
}

dependencies {
// Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.21"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.21"

// Moshi
implementation "com.squareup.moshi:moshi:1.8.0"
implementation "com.squareup.moshi:moshi-adapters:1.8.0"
implementation "com.squareup.moshi:moshi-kotlin:1.8.0"
implementation "com.squareup.retrofit2:converter-moshi:2.5.0"
implementation "com.squareup.retrofit2:adapter-rxjava2:2.5.0"

// Date Support
implementation "com.jakewharton.threetenabp:threetenabp:1.1.1"

// RxJava
implementation "io.reactivex.rxjava2:rxjava:2.2.4"
implementation "io.reactivex.rxjava2:rxandroid:2.1.0"

// Testing Dependencies
testImplementation "junit:junit:4.12"
testImplementation "com.squareup.okhttp3:mockwebserver:3.12.3"
}

generateSwagger {
platform = "kotlin"
packageName = "com.yelp.codegen.generatecodesamples"
specName = "junittests"
inputFile = file("./junit_tests_specs.json")
outputDir = file("./src/main/java/")
}

repositories {
mavenCentral()
}
61 changes: 61 additions & 0 deletions samples/junit-tests/junit_tests_specs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"definitions": {},
"info": {
"description": "This spec is used to have JUnit Tests to check the generated code.",
"title": "JUnit Tests",
"version": "1.0.0"
},
"paths": {
"/brackets/in/parameter/name": {
"get": {
"description": "Make sure that brackets in parameter name are treated properly",
"operationId": "getBracketsInParameterName",
"parameters": [
{
"in": "query",
"name": "page",
"required": false,
"type": "string"
},
{
"in": "query",
"name": "page[]",
"required": false,
"type": "string"
},
{
"in": "query",
"name": "datePosted[before]",
"required": false,
"type": "string"
},
{
"in": "query",
"name": "datePosted[strictly_before]",
"required": false,
"type": "string"
},
{
"in": "query",
"name": "datePosted[after]",
"required": false,
"type": "string"
},
{
"in": "query",
"name": "datePosted[strictly_after]",
"required": false,
"type": "string"
}
],
"responses": {
"200": {
"description": "successful operation"
}
},
"summary": "Test brackets in parameter name"
}
}
},
"swagger": "2.0"
}
2 changes: 2 additions & 0 deletions samples/junit-tests/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yelp.samplelibrary"/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* NOTE: This class is auto generated by the Swagger Gradle Codegen for the following API: JUnit Tests
*
* More info on this tool is available on https://github.com/Yelp/swagger-gradle-codegen
*/

package com.yelp.codegen.generatecodesamples.apis

import io.reactivex.Completable
import retrofit2.http.GET
import retrofit2.http.Headers

@JvmSuppressWildcards
interface DefaultApi {
/**
* Test brackets in parameter name
* Make sure that brackets in parameter name are treated properly
* The endpoint is owned by junittests service owner
* @param page (optional)
* @param page2 (optional)
* @param datePostedBefore (optional)
* @param datePostedStrictlyBefore (optional)
* @param datePostedAfter (optional)
* @param datePostedStrictlyAfter (optional)
*/
@Headers(
"X-Operation-ID: getBracketsInParameterName"
)

@GET("/brackets/in/parameter/name")
fun getBracketsInParameterName(
@retrofit2.http.Query("page") page: String?,
@retrofit2.http.Query("page[]") page2: String?,
@retrofit2.http.Query("datePosted[before]") datePostedBefore: String?,
@retrofit2.http.Query("datePosted[strictly_before]") datePostedStrictlyBefore: String?,
@retrofit2.http.Query("datePosted[after]") datePostedAfter: String?,
@retrofit2.http.Query("datePosted[strictly_after]") datePostedStrictlyAfter: String?
): Completable
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.yelp.codegen.generatecodesamples.tools

import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type

internal class CollectionFormatConverterFactory : Converter.Factory() {

override fun stringConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit): Converter<*, String>? {
val rawType = getRawType(type)
if (rawType == String::class.java || rawType == List::class.java)
annotations.forEach {
when (it) {
is CSV -> return CollectionFormatConverter(",")
is SSV -> return CollectionFormatConverter(" ")
is TSV -> return CollectionFormatConverter("\t")
is PIPES -> return CollectionFormatConverter("|")
}
}
return null
}

private class CollectionFormatConverter(private val separator: String) : Converter<Any, String> {
override fun convert(value: Any): String {
when (value) {
is String -> return value
is List<*> -> return value.joinToString(separator)
}
throw RuntimeException("Unsupported type")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.yelp.codegen.generatecodesamples.tools

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class CSV

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class SSV

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class TSV

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class PIPES
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.yelp.codegen.generatecodesamples.tools

import com.squareup.moshi.Json
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type

internal class EnumToValueConverterFactory : Converter.Factory() {

private val enumConverter = EnumToValueConverter()

override fun stringConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit): Converter<*, String>? {
return if (type is Class<*> && type.isEnum) {
enumConverter
} else {
null
}
}

internal class EnumToValueConverter : Converter<Any, String> {
override fun convert(enum: Any): String? {
val enumName = (enum as Enum<*>).name
val jsonAnnotation: Json? = enum.javaClass.getField(enumName).getAnnotation(Json::class.java)

// Checking if the Enum is annotated with @Json to get the name.
// If not, fallback to enum default (.toString())
return if (jsonAnnotation != null) {
jsonAnnotation.name
} else {
enum.toString()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.yelp.codegen.generatecodesamples.tools

import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Converter
import retrofit2.converter.moshi.MoshiConverterFactory

object GeneratedCodeConverters {
private val moshi = Moshi.Builder()
.add(XNullableAdapterFactory())
.add(KotlinJsonAdapterFactory())
.add(TypesAdapterFactory())
.build()

/**
* Creates everything needed for retrofit to make it work with the client lib, including a
* [Moshi] instance. If you want to use your own instance of moshi, use
* converterFactory(moshi) instead, and add [XNullableAdapterFactory], [KotlinJsonAdapterFactory] and
* [TypesAdapterFactory] to your moshi builder (in a similar way how we are instantiating the `moshi` field here).
*/
@JvmStatic
fun converterFactory(): Converter.Factory {
return WrapperConverterFactory(
CollectionFormatConverterFactory(),
EnumToValueConverterFactory(),
MoshiConverterFactory.create(moshi)
)
}

@JvmStatic
fun converterFactory(moshi: Moshi): Converter.Factory {
return WrapperConverterFactory(
CollectionFormatConverterFactory(),
EnumToValueConverterFactory(),
MoshiConverterFactory.create(moshi)
)
}
}
Loading