I am currently working on a Scala application which utilizes Spring-Boot and Swagger to send & receive REST-calls.
Swagger and Spring-Boot are pure Java-projects an
By default Spring uses jackson-mapper to decode JSON request body to Java classes and encode Java classes to JSON response.
Alternatively you can tell Spring to use ScalaObjectMapper which works well for scala data classes.
com.fasterxml.jackson.module
jackson-module-scala_2.12
2.9.7
Then configure Spring to use ScalaObjectMapper in WebMvcConfigurerAdapter
. Example;
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import scala.collection.JavaConverters._
@EnableWebMvc
@Configuration
@PropertySource(Array("classpath:config/default.properties"))
@ComponentScan(Array(
"com.prayagupd"
))
@Order(HIGHEST_PRECEDENCE)
class MyAppConfig extends WebMvcConfigurerAdapter {
override def extendMessageConverters(converters: java.util.List[HttpMessageConverter[_]]): Unit = {
val encodeDecoderOpt = converters.asScala.collectFirst { case p: MappingJackson2HttpMessageConverter => p }
val jacksonConverter = encodeDecoderOpt.getOrElse(new MappingJackson2HttpMessageConverter)
jacksonConverter.setObjectMapper(Config.objectMapper)
if (encodeDecoderOpt.isEmpty) // because converters is mutable
converters.add(jacksonConverter)
}
}
object Config {
@Bean
def objectMapper: ObjectMapper = {
new ObjectMapper() with ScalaObjectMapper
}.registerModule(DefaultScalaModule)
}
That should be it, now you can use pure scala data classes from Spring endpoint definition. Example
@RestController
@CrossOrigin(origins = Array("*"))
@RequestMapping(value = Array("/"))
class MyController @Autowired()(implicit val jacksonObjectMapper: ObjectMapper) {
import MyController._
@Async
@RequestMapping(value = Array("/talk"), method = Array(RequestMethod.POST), consumes = Array(MediaType.APPLICATION_JSON_VALUE), produces = Array(MediaType.APPLICATION_JSON_VALUE))
def talk(@RequestBody request: MyRequest): MyResponse = {
// goes here
}
}
//expose these in client jar if you want
object MyController {
final case class MyRequest(includeMovies: Boolean, includeTvShows: Boolean, somethingElse: List[String])
final case class MyResponse(whatever: String)
}