I have to consume an API that uses different JSONs schemas as responses for the same endpoint
This are some examples of the API responses
{
"type": 0,
...
...
}
{
"type": 1,
"amount": 10
...
}
obs: when another_type key is missing amount is a number
{
"type": 1,
"another_type": "FEES",
"amount":
{
"original": 20.1,
"fees": [...]
...
...
}
}
obs: when another_type value is FEES amount is an object
{
"type": 1,
"another_type": "OTHER",
"amount":
{
"original": 20.1,
"other": [...]
...
...
}
}
obs: when another_type value is OTHER amount is an object (no equal to the previous one)
{
"type": 2,
...
...
}
So my first approach was to do this
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes(
JsonSubTypes.Type(value = Type0::class, name = "0"),
JsonSubTypes.Type(value = Type1Abstract::class, name = "1"),
JsonSubTypes.Type(value = Type2::class, name = "2")
)
abstract class Response(
@field:NotEmpty
@field:JsonProperty("type")
open val codeType: Int
)
I added Type1 as another abstract class like this
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "anotherType")
@JsonSubTypes(
JsonSubTypes.Type(value = Fees::class, name = "FEES"),
JsonSubTypes.Type(value = NoInfo::class, name = ""),
JsonSubTypes.Type(value = Other::class, name = "OTHER")
)
abstract class Type1Abstract(
@field:NotEmpty
@field:JsonProperty("another_type")
open val anotherType: String
)
But it did not work because type1 is an abstract class and it can't be initialized (obviously)
Is there any way to use the annotation JsonTypeInfo to resolve this problem?
I need to create one response class or another by checking 2 fields instead of only one
I tried to use @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, but the documentation says it does not check for the value of the keys which is important in this case
UPDATE: I modified type 1 class and it´s no more an abstract class. Also I added this field
@JsonProperty("amount")
val amount: Any
and this function
private fun ..parse..(another_type: String, amount: Any): BigDecimal {
return when (amount) {
is Double -> amount.toBigDecimal()
is LinkedHashMap<*, *> -> {
return when (another_type) {
"FEES" -> BigDecimal(amount["original"] as String)
"OTHER" -> BigDecimal(amount["original"] as String)
else -> throw ...
}
}
else -> {
throw ...
}
}
}
It's not the cleanest way but at it works and I can use it until I found a better solution