Конвертировать java.lang.Boolean в Scala Boolean - PullRequest
0 голосов
/ 30 сентября 2018

В настоящее время я работаю над приложением Scala, которое использует Spring-Boot и Swagger для отправки и получения REST-вызовов.

Swagger и Spring-Boot являются чистыми Java-проектами и имеют ограниченную совместимость со Scala, но я, кажется, нашел обходной путь в отношении проблемы.

Поскольку Spring-Boot и Swagger обрабатывают запросы как объекты Java (для работы которых нужны установщики и получатели), мне придется обработать запрос как объект 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= Параметры (ложь, истина)

тест 2 = параметры (истина, истина)

тест 3 = параметры (ложь, ложь)

тест 4 = параметры (ложь,false)

Test 5 = Params (false, true)


ОК ... мой вопрос:

ЕстьЕсть ли более простой и понятный способ достижения этого?Должен ли я каждый раз вызывать ParamsAsJava.toScala или есть какой-нибудь потрясающий способ Scala сделать это?

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

По умолчанию 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 на использование ScalaObjectMapper в WebMvcConfigurerAdapter.Пример;

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)
}

Так и должно быть, теперь вы можете использовать чистые классы данных scala из определения конечной точки Spring.Пример

@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)
}
0 голосов
/ 30 сентября 2018
  1. Вам не нужно выписывать java.lang.blah каждый раз, когда

    ParamsAsJava(java.lang.Boolean.FALSE, java.lang.Boolean.TRUE)
    

    Просто используйте

    ParamsAsJava(false, true)
    

    .Автобокс никуда не делся.

  2. , чтобы избавиться от toScala, определите неявное преобразование в Params сопутствующем объекте:

    object Params {
      implicit def params_j2s(p: ParamsAsJava): Params = p.toScala()
    }
    

    теперь вы можетенапишите:

    val test1: Params = ParamsAsJava(true, false)
    

    и, конечно, если вы не определяете эту переменную в вакууме, а вместо этого передаете ее методу, правильный тип будет выведен автоматически, и объект будет преобразован неявно.

  3. Нет необходимости использовать парэнс () в def toScala(), метод не имеет побочных эффектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...