Aprende

Aprende sobre la última tecnología.

Construye

Da rienda suelta a tus conocimientos y construye!

Comparte

Que más gente lo aproveche para mejorar!
 

Servicios RESTful con Scala via Spring

martes, 11 de agosto de 2015

El objetivo final de esta entrada será que el lector pueda implementar servicios REST usando Scala en la operatoria y problemática de los servicios y Spring como transporte de los mismos. Recomendamos sino tiene conocimientos de Restful con Spring la lectura de la anterior entrada de Spring en este mismo blog Restful con spring.

En alguna entrada anterior he mencionado el uso de sbt  y de mi preferencia de no usarle en determinadas situaciones, esta es una de ellas, Spring con Scala, aunque tengo que reconocer que los de http://pivotallabs.com han hecho un trabajo interesante con ello. Recomiendo ver la siguiente prueba http://pivotallabs.com/spring-4-mvc-scala/; lo cual es prácticamente lo mismo que intentaremos hacer en nuestra entrada de hoy pero diferenciando el modo de construcción. En el ejemplo http://pivotallabs.com/spring-4-mvc-scala/ implementan navegación con Springmvc y la construcción con sbt, en nuestro caso implementaremos Servicios restfull con Spring y la construcción del mismo lo haremos con maven. En próximas entradas y con proyectos más complejos comenzaremos a usar  esta configuración que nos muestra pivotal, que ya tiene mas de un año desde las fases de prueba y parece ser la más indicada de una manera natural.

Otra vía, creo que la más natural para tratar Restful con Scala y específicamente para peticiones HTTP tanto request/response JSON debería ser Scala con Play, esta sería la solución ideal en el momento que conozcamos a fondo un PaaS, en mi caso no sé cómo se adaptaría esta solución a Openshift,único PaaS que de momento conozco.

La siguiente clase es una clase controladora, que simplemente llama a un servicio. Solo dos cosas a destacar la linea 22 es una definición del método y además retorna una lista que será un JSON de 3 elementos. Algo muy importante en esta linea 22 es la siguiente porción de código  java.util.List[Greeting] =  ....  en ella vemos que el tipo que devuelve nuestro servicio es una lista java sin embargo la lista gestionada dentro del servicio es una lista de Scala. Esta conversión(no es un CAST )  es de manera automática y es posible debido a la importación que hacemos en la linea 14 de collection.JavaConversions.

GreetingController.scala
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.ldg.spring.rest.controller

import com.ldg.spring.rest.service.Greeting

import org.springframework.web.bind.annotation.RequestParam
import java.util.concurrent.atomic.AtomicInteger
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.MediaType
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.ResponseBody
import scala.collection.immutable.List
import collection.JavaConversions._

@Controller
@Autowired
class GreetingController {

    @ResponseBody
    @RequestMapping(value=Array("/greeting"),method = Array(RequestMethod.GET))
    def greeting(@RequestParam(value="name", required=false, defaultValue="World") name: String) : java.util.List[Greeting] = {
         List(Greeting(1, name+"1"),Greeting(1, name+"2"),Greeting(3, name+"3"));
    }
 }

Después de ver nuestra anterior porción de código solo cabe una pregunta: ¿Por que convertir la lista de Scala a una lista de Java?La principal causa es la linea 8 del siguiente fichero de configuración(springContext.xml), aquí usamos el propio parser de mensajes a JSON que tiene Spring. Si la lista a retornar fuera una lista de Scala necesitaríamos hacer un conversor de JSON personalizado para nuestro tipo(jsonHttpMessageConverter,programado para Scala), tarea bastante ardua y que podría dar para otra entrada. Es probable que para un JSON más personalizado debamos hacer nuestro propio conversor.Con lo cual todas las response serán convertidas a JSON usando nuestro jsonHttpMessageConverter

springContext.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    <mvc:annotation-driven/>

    <context:component-scan base-package="com.ldg.spring.rest" use-default-filters="false">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>

    <!-- json handler -->
    <bean id="jsonHttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
        <property name="supportedMediaTypes" value="application/json"/>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jsonHttpMessageConverter"/>
            </list>
        </property>
    </bean>

La siguiente clase es una implementación del servicio, también en Scala y estará implementado a través de una case class, como un tema interesante tenemos la anotación @BeanProperty cuya finalidad es adicionar internamente métodos setter y getter siguiendo la convención de los JavaBeans,ello permitirá que nuestro servicio pueda ser inspeccionado por Spring ,todo ello transparente al desarrollador.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package com.ldg.spring.rest.service

import scala.beans.BeanProperty
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.annotation.JsonInclude;

//@BeanProperty is required in order to have Java Bean Style getter/setter that can be inspected by Spring
/**
 * La siguiente anotacion no es necesario especificar que produce un JSON,ya lo solucionamos de manera declarativa 
 * en springContext-webapp.xml destacando que todo lo que se produzca sea convertido a JSON con lo que solo 
 * @JsonInclude(JsonInclude.Include.NON_NULL)
 *
 **/

@Service
case class Greeting(@BeanProperty id: Int, @BeanProperty content: String)

No mencionamos en nuestras entradas detalles sobre la construcción del proyecto. Lo dejamos para el lector quiera descargarse el proyecto y ya en ese caso verá los detalles.Este es un caso particular ,no estableceremos referencia aquí a ningún código solo un link al pom del proyecto, mirar las dependencias y plugins relacionados con Scala y su modo de construcción.No lo detallamos aquí sobre todo para no extender esta entrada,cualquier duda pueden postearla en github.

Este pequeño holamundo de Scala-Restful-Spring lo puedes descargar y ejecutar siguiendo sus instrucciones en mi github. Hemos visto lo sencillo de implementar un servicio en Scala, en cuanto a la arquitectura REST se refiere, otra cosa será la implementación del servicio en si, que con scala aunque todo es mas sintetizado en ocasiones suele ser complejo.

Hacemos un resumen de las principales anotaciones y variables reservadas
que usamos aquí:
@BeanProperty: Cuando adjuntamos esta anotación a un campo, la misma añade metodos setter y getter a dicho campo siguiendo la convención de los javabeans.
case class : Una case class es como una clase normal con 2 grandes diferencias , que exporta los parámetros de su constructor con lo que son tratados como públicos y se puede acceder a ellos de manera directa. Así pues para construir una instancia de una case class no necesitamos new, solo será suficiente el nombre de la clase y la llamada al método en cuestión.Existe otro uso bastante importante de las case class , diría que el más importante , el relacionado con pattern match pero que dejaremos para una entrada dedicada a Scala únicamente.