Excepciones versatiles + Enums + Propiedades

Siguiendo la dinámica propuesta por el sistema de MonoLogger, le ha llegado la hora a las excepciones.
Además de utilizar otro fichero de propiedades donde vamos a definir un código de error y un mensaje, vamos a darle un buen uso a los ENUM de Java en lugar de una clase estática llena de mensajes y códigos de error (puaf puaf puag).

Lo primero que haremos será crear nuestro fichero de propiedades en es.monocaffe.exceptions con lo siguiente:

404=Service Not Found.
405=Computer Not Found.
406=Duplicated User, please use another code.
407=Duplicated Computer, please use another code.
408=Duplicated Value
409=User Not Found.

Para cada uno de estos errores crearemos un nueva excepción, menos para los valores duplicados donde crearemos una excepción general DuplicatedValueException o algo por el estilo. Pensando en objetos, un error de usuario duplicado es una excepción de valores duplicados, por lo tanto, definiremos sólo ésta excepción y cambiaremos sólo el código y el mensaje de error.

Un pequeño gráfico para que os hagais una idea:


¿Qué buscamos? Pues crear un grupo de clases bien definidas para manejar las excepciones de nuestra aplicación que sean facilmente modificables sin la necesidad de tocar mucho código o mejor, nada de código.

Lo más interesante aquí, es el uso que le doy al ENUM MCExceptions. Aquí la definición:


Como podeis ver, a cada elemento de la enumeración le asignamos un valor, el cual corresponde
al código de error que manejamos en el fichero de propiedades. Además, incluimos el mensaje, cargandolo desde el objeto ExceptionsMessages, quien devuelve el mensaje que tenemos en el fichero, utilizando el código de error. Esta clase ExceptionMessages es igual a la clase que definimos para las trazas en la entrada anterior, pero olvidandonos de lo referente a las trazas y centrandonos en la carga desde el fichero de propiedades.

Lo siguiente será crear las Excepciones en si. Como buena práctica, es siempre aconsejable que vayamos a definir unas excepciones que funcionen de forma diferente, crear una clase descendiente de Exception y a partir de ésta, definir nuestras propias excepciones.

Por otra parte, no hay que abusar de esto, y utilizar en lo posible, las excepciones propias de las librerias que estemos utilizando. Por ejemplo, no deseamos crear una excepción para referencias a Objetos nulos (NullPointerException) o excepciones como SintaxisJDBCIncorrecta. Recordar que el uso de las excepciones estandar, tiene la ventaja de la familiaridad que estas presentan para los desarrolladores, quienes reconoceran más rapidamente una NPException o una IOException a alguna otra que nosotros hayamos creado.

Vamos a crear la excepción MonoCaffeGeneralException:


Como veis, aquí empezamos a utilizar nuestro enum: MDExceptions. Este nos va a proveer con el código de error y el mensaje de error el cual mandamos a Exception y que luego podremos utilizar en nuestro código.

A continuación definiremos las excepciones especificas a cada caso que deseemos controlar. El ejemplo más útil para esto, es la DuplicatedValuesException la cual utilizaremos para distintos códigos de error, en lugar de definir una excepción para cada tipo de valor que pueda ser duplicado: User, PC, Client, etc. Vamos a contruir esa excepción:


Cada contructor tiene una aplicación específica, dejando gran libertad al usuario de esta excepción a hacer casí lo que quiera. En el primer caso el programador no tiene ganas de pensar en mensajes ni código de error, sólo en lanzar la excepción y continuar, entonces puede utilizar el primer contructor que generá una excepción de valores duplicados generica y con los mensajes que tenemos definidos.

La segunda excepción permite específicar un mensaje de error. Este contructor es opcional y deberiamos forzar a que cada nuevo error deba ser definido
en el fichero de propiedades y en el enum, antes de poder continuar, pero me siento condescendiente.

El tercero es el que más vamos a utilizar siempre y cuando tengamos definido en el enum el error que deseamos mostrar. Este contructor, tomara la mensaje
asociado al código de error y lo utilizará para lanzar la excepción.

Otra excepciones más específicas como UserNotFoundException, sólo deberia definir el primer tipo de contructor, para mantener un mensaje y código de error
constante a lo largo de la aplicación y sin hacernos pensar cada vez que lo utilicemos. Sólo con escribir:

throw new UserNotFoundException();

será suficiente.

Tambien podriamos seguir el mismo diseño utilizado para los valores duplicados y crear una excepción ObjectNotFound.

Para utilizar en nuestro código estas excepciones hariamos algo como:

throw new DuplicateValueException(); //El valor es duplicado
//...
throw new DuplicateValueException(MCExceptions.DUP_USER); //El usuario está duplicado
//...
throw new DuplicateValueException("Ese DNI/NIF/CIF ya existe"); //Una excepción poco habitual

Eso es todo, espero que os sea de utilidad.