Futuros en Java, Parte 2: Interfaz Future

Continuo con la serie de post sobre Futuros en Java que comencé con el anterior post. En este hablaré sobre la interfaz Future añadida en java 5.

Esta serie constará inicialmente de las siguientes partes:
Parte 1: Introducción
Parte 2: interfaz Future
Parte 3: CompletableFuture, introducción
Parte 4: CompletableFuture, uso avanzado

Interfaz Future: uso y ejemplos

Para poder evitar los bloqueos de los que hablé en el anterior post, nuestra primera herramienta en Java es la interfaz Future. Esta fue añadida hace tiempo ya, con Java 1.5, y nos provee lo básico para el trabajo con futuros. Como veremos, demasiado básico… Vamos con algunos ejemplos para demostrar su funcionamiento.

Creación:
No podemos crear directamente un futuro. Es una interfaz, y nos lo devolverá, por ejemplo, un método.

        Future<String> future = someBigProcess.processVeryLong("test");

Tiene un parámetro genérico que será el tipo del objeto que esperamos obtener cuando el futuro se complete.

Para crearlo, no hay una manera directa. Por ejemplo, la más sencilla sería esta:

    private final ExecutorService executor = Executors.newFixedThreadPool(5);

    public Future<String> processVeryLong(String param1) throws InterruptedException {
        return executor.submit(() -> {
            TimeUnit.SECONDS.sleep(5);
            LOG.info("Terminando processVeryLong...");
            return param1.concat(" result");
        });
    }

Usamos la interfaz ExecutorService para «lanzar» un Callable (con un lambda de Java 8). Para eso necesitamos haber definido el Executor, que es una clase que se encarga de gestionar pool de threads. Su método ‘submit’ ejecuta en otro thread el Callable o Runnable recibido, y devuelve un Future, que, cuando se complete la ejecución, contendrá el resultado.

Uso y bloqueos:
El uso principal de la interfaz Future es su método ‘get’:

        String result = future.get();

Este método es el que obtiene el valor real del futuro. Si el futuro todavía no se ha completado, al llamar a este método nos quedaremos bloqueados hasta que se complete.
Ojo, si al completarse el futuro se genera una excepción, la llamada a este método es la que lanzará esa excepción («envuelta» en una ExecutionException).
También existe una versión del mismo método que recibe un timeout, para no quedarnos bloqueados eternamente:

        String result = future.get(5, TimeUnit.SECONDS);

Aparte tiene algunos métodos más:
cancel(boolean mayInterruptIfRunning) -> Cancela la ejecución del futuro.
isCancelled() -> Comprueba si ha sido cancelado.
isDone() -> Comprueba si el futuro se ha completado.

Pero no nos ofrece ninguna posibilidad más. Si usamos la interfaz Future, en algún momento, si o si, tendremos que bloquear nuestro thread para obtener el resultado.

La interfaz Future de java se queda muy corta para siquiera empezar a montar un sistema «reactivo». Nos ofrece una manera sencilla de ejecutar métodos de manera asíncrona, pero nada más.

En el próximo post de la serie veremos como la clase CompletableFuture, añadida en Java 8, nos ayuda a resolver esto.

Tenéis en mi github (proyecto future-example) un ejemplo completo con la interfaz Future, con un test sencillo con el que probarlo, tanto para un caso normal, como para un caso que lanza una excepción.

Futuros en Java, Parte 1: Introducción

Comienzo hoy una seríe de post sobre los futuros en Java y sus posibilidades. En este primer post me centraré en explicar el concepto y los problemas de las aplicaciones «clásicas».

Esta serie constará inicialmente de las siguientes partes:
Parte 1: Introducción
Parte 2: interfaz Future
Parte 3: CompletableFuture, introducción
Parte 4: CompletableFuture, uso avanzado

Threads, bloqueos y demás

