0

I'm currently rewriting one of our applications, which uses PostgreSQL and now should use Mongo.

The architecture is pretty simple

db => case class => rest api

we are using scala jackson for it and everything works fine, except for some minor annoyance and I'm just looking for the right approach.

consider this case class to understand my annoyance

case class Test(val id:String, val value:Any)

the value in our application can be a number or a string at this point, number either an Integer or a Double.

so when we receive JSON like this, from our legacy application:

{ id:"a",value:"test"}

it gets mapped correctly and results in the expected types of String, String.

But assuming the following:

{ id:"b", value:"1"}

we would like to have this mapped instead to String,Integer. But obviously jackson thinks it's a String and maps it to String, String.

Is there some transparent way todo this? My thinking, would be something like an interceptor for jackson would be nice, which simple tests

if type.isDouble == true return double value
else if type.isInteger == true return integer value
else return string value

so we would end up with

String,Double
String,Integer
String,String

in this example.

Obviously I can write a generic parser and bring the dataformat into the correct form beforehand, but I rather would have this done transparency, since we never know when user will submit the legacy JSON format, with this bug and so possibly corrupt the system.

thx

berlinguyinca
  • 803
  • 1
  • 9
  • 16
  • Well, "1" is a String and, since MongoDB supports [numeric types](https://docs.mongodb.org/manual/reference/bson-types/), if it is retrieving the document that way, you have a problem when inserting data, not only when reading. – marcospereira Feb 27 '16 at 21:00
  • correct, this is our legacy format, before mongo. So we automatically want to convert it, when a user submits the old format – berlinguyinca Feb 27 '16 at 21:02

1 Answers1

0

Ok it looks like this is easier than exspected, with writing a customer serializer and annotating our one field which needs it

Solution found here

actual example:

class NumberDeserializer extends JsonDeserializer[Any] {
  override def deserialize(jsonParser: JsonParser, deserializationContext: DeserializationContext): Any = {
    val jsonNode: JsonNode = jsonParser.getCodec.readTree(jsonParser)

    val content = jsonNode.textValue

    try {
      content.toInt
    } catch {
      case e: NumberFormatException => try {
        content.toDouble
      }
      catch {
        case e2: NumberFormatException => content
      }
    }
  }
}

usage:

case class Test(
                   @JsonDeserialize(using = classOf[NumberDeserializer])
                   value: Any
                     )
Community
  • 1
  • 1
berlinguyinca
  • 803
  • 1
  • 9
  • 16