Jackson Integration

Finatra improves on the already excellent jackson-module-scala for JSON support. Note that the finatra-jackson library can be used outside of Finatra as a replacement for the jackson-module-scala or jerkson.

Features

  • Usable outside of the Finatra framework.
  • FinatraObjectMapper which provides additional Scala friendly methods not found in the ScalaObjectMapper.
  • Guice module for injecting the FinatraObjectMapper with support for customization e.g. snake_case vs. camelCase.
  • Custom case class deserializer which overcomes limitations in jackson-module-scala.
  • Support for case class validations which accumulate errors (without failing fast) during JSON parsing.
  • Integration with Finatra HTTP routing to support binding and validation of query params, route params, and headers.
  • Utilities for comparing JSON.
  • Experimental support for iterator-based JSON stream parsing.

Configuration

The default configuration of Jackson is provided by the FinatraObjectMapper.

The following Jackson integrations are provided by default:

Customization

To override defaults or provide other config options, specify your own module (usually extending FinatraJacksonModule).

class Server extends HttpServer {
  override def jacksonModule = CustomJacksonModule
  ...
}

For an example of extending the FinatraJacksonModule see Adding a Custom Serializer or Deserializer.

See the Framework Modules section for more information on customizing server framework modules.

Adding a Custom Serializer or Deserializer

To register a custom serializer or deserializer:

  • Create a module that extends the com.fasterxml.jackson.databind.module.SimpleModule. You can choose to instantiate an anonymous module but this is not recommended as it is not re-usable.
  • Add your serializer or deserializer using the SimpleModule#addSerializer or SimpleModule#addDeserializer methods in your module.
  • In your custom FinatraJacksonModule extension, add the module to list of additional jackson modules by overriding the additionalJacksonModules.
  • Set your custom FinatraJacksonModule extension as the framework Jackson module as detailed above in the Customization section.

For example,

// custom deserializer
class FooDeserializer extends com.fasterxml.jackson.databind.JsonDeserializer[Foo] {
  override def deserialize(...)
}

// Jackson SimpleModule for custom deserializer
class FooDeserializerModule extends com.fasterxml.jackson.databind.module.SimpleModule {
  addDeserializer(FooDeserializer)
}

// custom FinatraJacksonModule which replace the framework module
object CustomJacksonModule extends FinatraJacksonModule {
  override val additionalJacksonModules = Seq(
    new SimpleModule {
      addSerializer(LocalDateParser)
    },
    new FooDeserializerModule)

  override val serializationInclusion = Include.NON_EMPTY

  override val propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE

  override def additionalMapperConfiguration(mapper: ObjectMapper) {
    mapper.configure(Feature.WRITE_NUMBERS_AS_STRINGS, true)
  }
}

For more information see the Jackson documentation for Custom Serializer or Custom De-serializers.

Improved case class deserializer

Finatra provides a custom case class deserializer which overcomes limitations in jackson-scala-module:

  • Throws a JsonException when required fields are missing from the parsed JSON.
  • Use default values when fields are missing in the incoming JSON.
  • Properly deserialize a Seq[Long] (see https://github.com/FasterXML/jackson-module-scala/issues/62).
  • Support “wrapped values” using WrappedValue (needed since jackson-module-scala does not support the @JsonCreator annotation).
  • Support for accumulating JSON parsing errors (instead of failing fast).
  • Support for field and method level validations which also accumulate errors.

Java Enums

We recommend the use of Java Enums for representing enumerations since they integrate well with Jackson’s ObjectMapper and now have exhaustiveness checking as of Scala 2.10.

The following Jackson annotations may be useful when working with Enums:

  • @JsonCreator can be used for a custom fromString method
  • @JsonValue can be used for on an overridden toString method