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
You don't need to write out java.lang.blah
every time in
ParamsAsJava(java.lang.Boolean.FALSE, java.lang.Boolean.TRUE)
Just use
ParamsAsJava(false, true)
instead. Autoboxing hasn't gone anywhere.
to get rid of toScala
, define an implicit conversion in Params
companion object:
object Params {
implicit def params_j2s(p: ParamsAsJava): Params = p.toScala()
}
now you can write:
val test1: Params = ParamsAsJava(true, false)
and, of course, if you don't define this variable in vacuum, but pass it to a method instead, the right type will be inferred automatically, and the object will be converted implicitly.
No need to use parens ()
in def toScala()
, the method has no side effects.
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.
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.12</artifactId>
<version>2.9.7</version>
</dependency>
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)
}
I used scala.Boolean box and unbox methods.