El funcionamiento de una clásica aplicación web montada con Java, con Spring por ejemplo, se basa principalmente en aceptar peticiones http, usando para cada una de estas peticiones (o request) un thread propio. De tal manera que cuando a nuestra aplicación acceden varios usuarios concurrentemente, tendremos un thread para cada uno de esos usuarios.

Si nuestra aplicación no es muy eficiente, e incluso tiene cuellos de botella grandes, por ejemplo en el acceso a base de datos, en peticiones a otras apis, etc, cada una de esos threads estará «activo» mucho tiempo… Lo que implicará que si tenemos una aplicación con un gran volumen de usuarios, en un momento dado puede reventar el servidor por el número de threads.

La única manera inicial para resolver esto es a base de fuerza bruta: añadiendo más memoria a la maquina, para que aguante más threads… lo cual no es práctico, al final volverá a pasar. Un sistema así no escala. Lo ideal es que los threads que usan las requests se liberen lo antes posible (para poder servir otras requests esos mismos, en lugar de crecer el número de threads hasta el infinito…).

Todo esto ocurre principalmente por que nuestros threads están mucho tiempo activos, y la gran mayoria de ese tiempo están bloqueados. En esos accesos a base de datos, otros recursos web, apis externas, etc es donde se va el mayor tiempo con diferencia. Y, como digo, el thread se queda ahi bloqueado. No se libera, aunque realmente no está haciendo nada, pero esta ocupado, esperando…

Manifiesto reactivo, asincronía y futuros

Para solucionar este problema surge el Manifiesto Reactivo. Viene a ser unas buenas prácticas y una manera concreta de desarrollo de aplicaciones en las que, entre otras cosas, debemos evitar esos bloqueos de threads a toda costa, para desarrollar aplicaciones que escalen correctamente.

¿Y cómo evitamos esos bloqueos? Con los futuros. El concepto de Futuro es el de un objeto que, en algún momento, contendrá el resultado de un método. Cuando llamemos a ese método, devolverá inmediatamente el resultado (un objeto Futuro), y se irá ejecutando de manera asincrona, mientras nuestro método «llamante» continua. En algún momento, el método llamado terminará, y dejara el resultado en el futuro.

Un pequeño ejemplo:

        // LLamada al método, que será asincrona
        Future<String> resultFuture = dao.methodAccessingDB();

        // Hacemos otras cosas

        // Más cosas

        // Obtenemos el resultado del futuro
        String result = resultFuture.get();

Aún así, en algún momento habrá que bloquear al método llamado para obtener ese resultado (como vemos en la linea 9 del ejemplo anterior). Para evitar esto tenemos varías «estrategias» a la hora de programar, que veremos más adelante.

En los proximos posts de esta seríe me centraré en explicar ejemplos con las clases que Java nos provee para los futuros: Future y CompletableFuture (esta última añadido en Java 8).

Spring Boot series: developer tools

Hoy vuelvo con un pequeño post sobre Spring Boot. Hace poco salió la versión 1.3, con varias novedades, entre las que destacan las «developer tools». Vamos a ver un pequeño ejemplo para ver como funciona esta nueva funcionalidad.

Concepto

En la última versión de Spring Boot que ha liberado la gente de Spring hay varias novedades, pero la que más llama la atención son las developer tools, unas librerías para hacer más cómodo el desarrollo. Principalmente lo que nos ofrece es que, mientras estemos desarrollando en nuestro IDE, cualquier cambio que hagamos en el código se ‘auto-despliegue’ en la aplicación, para evitarnos el tener que estar parando y arrancando cada vez que hagamos un cambio.

El truco por lo visto es que Spring Boot, aunque realmente hace un ‘restart’, lo hace muy rápido gracias a que tiene dos class loaders, uno con los jars de nuestro proyecto, y otro con nuestras clases. Cuando se realiza ese ‘restart’ solo recarga el de nuestras clases, lo cual, aunque sea un reinicio completo, es MUY rápido.

