Cómo crear una aplicación SpringBoot con Scala

1
5349

En este tutorial se mostrará como crear una API REST desde 0 uniendo dos herramientas de programación tan versátiles como el lenguaje Scala y el framework Spring.

Índice de contenidos


1. Introducción

Uno de los pilares de diseño de Scala es la interoperabilidad total y directa con Java. Puesto que la sintaxis de Scala es un superconjunto de la sintaxis de Java esto permite que el código Scala pueda hacer uso de componentes de Java en su totalidad ya sea accediendo a campos, llamando a métodos, incluso estableciendo relaciones más complejas como la herencia de clases, o el uso de los tipos ya existentes, haciendo que Scala pueda trabajar con las librerías y/o frameworks ya existentes de Java de una manera sencilla y natural.

En este tutorial se plantea un caso de uso de esta capacidad, en concreto la integración Scala – Spring Framework, a través de la implementación de una API Rest.

A continuación se detallarán todos los aspectos necesarios para poner en marcha la aplicación como son la configuración del entorno, la declaración de dependencias y finalmente el código.


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro Retina 15′ (3 Ghz Intel Core i7, 16GB DDR3).
  • Sistema Operativo: Mac OS X 10.13.3
  • Entorno de desarrollo: IntelliJ IDEA 2017.3.4 (Ultimate Edition)
  • Scala plugin for IntelliJ
  • SBT plugin for IntelliJ
  • SBT 1.1.0
  • Scala 2.14.4


3. Preparar el entorno

El primer paso de este tutorial consiste en comprobar que se dispone del entorno adecuado de cara a poder proceder correctamente.

En este tutorial se hará uso del entorno de desarrollo IntelliJ junto con el plugin Scala plugin for IntelliJ que nos permitirá trabajar con el lenguaje, ya que no dispone de compatibilidad con Scala en su versión out-of-the-box.

Además se hará uso del plugin SBT for IntelliJ para facilitar el trabajo con la herramienta de construcción de los proyectos Scala.


4. Configuración del proyecto

La configuración base del proyecto se basa en el generador automático que establece IntelliJ para aplicaciones de tipo SBT a través del plugin homónimo.

En las imágenes que se muestran a continuación se puede observar el proceso de creación.

A continuación se configuran todos los aspectos necesarios para proceder con la construcción del proyecto en el fichero build.sbt, en este caso solo es necesario establecer las dependencias externas (spring-boot-starter-web).

build.sbt
name := "ScalaSpringRest"

version := "0.1"

scalaVersion := "2.12.4"

libraryDependencies ++= Seq(

  "org.springframework.boot" % "spring-boot-starter-web" % "1.5.10.RELEASE"

)

Por último estableceremos una serie de propiedades de Spring a través de en un fichero «application.properties».

application.properties
server.port=9000

scalaspringrest.properties.greeting1=You're welcome!!!
scalaspringrest.properties.greeting2=Hi!
scalaspringrest.properties.greeting3=Hello
scalaspringrest.properties.greeting4=What's up!!


5. Detalles de implementación

A continuación se repasaran los aspectos de implementación necesarios para crear la aplicación.

El primer punto consiste en crear una aplicación, para ello se hace uso de las dos herramientas que aportan, por un lado SpringBoot y por otro lado Scala:

Application.scala
package com.adictos.scalaspringrest

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
class Application

object Application extends App {
  SpringApplication.run(classOf[Application], args:_*)
}

La anotación @SpringBootApplication auna tres anotaciones como son @Configuration, @EnableAutoConfiguration, @ComponentScan, nos permiten arrancar el contexto de Spring, y todas las funcionalidades adicionales para arrancar una aplicación Spring de manera rápida y sencilla.

Por otro lado, Scala nos permite crear aplicaciones ejecutables mediante la extensión del trait App.
No es necesario sobreescribir el método main del trait App puesto que el cuerpo de la clase se convierte en el código a ejecutar.

En el interior de nuestro objeto Application realizamos la llamada a SpringApplication.run, el método que se encargará de arrancar todo el framework de Spring a través de los siguientes pasos:

  • Crear una instancia del ApplicationContext.
  • Registrar un CommandLinePropertySource para exponer los argumentos de la línea de comandos como propiedades de Spring.
  • Recargar el contexto de aplicación cargando todos los beans declarados.
  • Disparar los CommandLineRunner beans que existan en el ámbito de la aplicación.
Controller.scala
package com.adictos.scalaspringrest

