[Métodos] Serializar y Deserializar objetos con Java
La serialización y deserialización son dos procesos utilizados en programación para convertir datos como texto o incluso un objeto de una clase, a un formato de código binario para almacenarlo o transmitirlo, y luego revertir ese proceso en otro momento o lugar para recuperar los datos originales.
Tomemos como ejemplo la sigueinte clase Persona
publicclassPersonaimplements Serializable {privatestaticfinallong serialVersionUID =1L;// Identificador de versión para la serializaciónprivate String nombre;privateint edad;private String ciudad;// CONSTRUCTORES// GETTERS y SETTERS}
Es una simple clase en java que implementa la interfaz Serializable, de la cual cobra sentido el atributo serialVersionUID ya este número de versión nos indicará a la hora de deserializar si la clase ha sufrido algún cambio o modificación.
El siguiente ejemplo, muestra un método main que:
Instancia un objeto de la clase Persona
Serializa el objeto y lo guarda en un archivo, misma ubicación donde se está ejecutando, bajo el nombre de "persona.ser"
Por último, este fragmento de Deserialización pudiera estar en otro lado, pero hace lo propio deserializando un archivo "persona.ser", en la misma ubicación que la ejecución y lo lleva a un objeto Persona
publicstaticvoidmain(String[] args){// Crear una instancia de Persona
Persona persona =new Persona("Darío",35,"Buenos Aires");// Serializacióntry(ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("persona.ser"))){
oos.writeObject(persona);
System.out.println("Persona serializada correctamente.");}catch(IOException e){
e.printStackTrace();}// Deserializacióntry(ObjectInputStream ois =new ObjectInputStream(new FileInputStream("persona.ser"))){
Persona personaDeserializada =(Persona) ois.readObject();
System.out.println("Persona deserializada: "+ personaDeserializada);}catch(IOException | ClassNotFoundException e){
e.printStackTrace();}}
Por último, nuestra propia implementación para reutilizar en métodos independientes:
publicstaticvoidmain(String[] args){// Ejemplo de serialización y deserialización
Persona persona =new Persona("Dario",35,"Buenos Aires");// Serialización
serializarObjeto(persona,"ruta/del/directorio","persona.ser");// Deserialización
Persona personaDeserializada =(Persona) deserializarObjeto("ruta/del/directorio","persona.ser", Persona.class.getName());
System.out.println("Persona deserializada: "+ personaDeserializada);}
Maven es una herramienta de software para la gestión y construcción de proyectos Java creada por Jason van Zyl, de Sonatype, en 2002. Es similar en funcionalidad a Apache Ant, pero tiene un modelo de configuración de construcción más simple, basado en un formato XML. (fuente: Wikipedia)
Antes de Maven
Cada proyecto solía definir su forma de incluir dependencias, definir versión del proyecto, de compilar desde una version de jre a la version target, como realizar pruebas unitarias, generar reportes, crear ejecutables a partir del código fuente y hasta como se debería hacer la entrega de ese ejecutable.
Todo esto conlleva a que los desarrolladores tuvieran que invertir mucho tiempo para poder sumarse a un proyecto y al final del día para poder entregar el ejecutable final. Luego de esto, vuelta a empezar...
POM
El corazón de un proyecto manejado por maven es un fichero llamado pom.xml, que significa Project Object Model y debe encontrarse en la raíz de nuestro projecto.
En el ejemplo anterior podemos ve que se definen las coordenas maven, la manera única de identificar a cualquier proyecto maven entre otro proyectos maven.
GroupId: identifica a nuestra empresa o persona, y debe ser nuestro dominio invertido. Opcionalmente puede contener el grupo de aplicaciones
ArtifactId: identifica a nuestro artefacto, nuestro proyecto o microservicio.
version: la version del proyecto mismo.
Adicionalmente podemos encontrar debajo de las coords nuestro packaging, el tipo de empaquetado que resulta de nuestro projecto, pudiendo ser jar, war, ear o pom, entre otras. Si no se espefica ninguno, tomará el por defecto: jar.
Los ciclos de vida
Maven cuenta con 3 ciclos de vida predefinidos: clean, default y site
Clean: se encarga de eliminar la carpeta target básicamente.
Default: maneja el ciclo de vida pero de nuestro proyecto.
Site: se encarga de generar la documentación si es que la hubiera.
Cada uno de estos ciclos se puede ejecutar de manera independiente, aunque por lo general llamaremos al clean y a algunas de las fases de Default.
Fases de los ciclos de vida
Cada ciclo de vida de maven incluye fases progresivas, es decir que cada fase se ejecutará luego de haber ejecutado la anterior aunque no la llamemos.
Clean
pre-clean: ejecuta los procesos necesarios para la limpieza.
clean: remueve todos los archivos generados en construcciones anteriores.
post-clean: finaliza los procesos de limpieza.
Default
validate: valida que el proyecto sea correcto y la información esté disponible.
compile: compila el código fuente del proyecto.
test: ejecuta los test unitarios usando un framework de testing.
package: toma el código compilado y lo empaqueta en un formato distribuible, como un jar.
verify: corre los checks de las pruebas de integración para asegurar que la calidad haya sido alcanzada.
install: instala el empaqueta, según coordenadas, en el repository local para que otro proyecto pueda usarlo.
deploy: copia el empaqueta del repositorio local al repositorio remoto, si es que lo hubiera.
Site
pre-site: ejecuta los procesos necesarios para esta fase.
site: genera la documentación del proyecto.
post-site: finaliza los procesos de esta fase y prepara el sitio para el despliegue.
site-deploy: despliega los archivos generados al servidor especificado.
Para el listado completo de las fases de cada ciclo visitar la documentación de maven aquí
Dependency Manager
Una de las caracteristicas más importantes de maven es la gestión de dependencias. Haciendo uso de las coordenadas podemos declaras dependencias para nuestro proyecto, estas se buscan en nuestro repo local y de no encontrarlas se descargán de maven central o repositorio que hayamos definido y luego se instalan en nuestro repositorio maven local para posterior uso. A continuación este ejemplo:
Dependencias, dependencias transitivas y resolución de conflictos
Como buen gestor de dependencias maven se encarga de incluir a nuestro proyecto las dependencias que declaremos en el pom, asi como también de las dependencias transitivas, estas son las dependencias de nuestras dependencias para que estas puedan funcionar correctamente.
También se encarga de la resolución de conflictos, en el ejemplo de la imagen nuestras dependencias 1 y 2 dependen de B, de ser la misma versión sólo la incluirá una vez, de ser distintas versiones tomará la mas nueva como válida.
Scope, type, optional y exclusion
Dentro de la etiqueta <project>, declaramos una sección de <dependencies> la cual incluye todas nuestras librerias envueltas con la etiqueta <dependency>, está a su vez incluye:
Coordenadas: estas son obligatorias y se utilizan para identenficar una libreria.
type: corresponde a la extensión del archivo. Es opcional y por defecto es jar.
scope: se refiere a como encontrar la dependencia y de como agregarla al classpath de la aplicación. Hay 5 scopes disponibles:
compile: este es el valor por defecto si se omite, tiene que ser encontrada en el momento de la compilación y estará disponible en todos los classpath. Será propagada a los proyectos que dependan de esta.
provided: es similar a compile, pero indica que se espera que el JDK o un contenedor lo provea al momento de ejecución. Sólo está disponible en el classpath de compilación y test, y no es transitiva.
test: este scope indica que la dependencia no es requerida para el uso normal de la aplicación, y sólo esta disponible para las fases de compilación y ejecución pero de los tests. No es transitiva.
runtime: este scope indica que la dependencia no es requerida para la compilación, pero si en la ejecución. Estará en el classpath de ejecucion y test, pero no en el classpath de compilación.
system: es similar a provided excepto que tenés que proveer el JAR que lo contiene de manera explícita. El artefacto siempre está disponible y nunca será buscando en los repositorios.
optional: Marca una dependencia como optional cuando este projecto en si mismo es una dependencia.
Más Maven
Aun quedan temas por cubrir como herencia, super POM, Standard Directory Layout, Repositorios, Plugins, Arquetipos, instalación
Los principios de diseño de software son como una guia que nos ayuda dando pautas para el desarrollo de estas aplicaciones.
A diferencia de los patrones de diseños, los principios no proveen con pasos, situaciones donde aplicarlos, es un poco mas generico.
Alguno de estos principios son siglas en ingles, obviamente, y son autoexplicativos. Alguno de ellos son kiss dry yagni soc solid.
Kiss (Keep it simple, stupid)
"Mantenelo simple corazón", esa es mi traducción por lo del beso y el corazón, aun que no haga falta ser bilingue para saber a que ser
refiere la ultima S.
Otra variante podría ser invertir la palabras finales resultando ser "Mantenelo estupidamente simple" (keep it stupid simple)
Este principio nos dice que tanto la documentación, el diseño, el código debe ser tan simple como sea posible,
como si se tratará de leer una guia a prueba de tontos. Evitando la sobre-complicacíon cuando ésta sea innecesaria.
Luego de algún tiempo programando tendemos a aplicar nuestra experiencia resolviendo cuestiones no solicitadas, por ejemplo
crear un formulario para visualizar datos existentes en una base de datos y queremos realizar una progresive web app con soporte de
multilenguaje y personalización de estilos en tiempo de ejecución, con un backend con una arquitectura de microservicios,
con servidores de descubrimiento, servidor de para balancear la carga, otro para estadisticas y métricas, montado sobre contenedores...
y en fin muchas herramientas cuando existen alternativas mas sencillas.
Este es el principio más dificil de seguir en terminos de escalabildad. Por que nuestra solución sencilla es ideada para unos pocos usuarios,
pero nuestro cliente confia que pronto tendrá cientos o miles de usuarios y pronto serán usuarios insatisfechos quejandose de lo lenta que
resulta la herramienta que creamos manteniendo las cosas lo mas simple posible.
Será nuestra visión la que determine hasta donde se pueden mantener las cosas simples
DRY (Don’t Repeat Yourself))
O en español SECO (Siempre evita codigo oscuro), la máxima de este principio es evitar el uso del CTRL+C + CTRL+V, repitiendo funcionalidades
entre distintas clases o métodos, ya que esto haria que el proyecto en general tenga mas lineas de codigo, sea dificil de entender y de
mantener.
SOLID
Single Responsibility
Open/Closed
Liskov Sustitution
Interface segregation
Dependency inversion
A este principio le pusieron unas solidas ganas, introducido por Robert C. Martin y sus siglas agrupan otros 5 principios de la programacion orientada a objetos.
Single Responsibility, el principio de responsabilidad unica nos dice que una pieza de codigo tiene que tener una unica responsabilidad.
Ese metodo getUsuario(id) deberia obtener un usuario por su id, o almenos eso se espera de el, pero si al inspeccionar de cerca el metodo
nos damos cuenta que obtiene el usuario, actualiza la fecha de ultima actividad y le envia un mail con las novedades claramente estaria
violando este principio, haciendo a la aplicacion dificil de entender por su impredictibilidad. Lo mas razonable sea contar con otros
metodos como actulizarUltimaActividad(usuario) y informarNovedades(usuario) que se encarguen de una sola cosa.
Open/Closed, el principio de Abierto/Cerrado nos dice que una pieza de codigo tiene que estar abierta a extensiones pero cerrada al modificaciones.
Este principio esta destinado a clases que puedan ser heredadas, donde sus clases hijas puedan extender su funcionalidad, pero sin cambiar lo que existia.
Liskov sustitution, el principio de sustition de Liskov nos dice que cada clase puede ser sustituida en lugar de su padre, sin la necesidad
de conocer cual se esta implementando. Esto pasa generalmente al usar colecciones, definimos un objeto tipo List aunque la implementacion
podria ser ArrayList, LinkedList.
Interface segregation, el principio de segregacion de interfaces dice que el codigo cliente no debiera estar atado a funcionalidades innecesarias
al implementar una interfaz, esta no debe segregar metodos de proposito general. Una solucion a este problema es romper la interfaz en varias
interfaces mas pequeñas y mas especificas. Otra solucion es el patron adapter, que permite heredar de una clase que implementa una interfaz extensa
Dependency inversion, el pricipio de inversion de dependencia nos dice que se debe depender de abstracciones y no de implementaciones,
desacoplando asi los modulos de alto nivel de los modulos de bajo nivel. La Inyección de Dependencias es uno de los métodos que siguen este principio.
YAGNI (You aren’t gonna need it)
El principio de lo no vas a necesitar tiene su origen en la programación extrema, y propone evitar aquellas piezas de codigo que se desarrollan
por si acaso, generalmente sobrevalidaciones, sin estar seguros de necesitarlo y nos dice no, no lo vas a necesitar.
SOC (Separation of concern)
El principio de separacion de conceptos nos habla de los diferentes aspectos de la funcionalidad de nuestra aplicación.
Por ejemplo la capa de negocio, la capa de datos etc. Un buen ejemplo de separación es el patrón MVC(Modelo, vista, controlador).
The Boy Scout rule
Este no es un acronimo, si lo fuese seria TBSR, pero basicamente nos propone aplicar la regla del boyscout, dejar el campo en mejores condiciones
de lo que lo encontamos. Como desarrolladores siempre se puede hacer un pequeño cambio para mejorar la calidad de nuestro codigo, algo que veamos
al pasar y que estamos seguros que podemos mejorar, siempre y cuando este no sea un cambio.
La Ley de Demeter
Según este principio, una pieza de codigo solo debe tener conocimiento limitado de otras piezas de codigo, y solo conocer aquellas
que con las que está relacionadas. Es como aquella frase que dice nunca hables con extraños, podriamos agregar con amigos cerrcanos.
El principio de Hollywood
Este principio está basado en la típica respuesta que se les da a los actores que hacen una audicion para una película: "No nos llame, nosotros le llamaremos".
Un ejemplo del principio de Hollywood es la inversión de control (IoC), que hace que una clase obtenga las referencias a objetos
que necesita para poder funcionar, a través de una entidad externa, como el contenedor de Spring.
El acrónimo ACID en el mundo de base de datos se refiere a un estándar de propiedades que garantizan que las transacciones de la base de datos se procesen de manera confiable.
Está especialmente enfocado en cómo una DB se recupera ante cualquier falla que pueda ocurrir al procesar una transacción.
Puntualmente este acrónimo es:
Atomicity
Si cuando una operación consiste en una serie de pasos, bien todos ellos se ejecutan o bien ninguno, es decir, las transacciones son completas.
Lo que hace que la serie de operaciones sea "indivisible".
Una garantía de atomicidad evita que las actualizaciones de la base de datos se produzcan solo parcialmente
Consistency
La coherencia es un término muy general, que exige que los datos deben cumplir con todas las reglas de validación.
Todas las reglas de validación deben verificarse para garantizar la coherencia.
Isolation
Esta propiedad asegura que una operación no puede afectar a otras.
Durability
Esta propiedad asegura que una vez realizada la operación, esta persistirá y no se podrá deshacer aunque falle el sistema y que de esta forma los datos sobrevivan de alguna manera.
Cumpliendo estos 4 requisitos un sistema gestor de bases de datos puede ser considerado ACID Compliant.
Que una DB cumpla con las propiedades ACID, es un factor que ayuda a determinar cual opción tomar.
SOLID es el acrónimo en el mundo de desarrollo de software, no sólo se limita a java sino a todos los lenguajes, que Michael Feathers creó, basado el paper “Design Principles and Design Patterns” sobre los principios de la programación orientada a objetos que Robert C. Martin(uncle bob) había recopilado en el año 2000.
Cohesión es el grado en que el contenido de un módulo está relacionado entre sí. Acoplamiento es el grado de interdependencia que tienen dos módulos de software entre sí.
SRP: Principio de responsabilidad única:
A class should have only one reason to change.
Traducido al español sería “una clase debería tener una, y solo una, razón para cambiar”. Esto es precisamente, “razón para cambiar”, lo que Robert Martin identifica como “responsabilidad”.
El propio Bob te lo resume asi nomás: “Gather together the things that change for the same reasons. Separate those things that change for different reasons”, es decir: “Reunir las cosas que cambian por las mismas razones. Separa aquellas que cambian por razones diferentes”.
OCP: Principio de abierto/cerrado:
Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
El segundo principio de SOLID lo formuló Bertrand Meyer en 1988 en su libro “Object Oriented Software Construction”
y dice: “Deberías ser capaz de extender el comportamiento de una clase, sin modificarla”.
En otras palabras: las clases que usas deberían estar abiertas para poder extenderse y cerradas para modificarse.
Imaginemos un pintor que pinta figuras, como el siguiente ejemplo:
MAL
class Figura {}
class Cuadrado extends Figura {}
class Circulo extends Figura {}
class Pintor {
void pinta (Collection<Figura> figuras) {
for (Figura figura: figuras) {
if (figura instanceof Cuadrado) {
pinta((Cuadrado) figura);
} else if (figura instanceof Circulo) {
pinta((Circulo) figura);
}
}
}
void pinta (Cuadrado cuadrado) {
// ...
}
void pinta (Circulo circulo) {
// ...
}
}
El problema con el ejemplo anterior es que cuando necesitemos agregar nuevas figuras, el pintor debe modificarse violando el principio de abierto/cerrado.
Una solución a este problema que permita extender pero se cierre a modificaciones es el siguiente:
OK
interface Figura {
void pinta();
}
class Cuadrado implements Figura {
@Override
public void pinta() {
// ...
}
}
class Circulo implements Figura {
@Override
public void pinta() {
// ...
}
}
class Pintor {
void pinta (Collection<Figura> figuras) {
for (Figura figura: figuras) {
figura.pinta();
}
}
}
LSP: Principio de substitución de Liskov:
T obj = new T();
T obj = new S();
Subtype Requirement: Let φ(x) be a property provable about objects x of type T. Then φ(y) should be true for objects y of type S where S is a subtype of T.
En español y dice que “Sea φ (x) una propiedad comprobable sobre objetos x de tipo T, Entonces φ (y) debería ser verdadero para los objetos Y de tipo S donde S es un subtipo de T”.
Dicho de otra manera: "las clases derivadas deben poder sustituirse por sus clases base".
Esto significa que los objetos deben poder ser reemplazados por instancias de sus subtipos sin alterar el correcto funcionamiento del sistema o lo que es lo mismo: si en un programa utilizamos cierta clase, deberíamos poder usar cualquiera de sus subclases sin interferir en la funcionalidad del programa.
Según el propio Robert Martin incumplir el principio de substitución de Liskov implica violar a su vez también el principio de Abierto-Cerrado.
Si intentamos ejeutar el siguiente código obtendremos la siguiente salida:
Exception in thread "main" java.lang.ArrayStoreException:
java.lang.String
at proves.Main.main(Main.java:12)
En algún momento de la historia existía solo java.util.Date... y llegó java.sql.Timestamp a hacerle compañía que es un Date + nanosegundos, su definición es:
public class Timestamp extends java.util.Date
¿Problemas? No...ninguno, ¿porqué preguntas? Veamos lo siguiente:
Date date = new Date();
Timestamp ts = new Timestamp(date.getTime());
System.out.println(date.equals(ts));
System.out.println(ts.equals(date));
Recordemos el javadoc para el metodo equals de object:
Indicates whether some other object is "equal to" this one.
The equals method implements an equivalence relation on non-null object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and
only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and
y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y)
consistently return true or consistently return false, provided no information used in equals
comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
Según el cual, el método implica debe ser simétrico: si x e y son iguales si y solo si y y x también lo son.
Pero...
Date date = new Date();
Timestamp ts = new Timestamp(date.getTime());
System.out.println(date.equals(ts));
System.out.println(ts.equals(date));
Ejecutar el siguiente código resulta en un true seguido de un false
ISP: Principio de segregación:
Clients should not be forced to depend on methods they do not use.
El cuarto principio definido por el propio Robert Martin dice que "Los clientes no deben ser forzados a depender de métodos que no usen."
En otras palabras es preferible contar con muchas interfaces que definan pocos métodos que tener una interface maestra que haga todo.
Dada la siguiente clase encargada de la comunicación, que decribe 2 métodos para enviar los mismo a través de un String o un Object:
public class Comunicador {
public void enviaMensaje (String mensaje) {...}
public void enviaMensaje (Object object) {...}
}
Se nos pide agregar una encriptación para la misma, por lo tanto agregamos un método mas que se corresponde un nuevo Enum:
enum Encriptacion {
NINGUNA, ENCRIPTACION_DEBIL, ENCRIPTACION_FUERTE
}
public class Comunicador {
public void setEncriptacion (Encriptacion restriccion) {}
public void enviaMensaje (String mensaje) {}
public void enviaMensaje (Object object) {}
}
Decidimos abstraer la clase a una interface para que distintos clientes puedan hacer uso de ella:
public interface Comunicador {
static enum Encriptacion {
NINGUNA, ENCRIPTACION_DEBIL, ENCRIPTACION_FUERTE
}
public void setEncriptacion (Encriptacion restriccion);
public void enviaMensaje (String mensaje);
public void enviaMensaje (Object object);
}
Aun que estaríamos forzando a posibles clientes de implementar un nivel de encriptación que nunca necesiten:
public class ComunicadorImpl implements Comunicador {
...
}
La solución es segregar en una interface el envio de los mensajes y en otra la encriptación:
public interface Comunicador {
public void enviaMensaje (String mensaje);
public void enviaMensaje (Object object);
}
public interface Encriptable {
static enum Encriptacion {
NINGUNA, ENCRIPTACION_DEBIL, ENCRIPTACION_FUERTE
}
public void setEncriptacion (Encriptacion restriccion);
}
public class ComunicadorImpl implements Comunicador, Encriptable {
public void setEncriptacion (Encriptacion restriccion) {}
public void enviaMensaje (String mensaje) {}
public void enviaMensaje (Object object) {}
}
DIP: Principio de inversión de dependencia:
A. High-level modules should not depend on lowlevel modules. Both should depend on abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.
Depende de abstracciones, no de clases concretas es el último principio de la lista.
Así, Robert Martin recomendaría en español:
A - Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones.
B - Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones.
Generar código de barras y Códigos QR - Generación de códigos QR con ZXing
Los códigos QR o Quick Response Code son simple códigos de barras pero en 2 dimensiones que pueden ser leidos o escaneados por una cámara, como la de un teléfono móvil.
Un código QR consiste en cuadrados negros dispuestos en una cuadrícula cuadrada sobre un fondo blanco. Existen varias variantes de códigos QR que dependen del tamaño de los símbolos, el diseño, la codificación y la estructura.
Zxing es una librería para java y android que se pronuncia "Zebra Crossing" como el cruce peatonal de Abbey Road
Procedimiento:
Hay que agregar las dependencias de zxing-core y zxing-javase a nuestro propio proyeto
JasperReports es una biblioteca de creación de informes que tiene la habilidad de entregar contenido enriquecido al monitor, a la impresora o a ficheros PDF, HTML, XLS, CSV y XML... y no lo digo yo sino la wikipedia
Está escrito completamente en Java, su propósito principal es ayudar a crear documentos de tipo páginas, es de bajo licencia libre GNU, por lo que es Software libre.
Una de la más notoria ventaja es el diseño de sus templates a través de una sólida interfaz visual, componentes drag and drop para realizar el template xml por nosotros, además de que con un click realiza la compilación.
Nota mental: La ultima versión del iReport es la 5.6.0 del 28-May-2014 y al parecer solo funciona con java 7 en la variable de entorno JAVA_HOME. Pueden ser cambiado desde las configuraciones en la instalación, generalmente C:\Program Files (x86)\Jaspersoft\iReport-5.5.1\etc\ireport.conf o visitando la documentación
Jaspersoft Studio Eclipse plugin página del marketplace
La manera en que trabajar es la siguiente:
Se escribe un template xml con la extension .jrxml
Se compila con el motor de jasper para generar un archivo de extension .jasper
Se procesa junto a una fuente de datos: Collection de java o una conexion a la base de datos para obtener un ResultSet
Se obtiene como resultado un reporte! :D
Procedimiento
Crear un proyeto maven saltéandose la elección del arquetipo para luego agregar las dependencias a utilizar en el pom.xml:
Tras hacer esto obtendremos un error, de que no encuentra la librería de itext.jar:2.1.7.js6, el problema es que en maven central no existe esa version sino una itext.jar:2.1.7.js2 y agregando esa ya maven es feliz
Adicionalmente vamos a tener que declarar el repositorio jasperreports y sus librerias de terceros ya que la versión de itext que espera es la versión 2.1.7.js4 y será desde aqui donde se tomen las librerias necesarias:
Con cualquiera de las opciones disponibles para crear los jrxml, se procede a crear un reporte como a uno más le guste.
Para empezar podemos arrastrar un static text y escribir el típico hola mundo, hello world, etc.
Nota mental: Al usar el iReport 'por defecto' tiende a usar el lenguaje como groovy dando exceptions en la compilación. Hay que editarlo desde las properties del reporte en la solapa de Report Inspector o bien remover el attributo language="groovy" en etiqueta root jasperReport luego de todas las declaraciones de esquemas. Ah y de paso agregar whenNoDataType="AllSectionsNoDetail" para que no evite no generar el pdf cuando no hay un fuente de datos para completar los mismos.
El archivo creado deberá ser dejado en la carpeta src/main/resources para encontrarlo a tiro.
public static void imprime() throws JRException, IOException {
System.out.println("obtenemos la plantilla JRXML como un inputstream");
InputStream template = JasperRunnable.class.getResourceAsStream("/reporte.xml");
System.out.println("compilamos el reporte desde el stream");
JasperReport report = JasperCompileManager.compileReport(template);
System.out.println("obtenemos la fuente de datos");
Map<String, Object> sourceData = new HashMap<>();
System.out.println("llenamos el reporte en un print object, con la fuente de datos");
JasperPrint print = JasperFillManager.fillReport(report, sourceData);
File pdf = File.createTempFile("output.", ".pdf");
System.out.println("Lo exportamos a " + pdf.getAbsolutePath());
JasperExportManager.exportReportToPdfStream(print, new FileOutputStream(pdf));
}
La extensión puede ser tanto xml como jrxml dado que son simple archivos de texto plano con diferentes extension, pero para el caso es indistinto.
Ejecutando esta función en la clase main obtendremos una salida de consola como la siguiente:
obtenemos la plantilla JRXML como un inputstream
compilamos el reporte desde el stream
obtenemos la fuente de datos
llenamos el reporte en un print object, con la fuente de datos
Lo exportamos a C:\Users\Imago\AppData\Local\Temp\output.5354953787413152033.pdf
Dandonos como resultado, el mas simple de los pdf:
Es lo más básico de lo más básico que puede ofrecernos jasper report, pero es sólo el inicio.
A la hora de trabajar con git, existen varios formas de lograr con éxito una buena organización. Existen 2 métodos que proponen una forma de trabajar bajo ciertas normas, ninguna resulta ser perfecta, ninguna cubre todos los casos y es posible que necesitemos nuestra forma de realizar un flujo de trabajo y conocer estos métodos nos brindará una idea como hacerlo.
GitFlow
Gitflow o flujo de git es una manera de trabajar ordenando el repositorio en varias ramas que se corresponden con cada fase del desarrollo de la aplicacion.
La propuesta de este flujo de trabajo cuenta con 5 ramas:
master
hot-fix
release
develop
feature
Master
Este modo de trabajo nos propone dejar master donde se encuentren las versiones finales, similar a los tags.
Desde master de desprende hot-fix, para tratar incidentes urgentes generalmente rapidos y cortitos.
Develop
Desde master nace la rama de develop, una especie de borrador de master. Desde aqui cada desarrollador crearia su propia rama de trabajo feature-xxx.
Desde ahi uno es libre de seguir creando tantos branch locales como se necesite. Lo importante es, un vez finalizado el trabajo, mergear a develop.
En este punto, nace release, para corregir los ultimos detalles y adecuar al entorno del cliente. Una vez lograda cerrar las caracteristicas del nuevo desarrollo, se integra en develop y desde esta ultima se devolveria a master. Para finalizar se crea el tag.
GitHubFlow
Githubflow o flujo de github, es una manera de trabajar mas minimalista, con solo una rama principal(master) y la rama de turno para generar cambios.
Las caracteristicas principales son:
Todo en master es deployable(desplegable a nivel productivo), esto es ideal a la hora de trabajar con integracion continua y delivery continuo.
Cada nueva caracteristica requiere hacer un branch desde master, y pusheando al remoto hasta lograr una version de pruebas.
Podria haber tantas ramas como caracteristicas simulteneas se requieran.
Si un compañero finalizo su trabajo e integro en master, al crear la nuestra desde la misma instancia, se puede traer sus cambios y sumarlos a los propios.
Los pasos a seguir en flujo de trabajo son:
Crea tu propia rama, desde master
Trabajar de manera local pusheando los commits a la rama remota
Cuando la rama este lista para el merge con master se abre un pull request.
Se conversa y revisa el codigo con el grupo de trabajo
Deploy y testing en produccion, los arreglos y adecuaciones de configuracion se realizan en este punto