Y lo mejor es que funciona como casi todo en Spring Boot: no necesita ningún tipo de configuración ni nada, con añadir la dependencia necesaria a nuestro maven (o gradle), es suficiente.

Voy a implementar un pequeño ejemplo para probarlo, tanto con Intellij como con STS, con maven.

Entorno usado:
Java JDK 1.8
Maven 3.2.5
Git 2.6.3
IDEs Intellij 15.0.1 Ultimate version / STS 3.7.2

Pasos
1. Creamos un proyecto Spring Boot básico, con el starter web nada más, aparte de las dev tools. Nuestro pom.xml quedaría así:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edwise.pocs.springbootdevtoolstest</groupId>
    <artifactId>springboot-devtools-test</artifactId>
    <version>0.1</version>
    <packaging>jar</packaging>

    <name>springboot-devtools-test</name>
    <description>Test project for Spring Boot new featture: devtools</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

No tiene nada nuevo de cualquier ejemplo básico con Spring Boot, aparte de añadir la dependencia ‘spring-boot-devtools‘.

2. Y nuestra clase base de Spring Boot, como siempre:

package com.edwise.pocs.springbootdevtoolstest;

// imports...

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3. Arrancamos en nuestro Intellij, ya sea con una ‘Run Configuration’ de Spring Boot si tenemos la versión Ultimate, o directamente ejecutando el comando maven ‘spring-boot:run’ desde la tool window de maven.

4. Ahora que tenemos arrancado el servidor, vamos a hacer un cambio: añadimos un controller sencillito, un hello world:

package com.edwise.pocs.springbootdevtoolstest.controllers;

// imports...

@RestController
@RequestMapping("/helloworld")
public class HelloWorldController {

    @RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
    public String getHelloWorld() {
        return "Hello World!";
    }
}

5. Y ahora pulsamos el botón de «Make» en Intellij (CTRL + F9). Esto automáticamente recargará todo el contexto de nuestro proyecto. Si accedemos ahora a ‘http://localhost:8080/helloworld‘, nos responderá correctamente. Todo esto sin reiniciar ni parar y arrancar el servidor. Y sin hacer ningún tipo de configuración especial en nuestro IDE ni nada. Y es un redespliegue muy rápido, a mi me tarda menos de 2 segundos 🙂

Nota sobre STS: si hacemos la misma prueba con STS, es algo más sencillo. En ese caso, lo único que necesitamos para «lanzar» la recarga de nuestro proyecto es guardar el archivo, dado que en eclipse está activado por defecto el «Build automatically». Esto hace que en Intellij sea algo menos «automático», pero es debido a la manera de trabajar de este último, que es algo distinta en cuanto a los guardados de los ficheros.

He subido a mi github (proyecto springboot-devtools-test) el ejemplo, con algún controller más, para que lo probéis directamente en vuestros IDEs.

Expresiones regulares y ‘wildcards’ en servicios REST con JAX-RS

En el proyecto en el que estoy trabajando nos surgió hace poco la necesidad de que la ruta de un ‘endpoint’ de un servicio REST pudiera recibir, como variable en el path, una cadena que fuera una ruta de directorios, por ejemplo:

/micarpeta/otracarpeta/nombrefichero

Si eso lo intentamos hacer definiendo un ‘endpoint’ como este:

/api/files/{filepath}

… no funciona. La url completa sería /api/files/micarpeta/otracarpeta/nombrefichero, y no va a encontrarla, dado que no tenemos ningún endpoint definido así realmente.

Aunque inicialmente parece que no es posible conseguir un endpoint que se trague eso, si que se puede hacer :). Vamos a verlo.

A la hora de definir los ‘endpoints’ o urls de nuestros Resources (o Controllers en Spring), tenemos los básicos: endpoints fijos o los típicos con ‘path variable’:

Endpoint fijo:

/api/customers/orders

Con path variable:

/api/customers/{id}
/api/customers/{id}/orders/{idOrder}