import com.adictos.scalaspringrest.model.Greeting
import com.adictos.scalaspringrest.services.GreetingService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.{RequestMapping, RequestMethod, RestController}

@RestController
class Controller @Autowired()(greetingService: GreetingService) {

    @RequestMapping(value = Array("/greeting"), method = Array(RequestMethod.GET))
    def greeting: Greeting = greetingService.get

}

En el anterior snippet de código se presenta la declaración de un controlador rest (mediante @RestController) que responderá a las peticiones asociadas al método GET sobre el endpoint «http://url-hos/greeting».

Este controlador recibe como parámetro un servicio (GreetingService) que se encarga de generar el saludo que se dará como respuesta, con la anotación @RequestMapping establecemos la configuración relativa al controlador como puede ser el endpoint (value = Array(«/greeting»)) y al verbo HTTP que debe utilizarse para consumir el servicio (method = Array(RequestMethod.GET)).

GreetingService.scala
package com.adictos.scalaspringrest.services

import com.adictos.scalaspringrest.PropertiesBundle
import com.adictos.scalaspringrest.model.Greeting
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service

@Service
class GreetingService @Autowired()(properties: PropertiesBundle) {

    def get: Greeting = Greeting(s"Hey!, ${properties.greeting1}")

}   

El servicio se define como una clase con el método get, y se establece la anotación @Service, especialización de la anotación @Component que permite la autodetección, por parte de las implementaciones, a través del escaneado del classpath.

@Service debería estar reservado para clases que ofrecen una operación sin un estado encapsulado.

Además se establcee una relación de dependencia con una instancia de PropertiesBundle de la cual se obtendran los mensajes y cuya implementación se muestra a continuación:

PropertiesBundle.scala
package com.adictos.scalaspringrest

import javax.validation.constraints.NotNull
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component

import scala.beans.BeanProperty

@Component
@ConfigurationProperties("scalaspringrest.properties")
class PropertiesBundle {

    @BeanProperty @NotNull var greeting1: String = _
    @BeanProperty @NotNull var greeting2: String = _
    @BeanProperty @NotNull var greeting3: String = _
    @BeanProperty @NotNull var greeting4: String = _

}        

La clase PropertiesBundle mantendrá los valores establecidos a través del fichero de propiedades application.properties.

La anotación @Component marcará la clase como un Bean gestionado por el ApplicationContext de Spring, estableciendo así la clase como un candidato de cara a la auto-detección.

La anotación @ConfigurationProperties nos permite acceder a configuración externa, validarla y asociarla a los campos de una clase. En el código expuesto se hará uso de las propiedades que se han definido en el fichero application.properties bajo el sufijo «scalaspringrest.properties».

Para poder establecer dichos valores será necesario que nuestra clase exponga métodos que permitan al framework modificar el contenido de dichos campos, métodos getter y setter.

Para estas situaciones Scala aporta una anotación que permite generar dichos métodos (getter/setter) @BeanProperty.

Además establecemos la anotación @NotNull para asegurarnos de que dichos campos tengan valores.

package.scala
package com.adictos.scalaspringrest

import scala.beans.BeanProperty

package object model {

  class Greeting(@BeanProperty var body: String)

}

Declaración de un modelo básico de saludo que cuenta con un body que mantendrá el cuerpo del mensaje.

El proceso de serialización/deserialización JSON estará gestionado a través de Jackson, que se incluye por defecto en el spring-boot-starter seleccionado, ello implica cumplir con ciertas condiciones, siendo la principal que los objetos que van a ser serializados/desarializados cumplan con la definición de Java Bean, o al menos, que dispongan de los métodos setter y getter.

En este caso se ha dado una definición en el modelo de Greeting como una case class, aportando una serie de ventajas frente a las clases como la posibilidad de comparar por estructura y no por referencia o la capacidad de copiar crear copias de una instancia, sin embargo no dispone de los métodos getter/setter, para lo que establecemos de nuevo la anotación @BeanProperty


6. Conclusiones

Como se ha demostrado a lo largo de este tutorial crear aplicaciones Scala haciendo uso del Framework Spring es tan factible como sencillo gracias a la interoperabilidad directa entre Scala y Java.

Para crear la aplicación tan solo ha sido necesario seguir los mismos pasos que son necesarios para declarar una aplicación Spring en Java, haciendo uso de la sintaxis de Scala y utilizar algunas de las herramientas de las que Scala nos provee out-of-the-box.

1 COMENTARIO

  1. Tiene un error el código, en el object model falta la palabra case, asi:

    case class Greeting(@BeanProperty var body: String)

    Para que el código compile.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad