From 84a881d68bd7d8c54b0eb9077644e630e19b18b7 Mon Sep 17 00:00:00 2001 From: Ferran Pons Date: Wed, 7 Aug 2019 14:29:10 +0200 Subject: [PATCH 1/3] Added Feign Support --- generator/build.gradle | 1 + .../retroswagger/RetroswaggerGenerator.kt | 54 ++- .../spain/retroswagger/lib/FeignApiBuilder.kt | 414 ++++++++++++++++++ ...gerApiBuilder.kt => RetrofitApiBuilder.kt} | 2 +- 4 files changed, 468 insertions(+), 3 deletions(-) create mode 100644 generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt rename generator/src/main/java/com/schibsted/spain/retroswagger/lib/{RetroswaggerApiBuilder.kt => RetrofitApiBuilder.kt} (99%) diff --git a/generator/build.gradle b/generator/build.gradle index c091b65..7925eb8 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -50,6 +50,7 @@ dependencies { compile 'com.squareup:kotlinpoet:1.3.0' compile "io.reactivex.rxjava2:rxjava:2.2.9" compile 'com.squareup.retrofit2:retrofit:2.6.0' + compile 'io.github.openfeign:feign-core:10.2.3' def jacksonVersion = '2.8.4' compile "com.fasterxml.jackson.core:jackson-core:$jacksonVersion" diff --git a/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt b/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt index a51277d..572bdc0 100644 --- a/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt +++ b/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt @@ -2,8 +2,9 @@ package com.schibsted.spain.retroswagger import com.google.auto.service.AutoService import com.schibsted.spain.retroswagger.annotation.Retroswagger +import com.schibsted.spain.retroswagger.lib.FeignApiBuilder import com.schibsted.spain.retroswagger.lib.RetroswaggerErrorTracking -import com.schibsted.spain.retroswagger.lib.RetroswaggerApiBuilder +import com.schibsted.spain.retroswagger.lib.RetrofitApiBuilder import com.schibsted.spain.retroswagger.lib.RetroswaggerApiConfiguration import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.TypeSpec @@ -150,7 +151,35 @@ class RetroswaggerGenerator : AbstractProcessor() { overrideInterfaceSlash ) - val kotlinApiBuilder = RetroswaggerApiBuilder( + val isRetrofitAvailable = try { + Class.forName("retrofit2.Retrofit") + true + } catch (exception: ClassNotFoundException) { + false + } + + val isFeignAvailable = try { + Class.forName("retrofit2.Retrofit") + true + } catch (exception: ClassNotFoundException) { + false + } + + if (isRetrofitAvailable) { + generateRetrofitCode(configuration, className, pack) + } + + if (isFeignAvailable) { + generateFeignCode(configuration, className, pack) + } + } + + private fun generateRetrofitCode( + configuration: RetroswaggerApiConfiguration, + className: String, + pack: String + ) { + val kotlinApiBuilder = RetrofitApiBuilder( configuration, DummyRetroswaggerErrorTracking() ) @@ -165,6 +194,27 @@ class RetroswaggerGenerator : AbstractProcessor() { } } + private fun generateFeignCode( + configuration: RetroswaggerApiConfiguration, + className: String, + pack: String + ) { + val feignApiBuilder = FeignApiBuilder( + configuration, + DummyRetroswaggerErrorTracking() + ) + feignApiBuilder.build() + + generateClass(className, pack, feignApiBuilder.getGeneratedApiInterfaceTypeSpec()) + for (typeSpec in feignApiBuilder.getGeneratedModelListTypeSpec()) { + generateClass(className, pack, typeSpec) + } + for (typeSpec in feignApiBuilder.getGeneratedEnumListTypeSpec()) { + generateClass(className, pack, typeSpec) + } + } + + private fun generateClass( className: String, pack: String, diff --git a/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt b/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt new file mode 100644 index 0000000..4c744d9 --- /dev/null +++ b/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt @@ -0,0 +1,414 @@ +package com.schibsted.spain.retroswagger.lib + +import com.google.gson.annotations.SerializedName +import com.squareup.kotlinpoet.AnnotationSpec +import com.squareup.kotlinpoet.ClassName +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.ParameterSpec +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.TypeSpec +import com.squareup.kotlinpoet.TypeVariableName +import com.squareup.kotlinpoet.asClassName +import feign.Body +import feign.Param +import feign.RequestLine +import io.reactivex.Completable +import io.reactivex.Single +import io.swagger.models.HttpMethod +import io.swagger.models.ModelImpl +import io.swagger.models.Operation +import io.swagger.models.RefModel +import io.swagger.models.ArrayModel +import io.swagger.models.Swagger +import io.swagger.models.parameters.BodyParameter +import io.swagger.models.parameters.Parameter +import io.swagger.models.parameters.PathParameter +import io.swagger.models.parameters.QueryParameter +import io.swagger.models.properties.ArrayProperty +import io.swagger.models.properties.DoubleProperty +import io.swagger.models.properties.FloatProperty +import io.swagger.models.properties.IntegerProperty +import io.swagger.models.properties.LongProperty +import io.swagger.models.properties.Property +import io.swagger.models.properties.RefProperty +import io.swagger.models.properties.StringProperty +import io.swagger.parser.SwaggerParser +import java.io.FileNotFoundException +import java.lang.IllegalStateException +import java.net.UnknownHostException +import java.util.ArrayList + +private const val PACKAGE_PREFIX = "com.schibsted.retroswagger." + +class FeignApiBuilder( + private val retroswaggerApiConfiguration: RetroswaggerApiConfiguration, + private val errorTracking: RetroswaggerErrorTracking +) { + companion object { + const val OK_RESPONSE = "200" + const val ARRAY_SWAGGER_TYPE = "array" + const val INTEGER_SWAGGER_TYPE = "integer" + const val NUMBER_SWAGGER_TYPE = "number" + const val STRING_SWAGGER_TYPE = "string" + const val BOOLEAN_SWAGGER_TYPE = "boolean" + const val REF_SWAGGER_TYPE = "ref" + } + + private val swaggerModel: Swagger = try { + if (retroswaggerApiConfiguration.swaggerUrl.isNotEmpty()) { + SwaggerParser().read(retroswaggerApiConfiguration.swaggerUrl) + } else { + SwaggerParser().read(retroswaggerApiConfiguration.swaggerFile) + } + } catch (unknown: UnknownHostException) { + errorTracking.logException(unknown) + Swagger() + } catch (illegal: IllegalStateException) { + errorTracking.logException(illegal) + Swagger() + } catch (notFound: FileNotFoundException) { + errorTracking.logException(notFound) + Swagger() + } + + private lateinit var apiInterfaceTypeSpec: TypeSpec + private val responseBodyModelListTypeSpec: ArrayList = ArrayList() + private val enumListTypeSpec: ArrayList = ArrayList() + + fun build() { + createEnumClasses() + apiInterfaceTypeSpec = createApiRetrofitInterface(createApiResponseBodyModel()) + } + + fun getGeneratedApiInterfaceTypeSpec(): TypeSpec { + return apiInterfaceTypeSpec + } + + fun getGeneratedModelListTypeSpec(): List { + return responseBodyModelListTypeSpec + } + + fun getGeneratedEnumListTypeSpec(): List { + return enumListTypeSpec + } + + private fun createEnumClasses() { + addOperationResponseEnums() + addModelEnums() + } + + private fun addModelEnums() { + if (swaggerModel.definitions != null && swaggerModel.definitions.isNotEmpty()) { + for (definition in swaggerModel.definitions) { + if (definition.value != null && definition.value.properties != null) { + for (modelProperty in definition.value.properties) { + if (modelProperty.value is StringProperty) { + val enumDefinition = (modelProperty.value as StringProperty).enum + if (enumDefinition != null) { + val enumTypeSpecBuilder = TypeSpec.enumBuilder(modelProperty.key.capitalize()) + for (constant in enumDefinition) { + enumTypeSpecBuilder.addEnumConstant(constant) + } + if (!enumListTypeSpec.contains(enumTypeSpecBuilder.build())) { + enumListTypeSpec.add(enumTypeSpecBuilder.build()) + } + } + } + } + } + } + } + } + + private fun addOperationResponseEnums() { + if (swaggerModel.paths != null && swaggerModel.paths.isNotEmpty()) { + for (path in swaggerModel.paths) { + for (operation in path.value.operationMap) { + try { + for (parameters in operation.value.parameters) { + if (parameters is PathParameter) { + if (parameters.enum != null) { + val enumTypeSpecBuilder = TypeSpec.enumBuilder(parameters.name.capitalize()) + for (constant in parameters.enum) { + enumTypeSpecBuilder.addEnumConstant(constant) + } + if (!enumListTypeSpec.contains(enumTypeSpecBuilder.build())) { + enumListTypeSpec.add(enumTypeSpecBuilder.build()) + } + } + } + } + } catch (error: Exception) { + errorTracking.logException(error) + } + } + } + } + } + + private fun createApiResponseBodyModel(): List { + val classNameList = ArrayList() + + if (swaggerModel.definitions != null && swaggerModel.definitions.isNotEmpty()) { + for (definition in swaggerModel.definitions) { + + var modelClassTypeSpec: TypeSpec.Builder + try { + modelClassTypeSpec = TypeSpec.classBuilder(definition.key).addModifiers(KModifier.DATA) + classNameList.add(definition.key) + } catch (error: IllegalArgumentException) { + modelClassTypeSpec = TypeSpec.classBuilder("Model" + definition.key.capitalize()) + .addModifiers(KModifier.DATA) + classNameList.add("Model" + definition.key.capitalize()) + } + + if (definition.value != null && definition.value.properties != null) { + val primaryConstructor = FunSpec.constructorBuilder() + for (modelProperty in definition.value.properties) { + val typeName: TypeName = getTypeName(modelProperty) + val propertySpec = PropertySpec.builder(modelProperty.key, typeName) + .addAnnotation(AnnotationSpec.builder(SerializedName::class) + .addMember("\"${modelProperty.key}\"") + .build()) + .initializer(modelProperty.key) + .build() + primaryConstructor.addParameter(modelProperty.key, typeName) + modelClassTypeSpec.addProperty(propertySpec) + } + modelClassTypeSpec.primaryConstructor(primaryConstructor.build()) + + responseBodyModelListTypeSpec.add(modelClassTypeSpec.build()) + } + } + } + + return classNameList + } + + private fun createApiRetrofitInterface(classNameList: List): TypeSpec { + val apiInterfaceTypeSpecBuilder = TypeSpec + .interfaceBuilder("${retroswaggerApiConfiguration.componentName}ApiInterface") + .addModifiers(KModifier.PUBLIC) + + addApiPathMethods(apiInterfaceTypeSpecBuilder, classNameList) + + return apiInterfaceTypeSpecBuilder.build() + } + + private fun addApiPathMethods(apiInterfaceTypeSpec: TypeSpec.Builder, classNameList: List) { + if (swaggerModel.paths != null && swaggerModel.paths.isNotEmpty()) { + for (path in swaggerModel.paths) { + for (operation in path.value.operationMap) { + + var annotationSpec: AnnotationSpec + if (retroswaggerApiConfiguration.overrideInterfaceSlash) { + annotationSpec = when { + operation.key.name.contains( + "GET") -> AnnotationSpec.builder(RequestLine::class) + .addMember("GET \"${path.key.removePrefix("/")}\"").build() + operation.key.name.contains( + "POST") -> AnnotationSpec.builder(RequestLine::class) + .addMember("POST \"${path.key.removePrefix("/")}\"").build() + operation.key.name.contains( + "PUT") -> AnnotationSpec.builder(RequestLine::class) + .addMember("PUT \"${path.key.removePrefix("/")}\"").build() + operation.key.name.contains( + "PATCH") -> AnnotationSpec.builder(RequestLine::class) + .addMember("PATCH \"${path.key.removePrefix("/")}\"").build() + operation.key.name.contains( + "DELETE") -> AnnotationSpec.builder(RequestLine::class) + .addMember("DELETE \"${path.key.removePrefix("/")}\"").build() + else -> AnnotationSpec.builder(RequestLine::class) + .addMember("\"${path.key.removePrefix("/")}\"").build() + } + } else { + annotationSpec = when { + operation.key.name.contains( + "GET") -> AnnotationSpec.builder(RequestLine::class) + .addMember("GET \"${path.key}\"").build() + operation.key.name.contains( + "POST") -> AnnotationSpec.builder(RequestLine::class) + .addMember("POST \"${path.key}\"").build() + operation.key.name.contains( + "PUT") -> AnnotationSpec.builder(RequestLine::class) + .addMember("PUT \"${path.key}\"").build() + operation.key.name.contains( + "PATCH") -> AnnotationSpec.builder(RequestLine::class) + .addMember("PATCH \"${path.key}\"").build() + operation.key.name.contains( + "DELETE") -> AnnotationSpec.builder(RequestLine::class) + .addMember("DELETE \"${path.key}\"").build() + else -> AnnotationSpec.builder(RequestLine::class) + .addMember("\"${path.key}\"").build() + } + } + + try { + val doc = ((listOf(operation.value.summary + "\n") + + getMethodParametersDocs(operation)).joinToString("\n")).trim() + + val returnedClass = getReturnedClass(operation, classNameList) + val methodParameters = getMethodParameters(operation) + val funSpec = FunSpec.builder(operation.value.operationId) + .addModifiers(KModifier.PUBLIC, KModifier.ABSTRACT) + .addAnnotation(annotationSpec) + .addParameters(methodParameters) + .returns(returnedClass) + .addKdoc("$doc\n") + .build() + + apiInterfaceTypeSpec.addFunction(funSpec) + } catch (exception: Exception) { + errorTracking.logException(exception) + } + } + } + } + } + + private fun getMethodParametersDocs(operation: MutableMap.MutableEntry): Iterable { + return operation.value.parameters.filterNot { it.description.isNullOrBlank() } + .map { "@param ${it.name} ${it.description}" } + } + + private fun getTypeName(modelProperty: MutableMap.MutableEntry): TypeName { + val property = modelProperty.value + return when { + property.type == REF_SWAGGER_TYPE -> + TypeVariableName.invoke((property as RefProperty).simpleRef).requiredOrNullable(property.required) + + property.type == ARRAY_SWAGGER_TYPE -> { + val arrayProperty = property as ArrayProperty + getTypedArray(arrayProperty.items).requiredOrNullable(arrayProperty.required) + } + else -> getKotlinClassTypeName(property.type, property.format).requiredOrNullable(property.required) + } + } + + private fun getMethodParameters( + operation: MutableMap.MutableEntry + ): Iterable { + return operation.value.parameters.mapNotNull { parameter -> + // Transform parameters in the format foo.bar to fooBar + val name = parameter.name.split('.').mapIndexed { index, s -> if (index > 0) s.capitalize() else s }.joinToString("") + when (parameter.`in`) { + "body" -> { + ParameterSpec.builder(name, getBodyParameterSpec(parameter)) + .addAnnotation(AnnotationSpec.builder(Body::class).build()).build() + } + "path" -> { + val type = getKotlinClassTypeName((parameter as PathParameter).type, parameter.format).requiredOrNullable(parameter.required) + ParameterSpec.builder(name, type) + .addAnnotation(AnnotationSpec.builder(Param::class).addMember("\"${parameter.name}\"").build()).build() + } + "query" -> { + if ((parameter as QueryParameter).type == ARRAY_SWAGGER_TYPE) { + val type = List::class.asClassName().parameterizedBy(getKotlinClassTypeName(parameter.items.type)).requiredOrNullable(parameter.required) + ParameterSpec.builder(name, type) + } else { + val type = getKotlinClassTypeName(parameter.type, parameter.format).requiredOrNullable(parameter.required) + ParameterSpec.builder(name, type) + }.addAnnotation(AnnotationSpec.builder(Param::class).addMember("\"${parameter.name}\"").build()).build() + } + else -> null + } + } + } + + private fun getBodyParameterSpec(parameter: Parameter): TypeName { + val bodyParameter = parameter as BodyParameter + + return when (val schema = bodyParameter.schema) { + is RefModel -> ClassName.bestGuess(PACKAGE_PREFIX + schema.simpleRef.capitalize()).requiredOrNullable(parameter.required) + + is ArrayModel -> getTypedArray(schema.items).requiredOrNullable(parameter.required) + + else -> { + val bodyParameter1 = parameter.schema as? ModelImpl ?: ModelImpl() + + if (STRING_SWAGGER_TYPE == bodyParameter1.type) { + String::class.asClassName().requiredOrNullable(parameter.required) + } else { + ClassName.bestGuess(PACKAGE_PREFIX + parameter.name.capitalize()).requiredOrNullable(parameter.required) + } + } + } + } + + private fun getTypedArray(items: Property): TypeName { + val typeProperty = when (items) { + is LongProperty -> TypeVariableName.invoke(Long::class.simpleName!!) + is IntegerProperty -> TypeVariableName.invoke(Int::class.simpleName!!) + is FloatProperty -> TypeVariableName.invoke(Float::class.simpleName!!) + is DoubleProperty -> TypeVariableName.invoke(Double::class.simpleName!!) + is RefProperty -> TypeVariableName.invoke(items.simpleRef) + else -> getKotlinClassTypeName(items.type, items.format) + } + return List::class.asClassName().parameterizedBy(typeProperty) + } + + private fun TypeName.requiredOrNullable(required: Boolean) = if (required) this else copy(nullable = true) + + private fun getReturnedClass( + operation: MutableMap.MutableEntry, + classNameList: List + ): TypeName { + try { + if (operation.value.responses[OK_RESPONSE]?.schema != null && + operation.value.responses[OK_RESPONSE]?.schema is RefProperty) { + val refProperty = (operation.value.responses[OK_RESPONSE]?.schema as RefProperty) + var responseClassName = refProperty.simpleRef + responseClassName = getValidClassName(responseClassName, refProperty) + + if (classNameList.contains(responseClassName)) { + return Single::class.asClassName().parameterizedBy(TypeVariableName.invoke(responseClassName)) + } + } else if (operation.value.responses[OK_RESPONSE]?.schema != null && + operation.value.responses[OK_RESPONSE]?.schema is ArrayProperty) { + val refProperty = (operation.value.responses[OK_RESPONSE]?.schema as ArrayProperty) + var responseClassName = (refProperty.items as RefProperty).simpleRef + responseClassName = getValidClassName(responseClassName, (refProperty.items as RefProperty)) + + if (classNameList.contains(responseClassName)) { + return Single::class.asClassName().parameterizedBy( + List::class.asClassName().parameterizedBy(TypeVariableName.invoke(responseClassName)) + ) + } + } + } catch (error: ClassCastException) { + errorTracking.logException(error) + } + + return Completable::class.asClassName() + } + + private fun getValidClassName(responseClassName: String, refProperty: RefProperty): String { + var className = responseClassName + try { + TypeSpec.classBuilder(className) + } catch (error: IllegalArgumentException) { + if (refProperty.simpleRef != null) { + className = "Model" + refProperty.simpleRef.capitalize() + } + } + return className + } + + private fun getKotlinClassTypeName(type: String, format: String? = null): TypeName { + return when (type) { + ARRAY_SWAGGER_TYPE -> TypeVariableName.invoke(List::class.simpleName!!) + STRING_SWAGGER_TYPE -> TypeVariableName.invoke(String::class.simpleName!!) + NUMBER_SWAGGER_TYPE -> TypeVariableName.invoke(Double::class.simpleName!!) + INTEGER_SWAGGER_TYPE -> { + when (format) { + "int64" -> TypeVariableName.invoke(Long::class.simpleName!!) + else -> TypeVariableName.invoke(Int::class.simpleName!!) + } + } + else -> TypeVariableName.invoke(type.capitalize()) + } + } +} \ No newline at end of file diff --git a/generator/src/main/java/com/schibsted/spain/retroswagger/lib/RetroswaggerApiBuilder.kt b/generator/src/main/java/com/schibsted/spain/retroswagger/lib/RetrofitApiBuilder.kt similarity index 99% rename from generator/src/main/java/com/schibsted/spain/retroswagger/lib/RetroswaggerApiBuilder.kt rename to generator/src/main/java/com/schibsted/spain/retroswagger/lib/RetrofitApiBuilder.kt index b84b655..1710c85 100644 --- a/generator/src/main/java/com/schibsted/spain/retroswagger/lib/RetroswaggerApiBuilder.kt +++ b/generator/src/main/java/com/schibsted/spain/retroswagger/lib/RetrofitApiBuilder.kt @@ -48,7 +48,7 @@ import java.util.ArrayList private const val PACKAGE_PREFIX = "com.schibsted.retroswagger." -class RetroswaggerApiBuilder( +class RetrofitApiBuilder( private val retroswaggerApiConfiguration: RetroswaggerApiConfiguration, private val errorTracking: RetroswaggerErrorTracking ) { From 3debc5906bc19ed4439db7969cda118b451d564a Mon Sep 17 00:00:00 2001 From: Ferran Pons Date: Thu, 8 Aug 2019 07:59:36 +0200 Subject: [PATCH 2/3] Make Feign work but not finished --- app/build.gradle | 5 ++++ .../retroswagger/RetroswaggerGenerator.kt | 4 +--- .../spain/retroswagger/lib/FeignApiBuilder.kt | 23 +++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 975441c..34ebe5f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,11 @@ android { lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } } sourceSets { diff --git a/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt b/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt index 572bdc0..29bb2ff 100644 --- a/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt +++ b/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt @@ -167,9 +167,7 @@ class RetroswaggerGenerator : AbstractProcessor() { if (isRetrofitAvailable) { generateRetrofitCode(configuration, className, pack) - } - - if (isFeignAvailable) { + } else if (isFeignAvailable) { generateFeignCode(configuration, className, pack) } } diff --git a/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt b/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt index 4c744d9..4084cee 100644 --- a/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt +++ b/generator/src/main/java/com/schibsted/spain/retroswagger/lib/FeignApiBuilder.kt @@ -12,7 +12,6 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.asClassName -import feign.Body import feign.Param import feign.RequestLine import io.reactivex.Completable @@ -208,19 +207,19 @@ class FeignApiBuilder( annotationSpec = when { operation.key.name.contains( "GET") -> AnnotationSpec.builder(RequestLine::class) - .addMember("GET \"${path.key.removePrefix("/")}\"").build() + .addMember("\"GET ${path.key.removePrefix("/")}\"").build() operation.key.name.contains( "POST") -> AnnotationSpec.builder(RequestLine::class) - .addMember("POST \"${path.key.removePrefix("/")}\"").build() + .addMember("\"POST ${path.key.removePrefix("/")}\"").build() operation.key.name.contains( "PUT") -> AnnotationSpec.builder(RequestLine::class) - .addMember("PUT \"${path.key.removePrefix("/")}\"").build() + .addMember("\"PUT ${path.key.removePrefix("/")}\"").build() operation.key.name.contains( "PATCH") -> AnnotationSpec.builder(RequestLine::class) - .addMember("PATCH \"${path.key.removePrefix("/")}\"").build() + .addMember("\"PATCH ${path.key.removePrefix("/")}\"").build() operation.key.name.contains( "DELETE") -> AnnotationSpec.builder(RequestLine::class) - .addMember("DELETE \"${path.key.removePrefix("/")}\"").build() + .addMember("\"DELETE ${path.key.removePrefix("/")}\"").build() else -> AnnotationSpec.builder(RequestLine::class) .addMember("\"${path.key.removePrefix("/")}\"").build() } @@ -228,19 +227,19 @@ class FeignApiBuilder( annotationSpec = when { operation.key.name.contains( "GET") -> AnnotationSpec.builder(RequestLine::class) - .addMember("GET \"${path.key}\"").build() + .addMember("\"GET ${path.key}\"").build() operation.key.name.contains( "POST") -> AnnotationSpec.builder(RequestLine::class) - .addMember("POST \"${path.key}\"").build() + .addMember("\"POST ${path.key}\"").build() operation.key.name.contains( "PUT") -> AnnotationSpec.builder(RequestLine::class) - .addMember("PUT \"${path.key}\"").build() + .addMember("\"PUT ${path.key}\"").build() operation.key.name.contains( "PATCH") -> AnnotationSpec.builder(RequestLine::class) - .addMember("PATCH \"${path.key}\"").build() + .addMember("\"PATCH ${path.key}\"").build() operation.key.name.contains( "DELETE") -> AnnotationSpec.builder(RequestLine::class) - .addMember("DELETE \"${path.key}\"").build() + .addMember("\"DELETE ${path.key}\"").build() else -> AnnotationSpec.builder(RequestLine::class) .addMember("\"${path.key}\"").build() } @@ -297,7 +296,7 @@ class FeignApiBuilder( when (parameter.`in`) { "body" -> { ParameterSpec.builder(name, getBodyParameterSpec(parameter)) - .addAnnotation(AnnotationSpec.builder(Body::class).build()).build() + .addAnnotation(AnnotationSpec.builder(Param::class).addMember("\"${parameter.name}\"").build()).build() } "path" -> { val type = getKotlinClassTypeName((parameter as PathParameter).type, parameter.format).requiredOrNullable(parameter.required) From 8e4f4d340c840987907563d69dbb66dc401f43bb Mon Sep 17 00:00:00 2001 From: Ferran Pons Date: Thu, 8 Aug 2019 08:06:43 +0200 Subject: [PATCH 3/3] Not include retrofit and feign dependency and must bve provided --- app/build.gradle | 2 ++ generator/build.gradle | 5 +++-- .../schibsted/spain/retroswagger/RetroswaggerGenerator.kt | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 34ebe5f..99fbbbe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -67,6 +67,8 @@ dependencies { implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion" implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" + //implementation 'io.github.openfeign:feign-core:10.2.3' + implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" diff --git a/generator/build.gradle b/generator/build.gradle index 7925eb8..0c70439 100644 --- a/generator/build.gradle +++ b/generator/build.gradle @@ -49,8 +49,9 @@ dependencies { compile 'com.squareup:kotlinpoet:1.3.0' compile "io.reactivex.rxjava2:rxjava:2.2.9" - compile 'com.squareup.retrofit2:retrofit:2.6.0' - compile 'io.github.openfeign:feign-core:10.2.3' + + compileOnly 'com.squareup.retrofit2:retrofit:2.6.0' + compileOnly 'io.github.openfeign:feign-core:10.2.3' def jacksonVersion = '2.8.4' compile "com.fasterxml.jackson.core:jackson-core:$jacksonVersion" diff --git a/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt b/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt index 29bb2ff..203141d 100644 --- a/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt +++ b/generator/src/main/java/com/schibsted/spain/retroswagger/RetroswaggerGenerator.kt @@ -159,7 +159,7 @@ class RetroswaggerGenerator : AbstractProcessor() { } val isFeignAvailable = try { - Class.forName("retrofit2.Retrofit") + Class.forName("feign.Param") true } catch (exception: ClassNotFoundException) { false