jueves, 6 de junio de 2013

Tutorial sobre JUnit

1 - Introducción y vista general
JUnit es un framework de programación para escribir tests de unidad fácilmente repetibles. Se enmarca dentro de la arquitectura xUnit de frameworks de testeo (Existen AUnit, CUnit, NUnit, ... para otros lenguajes de programación). Dentro de los diferentes tipos de pruebas que se realizan sobre una aplicación en desarrollo, JUnit se dedica a las pruebas unitarias, llamadas así porque testean funcionalidades concretas del código. Son pruebas, podría decirse, locales, enfocadas a la funcionalidad de métodos o clases. JUnit nos ahorra tiempo de testeo de software porque nos evita repetir un montón de pruebas de forma manual cada vez que alguna modificación en el código así lo requiere.

El código creado con JUnit normalmente va en carpeta aparte para no mezclarse con el código propio de la aplicación. En su versión actual, la 4, se utilizan anotaciones en el código de testeo que identifican los métodos que realizan las pruebas. Los métodos de test están normalmente en una clase (clase de testeo) sólo para este fin. El orden de los métodos de test no es tomado en cuenta por JUnit (que lo considera arbitrario) así que un test no debería depender de otros.

Las anotaciones antes mencionadas que están disponibles en JUnit 4 son las siguientes (traducidas de [2]):


Annotation Description
@Test
public void method()
La anotación @Test identifica que un método es un método de test.
@Before
public void method()
Este método es ejecutado antes de cada test. Este método puede preparar el entorno de test (por ejemplo, leer datos de entrada o inicializar la clase).
@After
public void method()
Este método es ejecutado después de cada test. Este método puede limpiar el entorno de test (por ejemplo, borrar datos temporales o restablecer valores por defecto). También puede recuperar memoria, limpiando estructuras de memoria costosas.
@BeforeClass
public static void method()
Este método es ejecutado una vez, antes del comienzo de todos los tests. Se puede usar para realizar actividades intensivas en cuanto al tiempo, por ejemplo para conectarse a una base de datos. Los métodos así anotados necesitan ser definidos como static en JUnit.
@AfterClass
public static void method()
Este método es ejecutado una vez, después de que todos los tests hayan sido finalizados. Esto puede usarse para realizar tareas de limpieza, por ejemplo, desconectarse de una base de datos. Los métodos así anotados necesitan ser definidos como static en JUnit.
@Ignore Ignora el método de test. Esto es útil cuando el código subyacente ha sido cambiado y el caso de testeo no ha sido adaptado. O si el tiempo de ejecución de este test es demasiado largo como para ser incluido.
@Test (expected = Exception.class) Falla si el método no lanza la excepción esperada.
@Test(timeout=100) Falla si el método toma más de 100 milisegundos.

Dentro de los métodos de testeo escritos usando JUnit, se usan las llamadas sentencias de aserción (assert). Esto quiere decir que JUnit proporciona métodos estáticos en la clase Assert que nos permiten comprobar si se cumplen las condiciones que decidamos fijar. Estos métodos suelen empezar con la palabra assert y nos permiten especificar el mensaje de error si no se cumple la aserción y el valor esperado. En una aserción se compara dicho valor esperado con el que realmente se produce en la ejecución. Si no coinciden, se lanza una AssertionException. Hay varios métodos de aserción que pueden consultarse en la documentación de la API. Por poner un ejemplo, nombremos assertTrue([mensaje], boolean condicion) que comprueba si se cumple la condición booleana suministrada.