Pero no son las únicas opciones, vamos a ver alguna más, En un Resource con url base ‘/api/foo’:

  • Podemos tener un ‘endpoint’ que tenga un parámetro como path variable que obligatoriamente sea un entero:
        
        @GET
        @Path("onlyinteger/{id : \\d+}")
        @Produces(MediaType.TEXT_PLAIN)
        public String getFooWithIntegerId(@PathParam("id") int id) {
            return Integer.toString(id);
        }
    

    De esta manera, si accedemos a la url ‘/api/foo/onlyinteger/ID_123’, no funcionará. Tiene que ser un número entero si o si: ‘/api/foo/onlyinteger/123’.

  • Podemos también concatenar varios parámetros, sin usar la barra ‘/’, por ejemplo, con un guión:
        @GET
        @Path("twoparams/{firstname}-{surname}")
        @Produces(MediaType.TEXT_PLAIN)
        public String getFooWithNameAndSurname(@PathParam("firstname") String firstname,
                                               @PathParam("surname") String surname) {
            return firstname + " " + surname;
        }
    

    Ejemplo de url: ‘/api/foo/twoparams/bilbo-baggins’.

  • Y si queremos que el parámetro sea, como lo que comentaba al comenzar el post, una cadena en la que pueda venir una ruta de ficheros:
        @GET
        @Path("wildcard/{subpath : .+}")
        @Produces(MediaType.TEXT_PLAIN)
        public String getFooWithWildcard(@PathParam("subpath") String subpath) {
            return subpath;
        }
    

    Si accediéramos, por ejemplo, a esta url: ‘/api/foo/wildcard/midir/anotherdir/ficName.txt’, funcionaria.

Si queréis juguetear con un ejemplo, en mi github he creado un proyecto (jaxrs-wildcards-example), arrancable con jetty desde maven (‘mvn jetty:run’), con el que podéis probar el código del post.

Unit Testing – Como mockear un método de una clase padre

Recientemente, en el proyecto en el que estoy, nos hemos encontrado con un problema curioso a la hora de hacer los tests unitarios de una funcionalidad. El método que queríamos testear llamaba a un método de la clase padre, el cual hacia ciertas llamadas a base de datos y diversos recursos externos. No había manera de inicializar esos recursos como mocks antes, por la implementación de la clase padre, y no sabíamos como podíamos mockear solo esa parte, dado que no es otra clase, es la clase padre la que intentamos mockear, lo cual inicialmente no es posible…

Solución (la «regular» pero la más práctica)

Podemos mockear un método de una clase que estemos probando (que el método sea de la clase padre o no, no cambia nada, si es de la clase padre es como si fuera de la actual, lo hereda), usando los Spy de Mockito.

Veamos un poco por encima la diferencia entre Mock y Spy (en el framework Mockito):

  • Mock: cuando Mockito crea un Mock, lo único que hace es crear un esqueleto de la clase, sin funcionalidad alguna. Al llamar a los métodos del mock, no hará nada (aparte del comportamiento que le asignemos con los métodos when, thenReturn, etc)
  • Spy: Al crear un spy, es necesario pasarle un objeto YA creado de esa clase. Y mockito lo que hace realmente es una especie de wrapper sobre ese objeto. Al llamar a los métodos del spy, se ejecutarán los métodos de la clase (a no ser que hayamos cambiado el comportamiento, como vamos a hacer ahora).

Ejemplo:

Pongamos que tenemos estas dos clases. La primera, que tiene un método que usa algún recurso como base de datos o similar, y la segunda que hereda de esta y usa ese método dentro de uno propio:

public class Foo {

    public String doSomethingWithDatabase() {
        System.out.println("Method that connect with DB...");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Finished connection whit DB.");

        return "OK real Foo";
    }
}

public class Bar extends Foo {

    public int myMethod() {
        System.out.println("Method to test!");
        String msg = this.doSomethingWithDatabase();
        System.out.println("Msg: ".concat(msg));

        return 1;
    }
}

