-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[kotlin] better oneOf, anyOf support (#18382)
* add validteJsonElement * add oneOf support * various fixes, add tests * minor fixes * minor fixes * update data class * remove comments * array support, add test * update api client constructor * add anyOf support * add new files * fix merge * update * update * update * update
- Loading branch information
Showing
648 changed files
with
8,996 additions
and
6,249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
243 changes: 243 additions & 0 deletions
243
modules/openapi-generator/src/main/resources/kotlin-client/anyof_class.mustache
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
{{^multiplatform}} | ||
{{#gson}} | ||
{{#generateOneOfAnyOfWrappers}} | ||
import com.google.gson.Gson | ||
import com.google.gson.JsonElement | ||
import com.google.gson.TypeAdapter | ||
import com.google.gson.TypeAdapterFactory | ||
import com.google.gson.reflect.TypeToken | ||
import com.google.gson.stream.JsonReader | ||
import com.google.gson.stream.JsonWriter | ||
import com.google.gson.annotations.JsonAdapter | ||
{{/generateOneOfAnyOfWrappers}} | ||
import com.google.gson.annotations.SerializedName | ||
{{/gson}} | ||
{{#moshi}} | ||
import com.squareup.moshi.Json | ||
import com.squareup.moshi.JsonClass | ||
{{/moshi}} | ||
{{#jackson}} | ||
{{#enumUnknownDefaultCase}} | ||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue | ||
{{/enumUnknownDefaultCase}} | ||
import com.fasterxml.jackson.annotation.JsonProperty | ||
{{#discriminator}} | ||
import com.fasterxml.jackson.annotation.JsonSubTypes | ||
import com.fasterxml.jackson.annotation.JsonTypeInfo | ||
{{/discriminator}} | ||
{{/jackson}} | ||
{{#kotlinx_serialization}} | ||
import {{#serializableModel}}kotlinx.serialization.Serializable as KSerializable{{/serializableModel}}{{^serializableModel}}kotlinx.serialization.Serializable{{/serializableModel}} | ||
import kotlinx.serialization.SerialName | ||
import kotlinx.serialization.Contextual | ||
{{#enumUnknownDefaultCase}} | ||
import kotlinx.serialization.KSerializer | ||
import kotlinx.serialization.Serializer | ||
import kotlinx.serialization.builtins.serializer | ||
import kotlinx.serialization.encoding.Decoder | ||
import kotlinx.serialization.encoding.Encoder | ||
{{/enumUnknownDefaultCase}} | ||
{{#hasEnums}} | ||
{{/hasEnums}} | ||
{{/kotlinx_serialization}} | ||
{{#parcelizeModels}} | ||
import android.os.Parcelable | ||
import kotlinx.parcelize.Parcelize | ||
{{/parcelizeModels}} | ||
{{/multiplatform}} | ||
{{#multiplatform}} | ||
import kotlinx.serialization.* | ||
import kotlinx.serialization.descriptors.* | ||
import kotlinx.serialization.encoding.* | ||
{{/multiplatform}} | ||
{{#serializableModel}} | ||
import java.io.Serializable | ||
{{/serializableModel}} | ||
{{#generateRoomModels}} | ||
import {{roomModelPackage}}.{{classname}}RoomModel | ||
import {{packageName}}.infrastructure.ITransformForStorage | ||
{{/generateRoomModels}} | ||
import java.io.IOException | ||
|
||
/** | ||
* {{{description}}} | ||
* | ||
*/ | ||
{{#parcelizeModels}} | ||
@Parcelize | ||
{{/parcelizeModels}} | ||
{{#multiplatform}}{{^discriminator}}@Serializable{{/discriminator}}{{/multiplatform}}{{#kotlinx_serialization}}{{#serializableModel}}@KSerializable{{/serializableModel}}{{^serializableModel}}@Serializable{{/serializableModel}}{{/kotlinx_serialization}}{{#moshi}}{{#moshiCodeGen}}@JsonClass(generateAdapter = true){{/moshiCodeGen}}{{/moshi}}{{#jackson}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{/jackson}} | ||
{{#isDeprecated}} | ||
@Deprecated(message = "This schema is deprecated.") | ||
{{/isDeprecated}} | ||
{{>additionalModelTypeAnnotations}} | ||
{{#nonPublicApi}}internal {{/nonPublicApi}}data class {{classname}}(var actualInstance: Any? = null) { | ||
class CustomTypeAdapterFactory : TypeAdapterFactory { | ||
override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? { | ||
if (!{{classname}}::class.java.isAssignableFrom(type.rawType)) { | ||
return null // this class only serializes '{{classname}}' and its subtypes | ||
} | ||
val elementAdapter = gson.getAdapter(JsonElement::class.java) | ||
{{#composedSchemas}} | ||
{{#anyOf}} | ||
{{^isArray}} | ||
{{^vendorExtensions.x-duplicated-data-type}} | ||
val adapter{{{dataType}}} = gson.getDelegateAdapter(this, TypeToken.get({{{dataType}}}::class.java)) | ||
{{/vendorExtensions.x-duplicated-data-type}} | ||
{{/isArray}} | ||
{{#isArray}} | ||
@Suppress("UNCHECKED_CAST") | ||
val adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} = gson.getDelegateAdapter(this, TypeToken.get(object : TypeToken<{{{dataType}}}>() {}.type)) as TypeAdapter<{{{dataType}}}> | ||
{{/isArray}} | ||
{{/anyOf}} | ||
{{/composedSchemas}} | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
return object : TypeAdapter<{{classname}}?>() { | ||
@Throws(IOException::class) | ||
override fun write(out: JsonWriter,value: {{classname}}?) { | ||
if (value?.actualInstance == null) { | ||
elementAdapter.write(out, null) | ||
return | ||
} | ||
|
||
{{#composedSchemas}} | ||
{{#anyOf}} | ||
{{^vendorExtensions.x-duplicated-data-type}} | ||
// check if the actual instance is of the type `{{{dataType}}}` | ||
if (value.actualInstance is {{#isArray}}List<*>{{/isArray}}{{^isArray}}{{{dataType}}}{{/isArray}}) { | ||
{{#isPrimitiveType}} | ||
val primitive = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}.toJsonTree(value.actualInstance as {{{dataType}}}?).getAsJsonPrimitive() | ||
elementAdapter.write(out, primitive) | ||
return | ||
{{/isPrimitiveType}} | ||
{{^isPrimitiveType}} | ||
{{#isArray}} | ||
List<?> list = (List<?>) value.actualInstance | ||
if (list.get(0) is {{{items.dataType}}}) { | ||
val array = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}}.toJsonTree(value.actualInstance as {{{dataType}}}?).getAsJsonArray() | ||
elementAdapter.write(out, array) | ||
return | ||
} | ||
{{/isArray}} | ||
{{/isPrimitiveType}} | ||
{{^isArray}} | ||
{{^isPrimitiveType}} | ||
val element = adapter{{{dataType}}}.toJsonTree(value.actualInstance as {{{dataType}}}?) | ||
elementAdapter.write(out, element) | ||
return | ||
{{/isPrimitiveType}} | ||
{{/isArray}} | ||
} | ||
{{/vendorExtensions.x-duplicated-data-type}} | ||
{{/anyOf}} | ||
{{/composedSchemas}} | ||
throw IOException("Failed to serialize as the type doesn't match anyOf schemas: {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}") | ||
} | ||
|
||
@Throws(IOException::class) | ||
override fun read(jsonReader: JsonReader): {{classname}} { | ||
val jsonElement = elementAdapter.read(jsonReader) | ||
val errorMessages = ArrayList<String>() | ||
var actualAdapter: TypeAdapter<*> | ||
val ret = {{classname}}() | ||
|
||
{{#composedSchemas}} | ||
{{#anyOf}} | ||
{{^vendorExtensions.x-duplicated-data-type}} | ||
{{^hasVars}} | ||
// deserialize {{{dataType}}} | ||
try { | ||
// validate the JSON object to see if any exception is thrown | ||
{{^isArray}} | ||
{{#isNumber}} | ||
require(jsonElement.getAsJsonPrimitive().isNumber()) { | ||
String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString()) | ||
} | ||
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} | ||
ret.actualInstance = actualAdapter.fromJsonTree(jsonElement) | ||
return ret | ||
{{/isNumber}} | ||
{{^isNumber}} | ||
{{#isPrimitiveType}} | ||
require(jsonElement.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}()) { | ||
String.format("Expected json element to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString()) | ||
} | ||
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} | ||
ret.actualInstance = actualAdapter.fromJsonTree(jsonElement) | ||
return ret | ||
{{/isPrimitiveType}} | ||
{{/isNumber}} | ||
{{^isNumber}} | ||
{{^isPrimitiveType}} | ||
{{{dataType}}}.validateJsonElement(jsonElement) | ||
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} | ||
ret.actualInstance = actualAdapter.fromJsonTree(jsonElement) | ||
return ret | ||
{{/isPrimitiveType}} | ||
{{/isNumber}} | ||
{{/isArray}} | ||
{{#isArray}} | ||
require(jsonElement.isJsonArray) { | ||
String.format("Expected json element to be a array type in the JSON string but got `%s`", jsonElement.toString()) | ||
} | ||
|
||
// validate array items | ||
for(element in jsonElement.getAsJsonArray()) { | ||
{{#items}} | ||
{{#isNumber}} | ||
require(jsonElement.getAsJsonPrimitive().isNumber) { | ||
String.format("Expected json element to be of type Number in the JSON string but got `%s`", jsonElement.toString()) | ||
} | ||
{{/isNumber}} | ||
{{^isNumber}} | ||
{{#isPrimitiveType}} | ||
require(element.getAsJsonPrimitive().is{{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}}) { | ||
String.format("Expected array items to be of type {{#isBoolean}}Boolean{{/isBoolean}}{{#isString}}String{{/isString}}{{^isString}}{{^isBoolean}}Number{{/isBoolean}}{{/isString}} in the JSON string but got `%s`", jsonElement.toString()) | ||
} | ||
{{/isPrimitiveType}} | ||
{{/isNumber}} | ||
{{^isNumber}} | ||
{{^isPrimitiveType}} | ||
{{{dataType}}}.validateJsonElement(element) | ||
{{/isPrimitiveType}} | ||
{{/isNumber}} | ||
{{/items}} | ||
} | ||
actualAdapter = adapter{{#sanitizeGeneric}}{{{dataType}}}{{/sanitizeGeneric}} | ||
ret.actualInstance = actualAdapter.fromJsonTree(jsonElement) | ||
return ret | ||
{{/isArray}} | ||
//log.log(Level.FINER, "Input data matches schema '{{{dataType}}}'") | ||
} catch (e: Exception) { | ||
// deserialization failed, continue | ||
errorMessages.add(String.format("Deserialization for {{{dataType}}} failed with `%s`.", e.message)) | ||
//log.log(Level.FINER, "Input data does not match schema '{{{dataType}}}'", e) | ||
} | ||
{{/hasVars}} | ||
{{#hasVars}} | ||
// deserialize {{{.}}} | ||
try { | ||
// validate the JSON object to see if any exception is thrown | ||
{{.}}.validateJsonElement(jsonElement) | ||
log.log(Level.FINER, "Input data matches schema '{{{.}}}'") | ||
actualAdapter = adapter{{.}} | ||
ret.actualInstance = actualAdapter.fromJsonTree(jsonElement) | ||
return ret | ||
} catch (e: Exception) { | ||
// deserialization failed, continue | ||
errorMessages.add(String.format("Deserialization for {{{.}}} failed with `%s`.", e.message)) | ||
//log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e) | ||
} | ||
{{/hasVars}} | ||
{{/vendorExtensions.x-duplicated-data-type}} | ||
{{/anyOf}} | ||
{{/composedSchemas}} | ||
|
||
throw IOException(String.format("Failed deserialization for {{classname}}: no schema match result. Detailed failure message for anyOf schemas: %s. JSON: %s", errorMessages, jsonElement.toString())) | ||
} | ||
}.nullSafe() as TypeAdapter<T> | ||
} | ||
} | ||
} |
Oops, something went wrong.