La instalación de JUnit en el caso general es simple, ya que consiste en descargar la biblioteca de JUnit en formato .jar desde la página web oficial de JUnit (http://junit.org/) y añadirla luego a nuestro proyecto java y al classpath. En el caso concreto de que usemos el IDE Eclipse, nos encontraremos con que JUnit viene ya integrado.

En cuanto a la ejecución de las pruebas unitarias, los tests pueden ejecutarse de forma integrada con la interfaz del IDE si estamos trabajando en Eclipse, pero también puede hacerse de forma independiente (para este u otros IDE) usando el método runClasses() de la clase org.junit.runner.JUnitCore. Cabe decir también que para facilitar la ejecución de varias clases de testeo, haciendo que todas se ejecuten de forma conjunta, estas pueden combinarse en lo que en JUnit se llama “suite de pruebas” (test suite).

JUnit dispone también de opciones avanzadas que van más allá de lo que va a cubrir este tutorial introductorio, no obstante las nombraremos: los tests parametrizados, las reglas (anotación @Rule para mayor flexibilidad en los tests) y los falsos objetos (Docking).

2 - Ejemplo de uso con Eclipse

Para este tutorial introductorio vamos a trabajar con Eclipse pues este IDE tiene soporte integrado para JUnit y nos facilita el trabajo. Sin embargo, los tests JUnit pueden escribirse manualmente de forma independiente en cualquier IDE.

Este tutorial va a consistir en lo siguiente: crearemos un proyecto java en Eclipse y en este definiremos una clase Operaciones.java, que es el código sobre el que vamos a realizar las pruebas de unidad. Esta clase va a ser de funcionalidad simple pues vamos a definir las cuatro operaciones básicas sobre enteros: suma, resta, multiplicación y división, donde la división la programaremos aposta con una funcionalidad equivocada. Para esta clase crearemos nuestra clase de testeo ClaseTest.java que tendrá cuatro métodos para comprobar cada uno de los de la clase Operacion. Finalmente ejecutaremos las pruebas de unidad para mostrar la simplicidad de la prueba y la facilidad de repetirla ante futuros cambios en el código sobre el que realizamos las pruebas. Los pasos serán (1) crear el proyecto java, (2) programar la clase Operacion.java, (3) definir sobre ella la clase de test ClaseTest.java y finalmente (4) ejecutar las pruebas de unidad:

1) Creamos un nuevo proyecto Java (File->New->Project…)


Al que llamaremos TutorialJUnit y pulsamos Next>
Con “Create new source folder” crearemos una carpeta de nombre test, donde luego irá la clase de test


2) En la carpeta src creamos la clase Operaciones.java

Que tiene el siguiente código (notar nuestra “equivocación” en el método dividir):

3) Y ahora creamos la clase de test sobre la anterior. Usamos para ello el asistente que nos da Eclipse:
En el asistente indicamos los siguientes datos:
Tras pulsar a Next> seleccionamos los métodos sobre los que queremos realizar pruebas de unidad:
Eclipse piensa en todo…
Y aquí tenemos la plantilla de tests que deberemos modificar para cubrir nuestras necesidades:
La modificamos así (hemos hecho comprobaciones simples pero aún así de utilidad):
4) Sobre la clase de pruebas, hacemos click con el botón derecho y ejecutamos como JUnit Test

Y nos aparece una nueva pestaña de Eclipse donde se nos muestran los resultados de las pruebas. Como nos esperábamos, hemos encontrado un fallo en los tests. Se ha detectado que el funcionamiento del método dividir no era el esperado, como ya sabíamos por haber programado este método aposta de forma equivocada:

3 - Bibliografía y referencias

