Open carlos-verdes opened 2 years ago
@carlos-verdes BEWARE: Default implementations for Map
are vulnerable. Possible mitigations are limiting a number of accepted key-value pairs during parsing or using implementations which are safer: TreeMap
, java.util.HashMap
with Map
adapter, etc.
Map is only an example to show the expected output, it's obviously not a good practice to load full document in memory
I end up with something like that (but there are lot of things to improve:
given credentialsDecoder: JsonDecoder[Credentials] = new JsonDecoder[Credentials]:
override def unsafeDecode(trace: List[JsonError], in: RetractReader): Credentials =
Lexer.char(trace, in, '{')
Lexer.firstField(trace, in)
val firstKey = Lexer.string(trace, in).toString
Lexer.char(trace, in, ':')
if firstKey == JWT then Token(Lexer.string(trace, in).toString)
else if firstKey == USERNAME then
val username = Lexer.string(trace, in).toString
if Lexer.nextField(trace, in) && Lexer.string(trace, in).toString == PASSWORD then
Lexer.char(trace, in, ':')
val password = Lexer.string(trace, in).toString
UserPassword(username, password)
else unsafeDecodeMissing(trace)
else if firstKey == PASSWORD then
val password = Lexer.string(trace, in).toString
if Lexer.nextField(trace, in) && Lexer.string(trace, in).toString == USERNAME then
Lexer.char(trace, in, ':')
val username = Lexer.string(trace, in).toString
UserPassword(username, password)
else unsafeDecodeMissing(trace)
else unsafeDecodeMissing(trace)
What if the subclasses have the same fields?
I made something similar by having explicit case class for {"username": "$username", "password": "$password"}
much simpler IMO
@wadouk this doesn't cover the need to gather credentials with different models In my example you can login using user/password or using a token, this is a sum type that can be used later in the code with pattern matching
The idea is to do something like "getCredentialsFromJson" without the need of discriminator fields that are not part of the business domain
@gcnyin in the case there are same fields normally you use the first which match, so the general rule is to put more specific cases first and more generic ones at the end... but in a business domain it's unlikely to happen, normally you can solve the problem with optional fields
@carlos-verdes haven´t seen the token case. As you mention, using options would to the trick. no need of discriminator. Use a case cass with options for json codec Cretendials(username: Option[String], password: Option[String], token: Option[String])
with transformOrFail
and pattern match or <*>
to build your business model Credentials
if none, a codec error.
That would be a workaround option but it just shows a lack of a feature don't you think?
Taking an enum like this:
I need to be able to parse the next 2 jsons:
Taking as input the field names of each option we can implement something like this (manual approach):
Which pass the next test:
I think this implementation can be done getting the definition of each
case
and trying to match with the json provided.Something like this on Circe: https://circe.github.io/circe/codecs/adt.html