¿Como testeamos nuestra clase ‘Bar’, mockeando el método de la clase padre? Así:

package com.edwise.pocs.spymockito;

// imports...

public class BarTest {

    private Bar bar;

    @Test
    public void testMyMethodWithMockitoSpy() {
        bar = spy(new Bar());
        doReturn("OK Foo mocked").when(bar).doSomethingWithDatabase();

        int result = bar.myMethod();

        assertThat(result).isEqualTo(1);
    }
}

Creamos un Spy con el método estático de mockito pasándole una instancia ya creada de nuestra clase ‘Bar’. Y ahora, sobre esa instancia hacemos tanto el test (linea 14), como el cambio de comportamiento típico de mockito (linea 12).
Para mockear el método usamos ‘doReturn‘ y no ‘when‘, ya que con when no funcionaría… Con los Spy es necesario usar doReturn (ver javadoc de doReturn para más detalle)

Solución (la correcta…)

Realizar un test como el anterior realmente no es lo más correcto, estamos medio mockeando la clase que estamos probando… Ojo, funciona, y hace lo que tiene que hacer. Pero no es algo muy limpio, mezclamos en la misma instancia la clase testeada y la clase mockeada.
Si necesitamos hacer algo como esto para testear nuestra clase, lo que está pasando es que nuestro diseño no es correcto. En este caso, como en otros muchos, lo que ocurre es que estamos abusando de la herencia, y seguramente la relación entre nuestras dos clases debería ser composición (‘Bar’ no extendería ‘Foo’ y tendría un atributo de tipo ‘Foo’, probablemente pasado en el constructor, o por inyección de dependencias), algo como esto:

public class BarWellDesigned {

    private Foo foo;

    public BarWellDesigned(Foo foo) {
        this.foo = foo;
    }

    public int myMethod() {
        System.out.println("Method to test!");
        String msg = foo.doSomethingWithDatabase();
        System.out.println("Msg: ".concat(msg));

        return 1;
    }
}

La clase Foo sería idéntica a la anterior.

De esta manera nuestro test sería el típico en el que mockeamos la clase de la que dependemos (‘Foo’ en este caso) y testeariamos ‘Bar’ directamente sin ‘wrappearlo’ con el Spy de Mockito.

package com.edwise.pocs.spymockito;

// imports...

public class BarWellDesignedTest {

    private BarWellDesigned barWellDesigned;

    @Test
    public void testMyMethodWithoutMockito() {
        Foo foo = mock(Foo.class);
        barWellDesigned = new BarWellDesigned(foo);
        when(foo.doSomethingWithDatabase()).thenReturn("OK Foo mocked");

        int result = barWellDesigned.myMethod();

        assertThat(result).isEqualTo(1);
    }
}

Pero claro, en el mundo real, cuando te encuentras algo así, hacer un cambio de diseño (o pedir que lo haga el equipo que mantiene ese código), suele ser complicado…

Podéis descargaros todo el código de este post en mi github, proyecto spy-mockito-example.

Cómo devolver el resultado de un POST en un servicio REST

En varios posts he implementado, con un framework u otro, un servicio REST normalmente muy sencillo. Al ser tan sencillos normalmente no cumplo al 100% las «especificaciones» o buenas prácticas que se recomiendan para considerar un servicio como REST. En este post voy a explicar como se debe implementar un POST, el resultado que devolvemos en él y en concreto el modo de hacerlo en Java.

Concepto:

En la mayoría de ejemplos de servicios REST que he implementado en este blog, para no complicar el código, lo que hago es simplemente devolver un 201 (CREATED). Incluso en algunos casos devuelvo en el body el objeto completo recién creado. Pero lo más correcto es no devolver nada en el ‘body’, y devolver en el ‘location’ de los ‘headers’ la url con la que acceder a ese recurso recién creado. La respuesta debería ser algo así:

HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/api/info/12345
Content-Length: 0