[1] Página web oficial de JUnit (en http://junit.org/)
[2] Tutorial de JUnit de Lars Vogel (en http://www.vogella.com/articles/JUnit/article.html)
[3] http://es.wikipedia.org/wiki/JUnit
[4] http://en.wikipedia.org/wiki/JUnit

 4 - Autores

Diego Jesús y Francisco

Tutorial de uso del Plug-In para Eclipse Fat Jar.


Paso 1.  Creamos un nuevo proyecto java llamado "demolib".
             Dentro de él se crea una clase llamada "demolib.Demolib.java" con el siguiente código:

                                   package demolib;

                                   public class DemoLib {
                                             public static void sayHello() {
                                                      System.out.println("Hello");
                                             }
                                   }







Paso 2.  A continuación creamos un archivo jar usando el Plug-In Fat Jar:
          En la vista "Package-Explorer" (no en "Resource-View") click con botón derecho sobre nuestro   proyecto y seleccionamos "+ Build Fat Jar".


A continuación aparece un cuadro de diálogo, nombramos el fichero como demolib_fat.jar y luego presionamos "Finish".



 El fichero con extensión .jar ha sido creado en el directorio raíz del proyecto.






Paso 3. Seguidamente creamos un nuevo proyecto java llamado "demorun" y en propiedades del proyecto añadimos la librería "demolib/demolib_fat.jar" al Java Buid Path.



Paso 4.  Creamos una clase con método main.
    Dentro del proyecto "demorun" creamos una clase llamada "demorun.DemoRunMain.java" con el siguiente código:

                          package demorun;

                          import demolib.DemoLib;

                          public class DemoRunMain {
                                     public static void main(String[] args) {
                                                DemoLib.sayHello();
                                     }
                          }


          Tendriamos algo parecido a lo siguiente:



Paso 5.  Arranca el Build Fat Jar Dialog:
         Desde File-Menu ("File"->"Export") selecciona "+ Fat Jar Exporter" y pulsa "next >".

            


               Seleccionamos el proyecto "demorun" y pulsamos "next >".


                    
        Seguidamente aparece un cuadro de diálogo de configuración que muestra los ajustes actuales.



Paso 6.  Seleccionamos la clase principal.
             La clase principal, aquella que contiene el método estático main, debe ser definida en el jar. Click en el botón "Browse..." junto al campo editable y aparece:




     Seleccionamos "DemoRunMain" y click en botón "OK".
     Vemos como se establece el nombre completo cualificado "demorun.DemoRunMain" para la clase principal.


Paso 7.  Final
            Para finalizar se guardan los ajustes actuales pulsando el botón "Finish".


.

El fichero "demorun_fat.jar" ha siso creado en el directorio raíz del proyecto. Además el fichero ".fatjar" que almacena los ajustes de configuración ha sido creado también en el directorio raíz del proyecto.
El fichero jar creado contiene todas las clases de todos los ficheros jar referenciados (demolib_fat.jar) y las clases del proyecto. Este fichero puede ser ejecutado en cualquier parte, sin tener que definirse el classpath, porque todas las clases necesarias están incluidas dentro del "Fat Jar":

            > java -jar demorun_fat.jar
            Hello



Creación de Informes con Jasper Reports

Reportes con Conexión a Base de Datos

Frecuente, o mejor dicho siempre, los clientes desean ver reportes sobre los datos que se generan en el sistema y, en ocasiones, se encuentran almacenados en nuestra base de datos.

Si han tenido que hacer reportes de 7 o más columnas sabrán que esto no es tan sencillo como muchos de nosotros podríamos pensar. Muchos desarrolladores me han comentado que es lo más fácil que hay ya que, a lo más, nos tardaremos media hora en "crear el query" para obtener los datos que necesitamos...

Si bien esto podría ser cierto en la mayoría de los casos, lo que no siempre es fácil es mapear estos datos a los objetos que vamos a usar y aún menos el formaterarlos de manera que nuestro reporte sea fácil de entender y le proporcione al cliente la suficiente información como para que este le sea de utilidad.

La cosa se complica cuando nos piden reportes en formatos distintos al texto plano o HTML (en el caso de los sistemas web) como por ejemplo PDF, CSV, XLS, RTF, etc., ya que estos formatos no son manejados de forma nativa por Java


Podríamos usar iText para crear los reportes en PDF, JExcelAPI para los XLS, y así sucesivamente. Sin embargo estas APIs no trabajan de la misma forma, por lo que primero tendríamos que aprender a usar cada una de ellas además de que, en la mayoría de los casos, toda la información del formateo de los datos se encuentra en código Java duro, por lo que cualquier cambio requiere primero identificar entre nuestra maraña de código dónde se encuentra la sección que necesitamos modificar y posteriormente hacer este cambio.

Afortunadamente existe una alternativa para la creación de estos reportes: JasperReports. JasperReports es un API OpenSource que nos permite generar reportes en formatos PDF, XML, HTML, CSV, XLS, RTF, y TXT con solo unas cuantas líneas de código y guardar este reporte en un archivo, enviarlo por un OutputStream, o mostrarlo directamente con un visor especial (si usamos una aplicación swing).

Además nos permite integrar en nuestros reportes cosas como gráficas de todos tipos, tablas cruzadas, y subreportes para poder mostrar mejor nuestros datos.

Por si fuera poco los creadores de JasperReports nos proporcionan también un editor WYSIWYG para crear toda la parte visual de los reportes (formatos, posiciones, tipos de letra, estilos, imagenes, decoraciones, etc.) llamada iReport, la cual es un complemento perfecto para JasperReports.

iReports se encuentra en dos versiones, una es como una aplicación standalone básada en NetBeans (de hecho verán que la interface es casi la misma) y la otra es como un plugin para NetBeans 6.0, 6.1, y 6.5.

Lo primero que haremos es bajar el JasperReports y iReport. Este último lo usaremos en su faceta de aplicación standalone y no como plugin para NetBeans. Esto por aquellos que nos les guste usar el NetBeans.

Como ya había dicho: La última versión de iReport está basada en la plataforma de NetBeans por lo que, como pueden observar en la imagen siguiente, las interfaces de ambos son muy parecidas.


En este primer post veremos cómo crear reportes haciendo uso de una conexión a la base de datos directamente desde nuestro reporte.

Lo primero que haremos es crear una base de datos con tablas y datos de pruebas para poder tener algo interesante que ver en nuestros reportes. En este caso usaré MySQL versión 5.1, el cual pueden descargar desde su página oficial. Usando el conector para Java versión 5.1.13 que pueden descargar desde la página de MySQL. Pero cualquier base de datos que les guste funcionará para nuestros ejemplos.

La base de datos que usaré se llama "pruebaReportes" y contiene la tabla "participantes". Este es el script para la creación de esta tabla:


CREATE TABLE 'participantes' (            
                'ID' bigint(21) NOT NULL,               
                'NOMBRE' varchar(100) NOT NULL,         
                'USERNAME' varchar(100) NOT NULL,       
                'PASSWORD' varchar(100) NOT NULL,       
                'COMENTARIOS' varchar(100) default NULL,
                PRIMARY KEY  ('ID')                     
              ) ENGINE=InnoDB DEFAULT CHARSET=latin1


Y este es el script para poblar la tabla anterior:


insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (1,'Participante 1','par1user','part1pass','comentarios participante 1');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (2,'Participante 2','par2user','part2pass','comentarios participante 2');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (3,'Participante 3','par3user','part3pass','comentarios participante 3');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (4,'Participante 4','par4user','part4pass','comentarios respecto al participante 4');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (5,'Participante 5','par5user','part5pass','sin comentarios para el participante 5');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (6,'Participante 6','par6user','part6pass',NULL);
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (7,'Participante 7','par7user','part7pass','comentatios participante 7');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (8,'Participante 8','par8user','part8pass','comentarios participante 8');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (9,'Participante 9','par9user','part9pass','comentarios participante 9');
insert  into 'participantes'('ID','NOMBRE','USERNAME','PASSWORD','COMENTARIOS') values (10,'Participante 10','par10user','part10pass',NULL);


Ahora que tenemos nuestros datos crearemos un "datasource" en iReport para poder acceder a nuestros datos y hacer pruebas directamente, sin necesidad de una aplicación Java (por el momento). Para crear este datasource hacemos clic en el ícono "Report Datasources" ubicado en la barra de herramientas de iReport:



Con lo que se abrirá la ventana de "Connections / Datasources" que en este momento debe contener solo un "Empty datasource" y la conexión a una base de datos de prueba en HSQLDB. Ahora hacemos clic en el botón "New" para crear nuestro nuevo datasource.



En la nueva ventana que se abre seleccionamos "Database JDBC connection" y presionamos el botón "Next". En la siguiente ventana debemos proporcionar algunos datos como el nombre se le dará al datasource y los datos para realizar la conexión de la base de datos. Después de llenar estos datos su ventana debe haber quedado más o menos como la siguiente (recuerden usar el "JDBC Driver" que corresponda al manejador de base de datos que estén usando:



Antes de guardar esta configuración hagan clic en el botón "Test" para probar que todos los datos proporcionados son correctos. Si todo ha salido bien, al hacer clic en el botón "Save" la ventana actual debe cerrarse y nuestro datasource debe estar ahora en la ventana "Connections / Datasources".



Ahora pasaremos a crear nuestro nuevo reporte. Esta será la primer y única ocasión en la que haremos uso del "Report Wizard" para ayudarnos a generar el reporte. Para esto vamos al menú "File -> New...". Con esto se abrirá la ventana de "New File" en la que seleccionaremos el formato de nuestro reporte. En mi caso seleccionaré la plantilla "Wood" aunque pueden seleccionar la que ustedes deseen, y hacemos clic en el botón "Launch Report Wizard"



Este wizard nos ayudará a crear un reporte 100% funcional en 6 pasos (en realidad 5 ya que empezamos directamente en el paso 2) que podremos ver desde el mismo iReport sin necesidad de escribir una solo línea de código Java. Estos 7 pasos son:

  1. Selección de la ubicación en la que se guardará nuestro reporte.
  2. Selección del datasource e introducción del query para obtener los datos que nos interesan.
  3. Selección de los datos que queremos mostrar en el reporte.
  4. Creación de grupos para el reporte (se explicará en un post posterior).
  5. Selección del layout o acomodo de los datos en el reporte
  6. Felicitación por tenerminar nuestro reporte =D.

Los pasos interesantes son el 3 y el 4, así que será en estos en los que nos enfocaremos más.

El paso 1 se realiza de forma automática, así que no tenemos mucho que hacer en él. En el paso 2 (en donde comenzamos) seleccionamos el directorio en el que queremos guardar nuestro reporte y el nombre que tendrá.

Nota: La extensión de documentos de reportes generados por JasperReports es ".jrxml" que significa "jasper reports xml", y es un documento xml que contiene los datos para generar un archivo compilado (".jasper") que es el que usaremos principalmente en nuestras aplicaciones Java (aunque también podriamos optar por compilar nuestro archivo ".jrxml" desde la misma aplicación Java y así generar el archivo ".jasper" correspondiente).

En este momento no importa mucho en donde guardemos el archivo que se generará, ya que posteriormente tendremos que moverlo para que nuestra aplicación java pueda encontrarlo. Por mi parte llamaré al archivo "reporte1".

Hacemos clic en el botón "Next" para continuar con el paso 3. En este paso debemos seleccionar el datasource desde el que los datos del reporte serán tomados. Por default está seleccionado el "Empty datasource". Así que nosotros seleccionamos el datasource "Conexion MySQL Pruebas" (el datasource que creamos anteriormente).

Al hacer el cambio del datasource veremos que aparece un textarea con el título "Query(SQL)" y en la parte inferior debemos tener un mensaje de error que dice "Invalid query".



Esto ocurre porque, efectivamente, en el textarea no tenemos una consulta válida (de hecho no tenemos ninguna). Por lo que ahora corregiremos eso. Para esto tenemos 3 opciones:

  1. Escribir una consulta nosotros mismos de forma directa.
  2. Cargar una consulta que tengamos guardada en algún archivo .sql o .txt.
  3. Crear una consulta usando el "diseñador de consultas".

Nosotros haremos uso del diseñador de consultas. Hacemos clic en el botón "Design query" con lo que se abrirá una nueva ventana que está dividida en tres secciones.



La primer sección es la de la estructura de la consulta. Aquí básicamente podremos cambiar entre las sentencias que estamos editando (SELECT, WHERE, ORDER BY, etc.). La segunda sección es la de los elementos de nuestra base de datos (tablas, vistas, y temporales locales). Aquí podremos seleccionar los elementos de los que queremos obtener datos para la consulta. Finalmente la tercer sección nos muestra los elementos que hemos seleccionado de la segunda sección para que podamos seleccionar los datos a obtener.

La consulta que haremos será para obtener todos los datos de la tabla "participantes", con excepción del "ID". Para esto hacemos doble clic sobre el nombre de la tabla "participantes" en la segunda sección de la ventana que tenemos abierta. Con esto aparecerá en la tercer sección otra ventana con el título "participantes" y un conjunto de checkboxes, cada uno con un campo de nuestra tabla. Para generar la consulta que nos interesa solamente seleccionamos todos los checkboxes (con excepción del "ID") y veremos que la consulta se genera en la primer sección. Ya solo damos clic en el botón "OK".



Con esto ya tendremos nuestra consulta en el textarea correspondiente y podemos continuar con el paso 4, para lo que hacemos clic en el botón "Next".

En este paso solo tenemos que seleccionar cuáles campos del query generado en el paso anterior queremos que se muestren en el reporte. Como nosotros queremos que se muestren todos pasamos todos los campos del lado izquierdo al lado derecho y hacemos clic en el botón "Next".



Ahora en el paso 5 debemos seleccionar cómo queremos que los datos sean agrupados. Esto lo explicaré en algún otro post, pero por el momento dejemos todo en blanco y demos clic en el botón "Next".

El último paso es el solamente una felicitación por haber creado un nuevo reporte ^-^.



Ahora hacemos clic en el botón "Finish" y ya podremos ver la plantilla de nuestro reporte.



Si queremos ver como se verá el reporte final, en este caso, podemos ver un preview con los datos reales si cambiamos a la vista de "preview" en la ventana del editor.



Al hacer clic en la pestaña de "preview", nuestro reporte se compilará y se mostrará. En este caso el reporte puede ser pre-visualizado porque las siguientes condiciones se cumplen:

  • Tenemos una base de datos poblada (esto es muy importante, ya que si no tiene datos obtendremos un mensaje de error).
  • Tenemos un datasource configurado para esta base de datos.
  • Nuestro reporte hace una consulta directa a esta base de datos a través del datasource anterior.
  • El reporte está preparado para mostrar los datos recuperados anteriormente.

Como veremos en los siguientes posts, podría ser que no todas estas condiciones se cumplan al mismo tiempo, por lo que tendremos problemas para ver los datos en el preview del reporte.

Algo importante que ocurre al hacer este preview es que el reporte se compila generando el archivo "reporte1.jasper" el cual es el archivo que usaremos desde la aplicación Java que crearemos en un momento.

Si queremos compilar nuestro reporte de forma manual podemos hacer clic en el botón "Compile Report" de la vista de diseño:



Haremos algunas modificaciones para que este reporte se vea un poco mejor: primero cambiaremos el título que dice "Wood Title" por "Reporte de Participantes", cambiamos el color de texto a negro, y eliminamos el fondo y el subtitulo que tiene.

Además cambiamos el título de cada una de las columnas por algo más claro. Por ejemplo, podemos cambiar el título de la columna "participantes_USERNAME" a "Usuario", "participantes_NOMBRE" a "Nombre", etc.

Al final mi reporte queda de esta forma:



Con este preview:



Ahora que tenemos un reporte que nos agrada (o al menos que no se ve tan mal) veremos cómo generar este reporte desde una aplicación Java.

Nota: Hay algunas notaciones usadas en la plantilla del reporte que tal vez no comprendan como $F{participantes_USERNAME} y $V{PAGE_NUMBER}. Esta es una sintaxis especial que usa JasperReports para definir campos de objetos y variables, respectivamente. Existe otro tipo de dato que se usa llamado propiedades ($P{propiedad}). Como todo esto fue colocado por el wizard no lo explicaré hasta el siguiente post, por ahora solo confíen en que deben estar ahí.

Lo primero que haremos es crear un nuevo proyecto en NetBeans. Para esto vamos al menú "File -> new Project...". En la ventana de nuevos proyectos seleccionamos la categoría "Java" y de tipo de proyecto seleccionamos "Java Application" y hacemos clic en el botón "Next". En la siguiente ventana introducimos el nombre de nuestro proyecto y dejamos seleccionada la opción "Create Main Class" y "Set as Main Project".



Hacemos clic en el botón "Finish" para que nuestro proyecto se genere. Lo que haremos a continuación es crear una biblioteca que contenga los archivos jars básicos necesarios de JasperReports. De esta forma no tendremos que agregar cada uno de los jars cada vez que necesitemos usar JasperReports en un proyecto. Además si actualizamos la versión del API que usamos, solo debemos actualizar esta biblioteca.

Para crear nuestra biblioteca vamos al menú "Tools -> Libraries":



Con esto se abrirá la ventana del "Library Manager". En esta ventana hacemos clic en el botón "New Library":



En la ventana que se abre escribimos el nombre de la nueva biblioteca (en mi caso será "JasperReports") y en el tipo de la biblioteca seleccionamos la opción "Class Libraries".



Al hacer clic en el botón "OK" regresaremos al "Library Manager" y tendremos nuestra nueva biblioteca creada. Pero aún nos hace falta agregar los archivos jars que conformarán esta biblioteca. Nos aseguramos que la pestaña "Classpath" esté seleccionada y hacemos clic en el botón "Add Jar/Folder" situado a la derecha. Se abrirá un cuadro de dialogo para que seleccionemos los jars que queremos agregar.



Navegamos hasta el directorio en el que tenemos los jars de JasperReports que bajamos anteriormente. Para que los ejemplos que haremos más adelante (en los siguientes posts) funcionen, debemos agregar a la biblioteca los siguientes jars:

  • jasperreports-3.7.6.jar
  • jasperreports-3.7.6-javaflow.jar
  • jasperreports-fonts-3.7.6.jar
  • commons-beanutils-1.8.0.jar
  • commons-collections-2.1.1.jar
  • commons-digester-1.7.jar
  • commons-logging-1.0.4.jar
  • commons-javaflow-20060411.jar
  • groovy-all-1.7.5.jar
  • iText-2.1.7.jar
  • png-encoder-1.5.jar
  • poi-3.6.jar

Algunos de estos jars se encuentran en el directorio "dist" y otros en el directorio "lib" del archivo .zip de JasperRepots que bajamos anteriormente.

Hacemos clic en el botón "Add Jar/Folder" y con esto tendremos lista nuestra biblioteca "JasperReports" para agregarla a nuestro proyecto.



Hacemos clic en el botón "OK" para regresar al ambiente de trabajo.

Ahora hacemos clic derecho en el nodo "Libraries" de la ventana "Projects". Con esto se abrirá un menú contextual con 4 opciones, seleccionamos la opción "Add Library..."



En la ventana que se abre seleccionamos la biblioteca que creamos anteriormente ("JasperReports") y hacemos clic en el botón "Add Library". Al hacer esto veremos se agregar al nodo "Libraries" de nuestro proyecto todos los jars que tiene nuestra biblioteca.

Nota: Si no crearon la biblioteca como se indica en pasos anteriores pueden agregar cada uno de los jars manualmente seleccionando la opción "Add JAR/Folder..." del menú contextual



¿Recuerdan que cuando vimos el preview del reporte que creamos en iReports se generó un archivo "reporte1.jasper"? Tomamos este archivo y lo colocamos en el directorio raíz del proyecto de NetBeans que acabamos de crear (la raíz del proyecto es el directorio en el que se encuentran los subdirectorios "nbproject", "src", entre otros).



Ahora veremos el código para generar el reporte en varios formatos.

Lo primero es crear una conexión a la base de datos que creamos anteriormente. Si no saben cómo crear una conexión JDBC desde Java, pueden ver este artículo. Si recuerdan nuestra base de datos se llama "pruebareportes". Por lo que el código para generar la conexión en el siguiente:


Class.forName("com.mysql.jdbc.Driver"); 
Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost:3306/pruebareportes", "usuario", "password");


Nota: No olviden agregar el jar del driver de MySQL que bajamos anteriormente (mysql-connector-java-5.1.13-bin.jar) al proyecto al nodo "Libraries" de la ventana "Project" usando la opción "Add JAR/Folder" o también pueden agregar la biblioteca "MySQL JDBC Driver" que ya trae incluido el NetBeans, de la misma forma que agregamos la de JasperReports.

Seguramente en este momento el NetBeans les está marcando un error en estas dos líneas que hemos agregado. Esto es porque al tratar de hacer la conexión es posible que ocurra un error, y por lo tanto es posible que se lance una excepción de tipo "java.sql.SQLException". Para solucionar esto pueden hacer dos cosas. La primera es rodear estas líneas (y las siguientes que crearemos) en una clausula try/catch. La segunda opción (la que yo usaré) es agregar la clausula throws Exception en el método main:


public static void main(String[] args) throws Exception
{
        Class.forName("com.mysql.jdbc.Driver");
        Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost:3306/pruebareportes", "root", "123");
}


Pueden probar que la conexión se realiza correctamente presionando F6 o haciendo clic en el botón "Run Main Project". Si la conexión se realiza correctamente veremos el mensaje


run: 
BUILD SUCCESSFUL (total time: 0 second)


En la ventana "Output". De lo contrario verán el error el en stacktrace de la excepción que se lanzó. Una vez que la conexión se realice exitosamente podremos proseguir con los pasos restantes.

Lo siguiente que debemos hacer es cargar el archivo ".jasper" generado anteriormente y colocarlo en un objeto "net.sf.jasperreports.engine.JasperReport". Para esto hacemos uso de la clase de utilidad "net.sf.jasperreports.engine.util.JRLoader":


JasperReport reporte = (JasperReport) JRLoader.loadObject("reporte1.jasper");


Nota: Podemos cargar el archivo de esta forma gracias a que colocamos el archivo "reporte1.jasper" en la raíz del proyecto. Si lo colocaron en otra ubicación será necesario que pasen como parámetro al método "loadObject" la url absoluta en la que se encuentré el archivo.

Ahora el objeto "reporte" contiene la definición del reporte, pero aún hace falta que llenemos este reporte con los datos que obtendrá de la base de datos. Para esto usamos la clase "net.sf.jasperreports.engine.JasperFillManager". Esta clase tiene un método estático, "fillReport", que nos permite llenar el reporte con datos obtenidos de distintas fuentes de datos (una de estas fuentes es la sentencia SQL que escribimos al generar el reporte con el wizard en iReports y la conexión que usaremos en un momento, veremos qué otras fuentes de datos existen y cómo usarlos en los siguientes posts). En este caso la fuente de datos es la conexión directa a la base de datos que creamos anteriormente (el objeto conexion):


JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, null, conexion);


Pasamos "null" como segundo parámetro porque no estamos pasando ningún parámetro al reporte (esto también lo veremos después).

El objeto "JasperPrint" que obtenemos como resultado de la invocación del método "fillReport" es la representación de nuestro reporte (ahora con datos) que podemos mandar a imprimir, mostrar en pantalla (si estamos usando una aplicación swing o awt), o, como en este caso, guardarlo en un archivo.

Si están haciendo una aplicación swing y quieren mostrar este reporte directamente en un componente pueden pasar el objeto "JasperPrint" que acabamos de crear como parámetro a un nuevo objeto "net.sf.jasperreports.view.JasperViewer", el cual es un componente swing, y agregar este último a un panel.

Para guardar este reporte a un archivo debemos usar un "net.sf.jasperreports.engine.JRExporter". "net.sf.jasperreports.engine.JRExporter" es una interface, y las clases que la implementan nos permiten generar el reporte en distintos formatos de una forma sencilla. Veremos cómo generar los reportes en los siguientes formatos:

  • PDF
  • HTML
  • CSV
  • RTF
  • TXT
  • XLS
  • XML
  • XLSX
  • DOCX
  • PPTX

Entre muchos otros.

Primero declaramos una referencia a un objeto de tipo "JRExporter" de la siguiente forma:

JRExporter exporter = 


Será esta referencia la que usaremos de ahora en adelante. Para que nuestro reporte sea guardado en formato PDF creamos un objeto de tipo "net.sf.jasperreports.engine.export.JRPdfExporter" y lo asignamos a nuestra referencia exporter:


JRExporter exporter = new JRPdfExporter();


Ahora, las siguientes líneas son comunes no importando el formato en el que vaya a quedar nuestro reporte:


exporter.setParameter(JRExporterParameter.JASPER_PRINT,jasperPrint); 
exporter.setParameter(JRExporterParameter.OUTPUT_FILE,new java.io.File("reportePDF.pdf"));
exporter.exportReport();
La primer línea asigna a nuestro objeto "exporter" el "jasperPrint" (el reporte con datos) que creamos anteriormente. La segunda línea le dice al "exporter" cuál será el nombre del archivo generado (en este caso "reportePDF.pdf"). Recuerden cambiar el nombre y la extensión del archivo cada vez que cambiemos de formato.

La última línea es la que realiza el proceso de exportación.

Si ahora ejecutamos nuestra aplicación veremos que en el directorio raíz del proyecto se ha creado un archivo llamado "reportePDF.pdf":



Con el siguiente contenido:



Por lo que nuestra prueba ha sido exitosa ^-^.

Ahora, para que nuestro reporte sea exportado a formato HTML cambiamos la línea:


JRExporter exporter = new JRPdfExporter();


por


JRExporter exporter = new JRHtmlExporter();


y el nombre del archivo de "reportePDF.pdf" a "reporteHTML.html". Al ejecutar nuevamente nuestra aplicación tendremos veremos que se genera el archivo "reporteHTML.html" en el directorio raíz de la aplicación:



Con el siguiente contenido:



Como pudimos ver, con un par de modificaciones pudimos hacer que nuestro reporte se generara en un formato completamente distinto. Con el resto de los formatos es igual de simple. Usamos las siguientes clases para generar los reportes en los siguientes formatos:

  • PDF: net.sf.jasperreports.engine.exportJRPdfExporter
  • HTML: net.sf.jasperreports.engine.exportJRHtmlExporter
  • CSV: net.sf.jasperreports.engine.exportJRCsvExporter
  • RTF: net.sf.jasperreports.engine.exportJRRtfExporter
  • XLS: net.sf.jasperreports.engine.exportJRXlsExporter
  • XML: net.sf.jasperreports.engine.exportJRXmlExporter
  • TXT: net.sf.jasperreports.engine.exportJRTextExporter
  • XLSX: net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter
  • DOCX: net.sf.jasperreports.engine.export.ooxml.JRDocxExporter
  • PPTX: net.sf.jasperreports.engine.export.ooxml.JRPptxExporter

Entre muchos otros ^_^

Para generar archivos .txt tendrán que agregar, además, estas dos líneas:


exporter.setParameter(JRTextExporterParameter.CHARACTER_WIDTH, 12);//text exporter
exporter.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT, 12);//text exporter


Este es el código de la clase "Main":


public class Main
{
    /**
     * @param args argumentos recibidos por la linea de comandos
     */
    public static void main(String[] args) throws Exception
    {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conexion = DriverManager.getConnection("jdbc:mysql://localhost:3306/pruebareportes", "usuario", "password");

        JasperReport reporte = (JasperReport) JRLoader.loadObject("reporte1.jasper");
        JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, null, conexion);

        JRExporter exporter = new JRPdfExporter();
        
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_FILE, new java.io.File("reportePDF.pdf"));
        exporter.exportReport();
    }
}