-
-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Description
openapi-generator version
7.13.0
OpenAPI declaration file content or url
"data": {
"type": "array",
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/LocationDataTemperature"
},
{
"$ref": "#/components/schemas/LocationDataWind"
}
]
}
},
"LocationDataTemperature": {
"type": "object",
"properties": {
"display": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": ["display"]
},
"LocationDataWind": {
"type": "object",
"properties": {
"display": {
"type": "array",
"items": {
"type": "object",
"properties": {
"FF_KMH": {
"type": "number",
"format": "float"
},
"FX_KMH": {
"type": "number",
"format": "float"
},
"DD_DEG": {
"type": "integer"
}
},
"required": ["FF_KMH", "FX_KMH", "DD_DEG"]
}
}
},
"required": ["display"]
Generation Details
Gradle Task
val meteoMapApiName = "MeteoMap"
val meteoMapApiGenPackage = "${project.android.namespace}.${meteoMapApiName.lowercase()}"
val generateMeteoMap by registering(GenerateTask::class) {
generatorName.set("kotlin")
inputSpec.set("${project.projectDir}/${meteoMapApiName.lowercase()}-api.json")
outputDir.set("$buildDir/generated")
packageName.set(meteoMapApiGenPackage)
apiPackage.set("$meteoMapApiGenPackage.api")
modelNamePrefix.set(meteoMapApiName)
invokerPackage.set("$meteoMapApiGenPackage.invoker")
modelPackage.set("$meteoMapApiGenPackage.model")
configOptions.set(apiConfigOptions)
additionalProperties.set(
mapOf(
"enumPropertyNaming" to "UPPERCASE",
"useCoroutines" to "true",
"moshiCodeGen" to "true",
"generateOneOfAnyOfWrappers" to "true",
"serializationLibrary" to "gson",
),
)
library.set("jvm-retrofit2")
}
Steps to reproduce
When we receive a response from the server and parse it's body, an exception is thrown. Because too many Type Adapters match with the result.
Example of a json response:
"display": [
{
"FF_KMH": 4,
"FX_KMH": 7,
"DD_DEG": 212,
"dateTime": "2025-05-15T00:00:00+00:00"
}
]
This should obviousley only match to the type of LocationDataWind according to the schema provided above, but also the type of LocationDataTemperature apparantly does match the result. So I checked out the LocationDataTemperature.validateJsonElement() function.
@Throws(IOException::class)
fun validateJsonElement(jsonElement: JsonElement?) {
if (jsonElement == null) {
require(openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null
String.format("The required field(s) %s in MeteoMapLocationDataTemperature is not found in the empty JSON string", MeteoMapLocationDataTemperature.openapiRequiredFields.toString())
}
}
// check to make sure all required properties/fields are present in the JSON string
for (requiredField in openapiRequiredFields) {
requireNotNull(jsonElement!!.getAsJsonObject()[requiredField]) {
String.format("The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())
}
}
val jsonObj = jsonElement!!.getAsJsonObject()
// ensure the required json array is present
requireNotNull(jsonObj["display"]) {
"Expected the field `display` to be an array in the JSON string but got `null`"
}
require(jsonObj["display"].isJsonArray()) {
String.format("Expected the field `display` to be an array in the JSON string but got `%s`", jsonObj["display"].toString())
}
}
It looks like the validate function here only checks if an array is present and then declares the json as valid. It does not check if the items inside the array are actual strings. This check is just simply missing. In the LocationDataWind.validateJsonElement() function there is such a check implemented:
for (i in 0 until jsonObj.getAsJsonArray("display").size()) {
MeteoMapLocationDataWindDisplayInner.validateJsonElement(jsonObj.getAsJsonArray("display").get(i))
}
Suggest a fix
If there is a list of strings, the validateJsonElement() should also contain a check that all elements inside the array are in fact strings. This prevents false matches in a oneOf schema declaration.