Vamos a ver como devolver esta respuesta tanto en un proyecto con Spring MVC como en un proyecto con JAX-RS. Para ello modificaré los REST que hice para los posts de implementar un servicio Rest con Spring e implementar un servicio Rest con JAX-RS (Jersey).

Por último, comentaremos brevemente como sería si usáramos Spring HATEOAS.

Entorno usado:
Java JDK 1.8
Maven 3.2.1
Git 1.9.5
IDE Intellij 14.1.1 Ultimate version

Con Spring MVC:

1. Usaremos el proyecto spring-rest-example el cual implementé en mi post Implementar un servicio Rest con Spring. Si abrimos nuestro controller, veremos que en el caso del POST no devolvemos nada:

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public void insertUser(@RequestBody User user) {
        userService.save(user);
    }

2. Lo que necesitamos es devolver en los headers el location relleno con la url del objeto creado, sería algo así:

    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity<User> insertUser(@RequestBody User user) {
        User userSaved = userService.save(user);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setLocation(...);

        return new ResponseEntity<>(httpHeaders, HttpStatus.CREATED);
    }

Creamos un objeto HttpHeaders, y necesitamos setearle el location (de tipo URI). Y en el return del método devolvemos un ResponseEntity con esos headers y el código HTTP de respuesta que corresponde a un POST (201 – Created).

La primera idea que se nos puede venir a la cabeza es meterle la url directamente, con un String o quizá obteniendo el dominio de alguna variable o propiedad, que tengamos en una constante. Con esto funcionaria, pero… vamos a hacerlo un poco mejor 🙂

3. Usaremos un builder que nos provee Spring para crear URIs: ServletUriComponentsBuilder, de la siguiente manera:

    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity<User> insertUser(@RequestBody User user) {
        User userSaved = userService.save(user);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setLocation(
                ServletUriComponentsBuilder
                        .fromCurrentRequest()
                        .path("/{id}")
                        .buildAndExpand(userSaved.getId())
                        .toUri());

        return new ResponseEntity<>(httpHeaders, HttpStatus.CREATED);
    }

Con esto creamos nuestra URI, los métodos del builder son bastante autoexplicativos: con la request actual, le añadimos un path variable ‘/{id}’, y le metemos el id en esa variable.
(El código en mi github está algo refactorizado, pero es lo mismo 😛 )

4. Arrancando con el plugin maven de Spring Boot, como siempre, podemos probar nuestro POST. La respuesta del POST /api/users será algo así:

HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/api/users/45332
Content-Length: 0
Date: Mon, 06 Apr 2015 18:23:50 GMT

5. (Bonus) Testing: Si tenemos test unitario de nuestro controller, se complica un poco. Tenemos que, o bien mockear los métodos del builder (es estático, necesitaríamos PowerMock o similar), o simplemente añadimos una MockHttpServletRequest al contexto, cosa que es lo que he hecho en el método @Before, para no complicarme mucho. El test completo, aquí
Si lo que tenemos son tests de integración, no habría que cambiar nada si el test está bien configurado.

Con JAX-RS (Jersey):

1. Usaremos el proyecto jersey-rest-example el cual implementé en mi post Implementar un servicio REST con JAX-RS (Jersey). Si abrimos nuestro controller, ahora mismo tenemos lo siguiente:

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response insertUser(User user) {
        userService.save(user);
        return Response.status(Response.Status.CREATED).build();
    }

2. Necesitamos, igual que antes devolver en los headers el location relleno con la url de nuestro recurso, en este caso, de esta manera:

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response insertUser(User user) {
        User userSaved = userService.save(user);
        URI uri = ...;
        return Response.created(uri).build();
    }

Aquí devolvemos un Response, que creamos con su método ‘created’ (esto le asigna ya como http status el 201 – Created) y le pasamos la uri que se asignará en el location.

