Cuando implementamos nuestros servicios REST que devuelven objetos de la lógica de negocio de nuestra aplicación se pueden dar dos casos: los objetos que devolvemos son entidades, nuestros objetos no son entidades.

Si los objetos son entidades, estaremos exponiendo todos sus datos y en muchos casos no querremos enviarlo todo. Por ejemplo si guardase en una entidad los valores usuario y password, no debemos enviar dicho password como respuesta del JSON. Ante esta situación podríamos usar la anotación @JsonIgnore que fuerza que ese campo no se envíe, pero se aplicaría a todos los casos.

Si a partir de una entidad según en caso quisiéramos mandar un conjunto de campos diferente, la anotación @JsonIngore no es suficiente. En general las buenas prácticas de uso de servicios REST nos indican que siempre devolvamos objetos DTO y no expongamos las entidades de negocio, por tanto debemos seguir esta directríz.

Para evitar que la generación de la respuesta como DTO añada complejidad a nuestro código, es recomendable usar elementos de la programación funcional disponibles desde Java8. El modo de proceder debería ser similar al siguiente:

  1. Creamos dentro del paquete model ( por ejemplo: es.um.atica.miaplicacion.model) los objetos DTO que vamos a enviar. Si el proyecto es grande y lo tenemos dividido en módulos tendremos diferentes paquetes model por lo que deberemos crear cada DTO en el que corresponda.
  2. Dentro de nuestras entidades creamos un método toDTO() o varios toXXDTO() (siendo XX un indentificador que aporte valor semántico) que devolverá un objeto del tipo DTO con los datos que requiera de la entidad.
  3. Modificamos nuestro método REST para que, a partir de una lista de entidades, devuelva una lista de DTO, para esto usaremos programación funcional

Método tradicional:

@GetMapping("api/{version}/usuarios")
	public List<Usuario> listarUsuarios() {
		return this.usuarioService.findAll(); //Llamamos al servicio de usuarios que devolverá una lista de todos los usuarios del sistema (son Entidades).
	}


Devolviendo DTO con programación funcional

@GetMapping("api/{version}/usuarios")
	public List<UsuarioDTO> listarUsuarios() {					
		return  this.usuarioService.findAll().parallelStream().map(Usuario::toDTO).collect(Collectors.toList());
	}