我目前正在开发一个Scala应用程序,该应用程序利用Spring-Boot和Swagger发送和接收REST调用。
Swagger和Spring-Boot是纯Java项目,与Scala的兼容性有限,但是我似乎找到了解决此问题的方法。
由于Spring-Boot和Swagger将请求作为Java对象处理(需要使用setter和getter才能工作),因此,我必须将请求视为Java对象,然后将请求转换为更高版本。这是我所做的非常简化的版本:
case class ParamsAsJava(includeMovies: java.lang.Boolean = java.lang.Boolean.FALSE, includeTvShows: java.lang.Boolean = java.lang.Boolean.FALSE) {
def toScala(): Params = {
Params(
includeMovies = convertToScala(includeMovies),
includeTvShows = convertToScala(includeTvShows)
)
}
private def convertToScala(test: java.lang.Boolean): Boolean
= if (test == null) false else test.booleanValue
}
case class Params(includeMovies: Boolean = false, includeTvShows: Boolean = false)
object Application extends App {
val test1 = ParamsAsJava(java.lang.Boolean.FALSE, java.lang.Boolean.TRUE).toScala
val test2 = ParamsAsJava(java.lang.Boolean.TRUE, java.lang.Boolean.TRUE).toScala
val test3 = ParamsAsJava().toScala
val test4 = ParamsAsJava(null, null).toScala
val test5 = ParamsAsJava(null, java.lang.Boolean.TRUE).toScala
println(s"Test 1 = $test1")
println(s"Test 2 = $test2")
println(s"Test 3 = $test3")
println(s"Test 4 = $test4")
println(s"Test 5 = $test5")
}
输出
测试1 = Params(false,true)
测试2 = Params(true,true)
测试3 = Params(false,false)
测试4 = Params(false,false)
测试5 = Params(false,true)
好的...我的问题是:
是否有更简单,更易读的方式来实现这一目标? 我是否必须每次都调用ParamsAsJava.toScala还是有一些很棒 Scala的方式来实现?
答案 0 :(得分:3)
默认情况下,Spring使用jackson-mapper将JSON请求主体解码为Java类,并将Java类编码为JSON响应。
或者,您可以告诉Spring使用ScalaObjectMapper,它对scala数据类非常有效。
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.12</artifactId>
<version>2.9.7</version>
</dependency>
然后将Spring配置为在WebMvcConfigurerAdapter
中使用ScalaObjectMapper。例子;
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)
}
应该是这样,现在您可以使用Spring端点定义中的纯scala数据类。例子
@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)
}
答案 1 :(得分:2)
您不需要每次都写出java.lang.blah
ParamsAsJava(java.lang.Boolean.FALSE, java.lang.Boolean.TRUE)
只需使用
ParamsAsJava(false, true)
相反。自动装箱还没有到位。
要摆脱toScala
,请在Params
伴随对象中定义一个隐式转换:
object Params {
implicit def params_j2s(p: ParamsAsJava): Params = p.toScala()
}
现在您可以写:
val test1: Params = ParamsAsJava(true, false)
当然,如果您不是在真空中定义此变量,而是将其传递给方法,则会自动推断出正确的类型,并且将隐式转换对象。
无需在()
中使用括号def toScala()
,该方法没有副作用。
答案 2 :(得分:1)