3. Y al igual que antes, vamos a hacerlo con un builder que nos de la url, en este caso usaremos uno de la especificación JAX-RS: UriBuilder. Para ello, eso sí, necesitamos inyectar en nuestro controller un UriInfo, que se obtiene del contexto de la aplicación:

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response insertUser(User user) {
        User userSaved = userService.save(user);
        UriBuilder uriBuilder = uriInfo.getRequestUriBuilder();
        URI uri = uriBuilder.path(userSaved.getId().toString()).build();
        return Response.created(uri).build();
    }

Necesitamos un bean de contexto, UriInfo, con el que podremos obtener el builder concreto para nuestra URI. una vez con el builder, con su método ‘path’ le añadimos el id de nuestro recurso, y listo.
(El código en mi github está algo refactorizado, pero es lo mismo 😛 )

4. Arrancamos la aplicación (ya sea con un tomcat o con un glassfish, como vimos en el post de JAX-RS), y el servicio nos devolverá lo siguiente al hacer el POST:

HTTP/1.1 201 Created
Server: GlassFish Server Open Source Edition  4.1
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.1  Java/Oracle Corporation/1.8)
Location: http://localhost:8080/api/users/45332
Date: Mon, 06 Apr 2015 18:50:13 GMT
Content-Length: 0

5. (Bonus) Testing: aquí, si también tenemos test unitario, igualmente se complica un poco. En este caso si he mockeado todo el tema de la UriInfo. El tests completo, aquí.

Con Spring HATEOAS:

No quiero entrar mucho en detalle, porque creo que esto da para otro post aparte que escribiré pronto, pero no quería terminar este post sin nombrar el concepto HATEOAS, así como el modulo de Spring que lo implementa. Si usamos Spring HATEOAS en nuestro proyecto, no necesitamos obtener el link a través de ningún builder, ya que nuestro propio recurso tendrá su link «self». Más información sobre HATEOAS aquí, así como sobre el proyecto Spring. Lo veremos en otro post.

Nada más. Recordad que todo el código de este post está subido en los proyectos spring-rest-example y jersey-rest-example de mi github.

Java: el paso de parámetros es por valor

El post de hoy es para resolver una duda sobre Java básico que a veces surge incluso entre gente con mucha experiencia: ¿Cómo es el paso de parámetros en Java? ¿Es por valor o por referencia?

Dependiendo del lenguaje de programación, el paso de parámetros puede ser por valor o por referencia:

  • El paso por valor es cuando al pasar una variable como parámetro a un método, el valor de ese parámetro se copia en una variable «temporal» que solo estará vigente durante la ejecución de ese método. De manera que al salir del método, la variable inicial tendrá el mismo valor que al inicio, ya que dentro del método no puede modificarse.
  • En el paso por referencia, en cambio, al pasar una variable como parámetro a un método, se pasa una referencia a esa variable. Con lo que si dentro del método es modificada, al salir del método el valor de la variable será distinto al inicial.

En Java el paso de parámetros es siempre por valor. Siempre. Varias veces he oído a gente decir que el paso en Java es por referencia, o, más concrétamente, que el paso es por valor si son datos primitivos y por referencia si son objetos. Esto último lo cree mucha gente, y no es cierto realmente, aunque lo pueda parecer.

Vamos a explicarlo con un pequeño ejemplo, veamos el siguiente código:

    public void primitiveExample() {
        int years = 10;
        System.out.println("Years before method: " + years);
        methodWithPrimitive(years);
        System.out.println("Years after method: " + years);
    }

    private void methodWithPrimitive(int arg) {
        arg = arg + 3;
        System.out.println("Parameter modified: " + arg);
    }

En el código pasamos un int ‘years’ como parámetro a un método y dentro del método le asignamos un nuevo valor.
Si ejecutamos ese código, la salida sería la siguiente:

Years before method: 10
Parameter modified: 13
Years after method: 10

Como vemos, al salir del método la variable ‘years’ tiene el mismo valor que tenia antes de entrar en el método, aún habiéndose modificado en él. Así funciona el paso por valor.

