-
Notifications
You must be signed in to change notification settings - Fork 26
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
chore: update models in kotlin client generator #1373
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Signed-off-by: Allain Magyar <[email protected]>
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
7.4.0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Custom Types | ||
|
||
Right now, the `openapi-generator` tool being used [doesn't cover](https://openapi-generator.tech/docs/generators/kotlin#schema-support-feature) | ||
all the `OAS 3+` features. The goal of this document is to define some processes when we have to manually write the models for it. | ||
|
||
- OpenApi Generator for Kotlin: https://openapi-generator.tech/docs/generators/kotlin | ||
|
||
## OneOf | ||
|
||
- Specification: https://swagger.io/specification/#discriminator-object | ||
|
||
1. Generate the models | ||
2. Find the model you want to override | ||
3. Add the file to `.openapi-generator-ignore` | ||
4. Implement the files | ||
1. Model class | ||
2. Interfaces | ||
3. Adapters | ||
5. Add to git | ||
6. Push | ||
|
||
### OneOf - File Implementation | ||
|
||
The strategy found to implement the `OneOf` was through interfaces. | ||
|
||
E.g. | ||
```yml | ||
AnimalResponse: | ||
oneOf: | ||
- $ref: '#/components/schemas/Cat' | ||
- $ref: '#/components/schemas/Dog' | ||
- $ref: '#/components/schemas/Lizard' | ||
``` | ||
|
||
Generating the models will create the `AnimalResponse` model class file. | ||
In this case `AnimalResponse` can be one of these 3 types | ||
|
||
- Cat | ||
- Dog | ||
- Lizard | ||
|
||
The next step is to create a new base types (interfaces) in `org.hyperledger.identus.client.custom.types.base` package. | ||
|
||
Since we are not going to add a new `model` we just have to create the interfaces in that package. | ||
|
||
It's `mandatory` that each interface implements the `BaseType` interface. | ||
|
||
#### Interfaces | ||
|
||
```kotlin | ||
interface CatType : BaseType { | ||
fun meow(): String { | ||
return convert() | ||
} | ||
} | ||
``` | ||
|
||
```kotlin | ||
interface DogType : BaseType { | ||
fun bark(): String { | ||
return convert() | ||
} | ||
} | ||
``` | ||
|
||
```kotlin | ||
interface LizardType : BaseType { | ||
fun chirp(): String { | ||
return convert() | ||
} | ||
} | ||
``` | ||
|
||
#### Model class | ||
|
||
```kotlin | ||
@JsonAdapter(AnimalResponseAdapter::class) | ||
class AnimalResponse(override var value: Any?) : CatType, DogType, LizardType | ||
``` | ||
|
||
#### Adapter | ||
|
||
If there's no `discriminator` you'll have to try to parse each type to retrieve the typed object. | ||
|
||
```kotlin | ||
class ServiceTypeAdapter : TypeAdapter<AnimalResponse>() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should it be |
||
override fun write(out: JsonWriter, value: AnimalResponse) = // ... | ||
override fun read(input: JsonReader): AnimalResponse { | ||
// use the generic Extension.read(input) to retrieve the object as `Hashmap` | ||
// and add the cases to deserialize the object. | ||
// this method sets the `value` of the base type | ||
return AnimalResponse | ||
} | ||
} | ||
``` | ||
|
||
Or add the `GenericObjectType` interface to the type and retrieve using the `.asObject(MyClass::class)` method. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
version=0.0.1 | ||
version=0.0.1-SNAPSHOT |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.hyperledger.identus.client.custom | ||
|
||
import com.google.gson.Gson | ||
import com.google.gson.ToNumberPolicy | ||
import com.google.gson.TypeAdapter | ||
import com.google.gson.reflect.TypeToken | ||
import com.google.gson.stream.JsonReader | ||
import com.google.gson.stream.JsonToken | ||
import com.google.gson.stream.JsonToken.BEGIN_ARRAY | ||
import com.google.gson.stream.JsonToken.BEGIN_OBJECT | ||
import com.google.gson.stream.JsonToken.BOOLEAN | ||
import com.google.gson.stream.JsonToken.NULL | ||
import com.google.gson.stream.JsonToken.NUMBER | ||
import com.google.gson.stream.JsonToken.STRING | ||
import com.google.gson.stream.JsonWriter | ||
import org.hyperledger.identus.client.custom.adapters.JsonTypeAdapter | ||
import org.hyperledger.identus.client.custom.types.JsonType | ||
import org.hyperledger.identus.client.custom.types.base.BaseType | ||
|
||
inline fun <reified T : Any> BaseType.convert(): T? { | ||
if (this.value == null) { | ||
return null | ||
} | ||
if (this.value is T) { | ||
return this.value as T | ||
} | ||
throw IllegalStateException("Requested parameter as [${this.value!!::class.simpleName}] but is [${T::class.simpleName}]") | ||
} | ||
|
||
inline fun <reified T: BaseType> TypeAdapter<T>.writeExtension(out: JsonWriter, value: T) { | ||
out.jsonValue(Gson().toJson(value.value)) | ||
} | ||
|
||
fun JsonTypeAdapter.oleole() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you've been using this while developing and forgot to remove |
||
println("PORRA") | ||
} | ||
|
||
inline fun <reified T: BaseType> TypeAdapter<T>.readExtension(input: JsonReader): T { | ||
val constructor = T::class.constructors.first() | ||
when (val parsed = input.parse(input)) { | ||
is List<*> -> { | ||
val json = Gson().toJson(parsed) | ||
val type = object : TypeToken<List<Any?>>() {}.type | ||
val list: List<Any?> = Gson().fromJson(json, type) | ||
return constructor.call(list) | ||
} | ||
null, | ||
is String, | ||
is Number, | ||
is Boolean, | ||
is HashMap<*,*> -> return constructor.call(parsed) | ||
else -> throw IllegalArgumentException("Unsupported type ${parsed?.javaClass}") | ||
} | ||
} | ||
|
||
fun JsonReader.parse(input: JsonReader): Any? { | ||
val token: JsonToken = input.peek() | ||
when (token) { | ||
BEGIN_ARRAY -> { | ||
val list = mutableListOf<Any?>() | ||
input.beginArray() | ||
|
||
while (input.hasNext()) { | ||
list.add(parse(input)) | ||
} | ||
|
||
input.endArray() | ||
return list | ||
} | ||
BEGIN_OBJECT -> { | ||
val map = linkedMapOf<Any, Any?>() | ||
input.beginObject() | ||
while (input.hasNext()) { | ||
map[input.nextName()] = parse(input) | ||
} | ||
input.endObject() | ||
return map | ||
} | ||
STRING -> return input.nextString() | ||
NUMBER -> return ToNumberPolicy.LAZILY_PARSED_NUMBER.readNumber(input) | ||
BOOLEAN -> return input.nextBoolean() | ||
NULL -> { | ||
input.nextNull() | ||
return null | ||
} | ||
else -> throw IllegalStateException() | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.hyperledger.identus.client.custom.adapters | ||
|
||
import com.google.gson.TypeAdapter | ||
import com.google.gson.stream.JsonReader | ||
import com.google.gson.stream.JsonWriter | ||
import org.hyperledger.identus.client.custom.readExtension | ||
import org.hyperledger.identus.client.custom.types.JsonType | ||
import org.hyperledger.identus.client.custom.writeExtension | ||
|
||
class JsonTypeAdapter : TypeAdapter<JsonType>() { | ||
override fun write(out: JsonWriter, value: JsonType) = writeExtension(out, value) | ||
|
||
override fun read(input: JsonReader): JsonType = readExtension(input) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.hyperledger.identus.client.custom.adapters | ||
|
||
import com.google.gson.TypeAdapter | ||
import com.google.gson.stream.JsonReader | ||
import com.google.gson.stream.JsonWriter | ||
import org.hyperledger.identus.client.custom.readExtension | ||
import org.hyperledger.identus.client.custom.types.ServiceType | ||
import org.hyperledger.identus.client.custom.writeExtension | ||
|
||
class ServiceTypeAdapter : TypeAdapter<ServiceType>() { | ||
override fun write(out: JsonWriter, value: ServiceType) = writeExtension(out, value) | ||
override fun read(input: JsonReader): ServiceType = readExtension(input) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.hyperledger.identus.client.custom.types | ||
|
||
import com.google.gson.annotations.JsonAdapter | ||
import org.hyperledger.identus.client.custom.adapters.JsonTypeAdapter | ||
import org.hyperledger.identus.client.custom.types.base.ArrayType | ||
import org.hyperledger.identus.client.custom.types.base.BoolType | ||
import org.hyperledger.identus.client.custom.types.base.GenericObjectType | ||
import org.hyperledger.identus.client.custom.types.base.NullType | ||
import org.hyperledger.identus.client.custom.types.base.NumberType | ||
import org.hyperledger.identus.client.custom.types.base.StringType | ||
|
||
@JsonAdapter(JsonTypeAdapter::class) | ||
class JsonType(override var value: Any?) : ArrayType, BoolType, NullType, NumberType, GenericObjectType, StringType |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.hyperledger.identus.client.custom.types | ||
|
||
import com.google.gson.annotations.JsonAdapter | ||
import org.hyperledger.identus.client.custom.adapters.ServiceTypeAdapter | ||
import org.hyperledger.identus.client.custom.types.base.ArrayType | ||
import org.hyperledger.identus.client.custom.types.base.StringType | ||
|
||
@JsonAdapter(ServiceTypeAdapter::class) | ||
class ServiceType(override var value: Any?) : ArrayType, StringType |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
import org.hyperledger.identus.client.custom.convert | ||
|
||
interface ArrayType : BaseType { | ||
fun asArray(): kotlin.collections.List<Any>? { | ||
return convert() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
import com.google.gson.annotations.JsonAdapter | ||
import org.hyperledger.identus.client.custom.adapters.JsonTypeAdapter | ||
|
||
@JsonAdapter(JsonTypeAdapter::class) | ||
interface BaseType { | ||
var value: Any? | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
interface BoolType : BaseType { | ||
fun asBool(): Boolean { | ||
return value as Boolean | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
import com.google.gson.Gson | ||
import kotlin.reflect.KClass | ||
|
||
interface GenericObjectType : BaseType { | ||
fun <T : Any> asObject(clazz: KClass<T>): T { | ||
val json = Gson().toJson(value) | ||
return Gson().fromJson(json, clazz.java) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
interface NullType : BaseType { | ||
override var value: Any? | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
interface NumberType : BaseType { | ||
fun asNumber(): kotlin.Number { | ||
return value as kotlin.Number | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.hyperledger.identus.client.custom.types.base | ||
|
||
import org.hyperledger.identus.client.custom.convert | ||
|
||
interface StringType : BaseType { | ||
fun asString(): kotlin.String? { | ||
return convert() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm probably not understanding something, but I thought initially that you will override
Service(id, type, serviceEndpoint)
type here, should not you also add it in this file as well?