Veamos ahora el siguiente ejemplo, con un objeto en lugar de un tipo primitivo:

    class User {
        private String name;

        public User(String name) {
            this.name = name;
        }

        //getter and setter...

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    ...
    public void objectExample() {
        User user = new User("edwise");
        System.out.println("User before method: " + user);
        methodWithObjectSet(user);
        System.out.println("User after method: " + user);
    }

    private void methodWithObjectSet(User arg) {
        arg.setName("newUser");
        System.out.println("Parameter modified: " + arg);
    }

Aquí, creamos un ‘User’ (clase muy simple con un atributo String), se lo pasamos como parámetro a un método y dentro de este llamamos a un método set para modificar un atributo de nuestro objeto.
La salida por consola sería la siguiente:

User before method: User{name='edwise'}
Parameter modified: User{name='newUser'}
User after method: User{name='newUser'}

Si, ahora, como vemos, nuestro parámetro ha sido modificado dentro del método, y esa modificación perdura en nuestro objeto. ¿Es entonces esto paso por referencia? No… realmente es paso por valor, como siempre. ¿Qué ha pasado entonces?

Veamos un último ejemplo, y lo explicamos:

    public void otherObjectExample() {
        User user = new User("edwise");
        System.out.println("User before method: " + user);
        methodWithObjectNew(user);
        System.out.println("User after method: " + user);
    }

    private void methodWithObjectNew(User arg) {
        arg = new User("newUser");
        System.out.println("Parameter modified: " + arg);
    }

En este caso hacemos casi lo mismo que en el código anterior. Dentro del código estamos modificando nuestro objeto, pero ahora creando un nuevo y asignandoselo. El resultado debería ser el mismo.
Salida:

User before method: User{name='edwise'}
Parameter modified: User{name='newUser'}
User after method: User{name='edwise'}

No, en este caso nuestro objeto no se ha modificado. Aquí si parece claro que el paso es por valor.

Para entender el porque de nuestro segundo ejemplo, la clave es recordar que, en Java, todas las variables que «son» objetos realmente son referencias a objetos, no son el objeto en si. De manera que, tanto en nuestro segundo y tercer ejemplo al método le pasamos una referencia a un objeto. Y como el paso es por valor, se crea una variable temporal para el método en la que se copia el valor de la variable que le pasamos, que es una referencia. Luego entonces, dentro del método tenemos una nueva referencia que apunta al mismo objeto.

En el segundo ejemplo (método ‘objectExample‘), llamamos desde nuestra nueva referencia (‘arg’) al método set del objeto. Como el objeto sobre el que llamamos a ese método es el mismo que para la referencia de fuera, nuestro objeto inicial es modificado.

En el tercer ejemplo (método ‘otherObjectExample‘), lo que realmente estamos haciendo es crear un nuevo objeto, y que la referencia ‘arg’ apunte/referencie a ese objeto. Al salir del método la referencia ‘arg’ desaparece, y la ‘user’ sigue apuntando al primer objeto, el cual no ha sido modificado, claro. (Además, el objeto creado dentro del método será destruido por el Gargabe Collector al no tener ninguna referencia que apunte a él, pero eso ya es otra historia).

Conclusiones

El paso de parámetros en Java es siempre por valor. Pero al ser referencias a objetos las «variables objetos», desde dentro de un método podemos acceder y modificar el objeto original. Y hay que tener mucho cuidado cuando asignemos un nuevo objeto a un parámetro de un método, ya que el resultado no va a ser el esperado…

De todas maneras, asignar nuevos valores / objetos a un parámetro de un método no suele considerarse una buena práctica, con lo que si hacemos un código medianamente limpio no deberíamos tener estos problemas…

Tenéis en mi github (proyecto passbyvalue-example) el código completo de este post, para poder ejecutarlo y comprobar que es cierto todo esto 😉