echo =================================================
echo TODOS LOS MODULOS HA SIDO DESPLEGADOS CON EXITO
echo =================================================
Bitsmi Blog
Creación de un Fat Jar con Apache Ant
30-03-2015 - Antonio Archilla
Normalmente para construir el distribuible de una aplicación Java se empaqueta el código principal de esta dentro de un fichero jar ejecutable, esto es, que contiene dentro de su fichero de definición MANIFEST.MF
una entrada que especifica qué clase contiene el metodo main()
y junto a este se crea una carpeta que contenga todas las dependéncias que este (habitualmente se llama a esta carpeta lib
).
Esto hace que para especificar el classpath de la aplicación sea necesario:
Especificar directamente en el archivo MANIFEST.MF
de forma individual todos las dependéncias que forman el classpath mediante la propiedad Class-Path de la siguiente manera
Class-Path: lib/jar1.jar lib/jar2.jar lib/jar3.jar
Especificar en la orden de ejecución Java las dependéncias a través del parámetro cp
En Windows: java -cp "lib/jar1.jar;lib/jar2.jar;lib/jar3.jar" -jar jar_principal
En Unix: java -cp "lib/jar1.jar:lib/jar2.jar:lib/jar3.jar" -jar jar_principal
En Java 6 también es posible utilizar wildcards: java -cp "lib/*" -jar jar_principal
Este método hace tediosa la llamada a la máquina vitual y normalmente se tiende a crear un shell-script o cmd que haga la llamada por nosotros, con lo que se añade un fichero más al distribuible
En ciertas circumstancias muchas veces es preferible distribuir nuestra aplicación en un jar simple que facilite su distribución y ejecución, pero hay que incluir las dependencias de alguna manera. Aquí es donde entra la técnica de generar un fat jar, o dicho de otra manera, empaquetar toda la aplicación, dependéncias incluidas dentro de un mismo fichero jar. Para ello se suelen extraer los ficheros .class compilados que se encuentran dentro de los jars de las dependéncias y se incluyen dentro del jar principal de la aplicación. Cómo el package de las clases és único no se producen conflictos al incluirlos dentro de este. Un mecanismo sencillo de realizar esta tarea mediante un script de Apache Ant es la siguiente:
Incluir todas las clases de las dependencias en un mismo jar temporal que servirá como fuente en la creación del jar definitivo
<target name="main.dependencies.jar">
<jar jarfile="${dist.dir}/dependencies-all.jar">
<zipgroupfileset dir="lib">
<include name="**/*.jar" />
</zipgroupfileset>
</jar>
</target>
Mediante el tag zipgroupfileset
se incluyen en el jar de dependéncias todos los ficheros contenidos dentro de los jars de la carpeta lib.
Construir el jar principal, para ello se lanzan previamente las tareas de limpieza, compilado y generación del jar de dependencias. No se encuentran definidas en el ejemplo las 2 primeras tareas porque es bastante obvia su función. El siguiente código corresponde a la tarea de generación del jar principal
<target name="main.jar" depends="clean, main.compile, main.dependencies.jar">
<mkdir dir="${dist.dir}"/>
<jar destfile="${dist.dir}/${jar.name}.jar"
basedir="${main.build.dir}"
manifest="${main.resources.dir}/META-INF/MANIFEST.MF">
<zipfileset src="${dist.dir}/dependencies-all.jar"
excludes="META-INF/*.SF" />
</jar>
</target>
Mediante el tag zipfileset
se incluyen en el jar todos los ficheros contenidos en el jar de dependencias exceptuando el contenido del directorio META-INF
que pueda sobreescribir el MANIFEST.MF
de la aplicación principal
Ejecución de Maven des de consola de comandos MS-DOS
23-07-2014 - Xavier Salvador
Caso de Ejemplo:
Se dispone de un proyecto multi-módulo del que se desean desplegar varios de sus módulos. Se dispone de Maven en su versión 2.2 y de un servidor Weblogic 9.2 Mp4 para los módulos J2EE de las aplicaciones. Para automatizar los despliegues de dichos módulos sin necesidad de acceder ni recorrer el árbol de directorios mediante la consola de comandos DOS del Windows 7 se ha creado el siguiente script. Este script ejecuta los despliegues de cada uno de los módulos que forman el proyecto J2EE en la carpeta establecida como ruta de despliegue para el servidor Weblogic en el fichero de configuración de Maven.
Además, informa de los nombres de los módulos y de los tiempos en que se ejecuta cada uno de los despliegues y lo almacena todo en un fichero llamado resultado.txt
, que puede consultarse con posterioridad.
Una vez realizadas todas las tareas se publica en el fichero un mensaje de finalización de éxito:
Detalle:
A continuación se detalla una sección del código fuente del fichero .bat
explicando un poco su funcionalidad.
La sección más importante del script es la siguiente:
ECHO __________>>resultado.txt.
echo Modulo ST >>resultado.txt. (1)
time /t>>resultado.txt. (2)
ECHO __________>>resultado.txt.
call mvn package war:exploded -f<Ruta_ubicación_fichero_pom>pomITT.xml>>resultado.txt. (3)
if not %ERRORLEVEL% == 0 exit /b. (4)
time /t>>resultado.txt (5)
-
Título del módulo
-
Se indica el inicio del tiempo de despliegue
-
Se llama al maven mediante la instrucción call de DOS para ejecutar el despliegue del módulo actual
-
En caso de error salimos de la consola de comandos
-
Se indica el final del tiempo de despliegue y se escribe la salida de pantalla al fichero de texto de resultado.txt
Se sobreentiende que el fichero pom.xml
de cada uno de los módulos o proyectos J2EE ya incluye en su sección de despliegue la ruta correcta para el servidor Weblogic (En todo caso debe indicarse cuál es la ruta correcta para realizar los despliegues pertinentes).
Actualización del 20/01/2015
En lugar de escribir directamente la ruta de cada uno de los ficheros se utiliza el paso de parámetros en el script. En lugar de utilizar esta línea de código:
call mvn package war:exploded -f<Ruta_ubicación_fichero_pom>pomITT.xml>>resultado.txt
se modifica esta llamada por esta otra línea de código:
call mvn install -f%1<nombre_del proyecto>pom.xml>>resultado.txt
El %1
permite recuperar la ruta en la que se encuentran los proyectos en desarrollo accediendo al fichero POM pasando dicha ruta como parámetro al script. Puede utilizarse cualquier ruta o directorio siempre que el directorio disponga de fichero pom.xml
con una configuración Maven, sino el script dará un error.
Este cambio por un lado nos permite ejectuar la llamada de Maven en todos los proyectos indistintamente de su ubicación dentro del sistema de archivos dado que la carpeta contenedora siempre se pasa por parámetro.
La configuración de Maven (dentro de la etiqueta <build><plugin>
) dentro del fichero POM es la siguiente:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
<attachClasses>true</attachClasses>
<classesClassifier>classes</classesClassifier>
<encoding>ISO-8859-1</encoding>
<webappDirectory>C:/Weblogic_Despliegues/${project.artifactId}</webappDirectory>
</configuration>
</plugin>
El script de ejecución puede encontrarse en este enlace.
Para un mayor detalle sobre el plugin de maven-war-plugin
se puede encontrar información detallada en este enlace.
OCP7 04 – Diseño avanzado de una clase Java
12-07-2014 - Antonio Archilla
Classes
Las clases abstractas sirven para indicar el comportamiento general que deben tener sus subclases sin implementar algunos métodos. Dichas subclases son las que se encargan de implementar estos métodos.
abstract class FiguraGeometrica {
abstract void dibujar();
}
class Circulo extends FiguraGeometrica {
void dibujar() {
// codigo para dibujar Circulo
}
}
Una clase que tenga uno o más métodos abstractos se llama clase abstracta. Debe contener en su declaración el termino abstract
. A su vez, esta clase puede también contener métodos que no sean abstractos.
Un método abstracto contiene el termino abstract
en su declaración y no dispone de ninguna implementación: abstract type nom_metodo();
Es obligatorio que todas las subclases que heredan de la clase abstracta realicen la implementación de todos los métodos abstractos de la superclase dentro de su especificidad.
Aunque una clase abstracta puede ser utilizada como tipo de referencia, ésta no puede ser instanciada ya que su implementación está completa y si se intenta se producirá un error de compilación.
Palabras Reservadas
Static
Es útil disponer de una variable compartida por todas las instancias de una clase mediante el modificador static
.
Los campos que tienen static en su declaración se llaman campos estáticos o variables de clase.
Si existen por ejemplo tres objetos definidos que tienen el campo definido como estático, todas sus instancias pueden modificar el valor de dicho campo dado que está compartido por todos los objetos de la misma clase.
Para referenciar el campo estático es suficiente utilizar el nombre de la clase para acceder al campo.
Un método estático también tiene el modificador static en su declaración. También puede ser invocado sólo con el nombre de clase sin necesidad de instanciar el tipo. Cualquier de acceso a campos o métodos no estáticos provocará un error de compilación. Una clase también puede contener bloques de código estáticos que no forman parte de los métodos normales. Estos bloques estáticos se encuentran encerrados entre llaves. El código dentro de los bloques estáticos sólo se ejecuta una única vez, cuándo la clase se carga por primera vez. Si aparecen varios bloques dentro de la clase, éstos se ejecutan por orden de aparición en la clase. Importaciones static: Pueden utilizarse cuándo queramos importar campos o métodos estáticos de una clase sin anteponer el nombre de la misma:
import static java.lang.Math.random
y al no ser necesario anteponer el nombre de la clase al utilizar la importación estática su implementación queda de la siguiente manera:
double d = random();
System.out.println(d);
Final
Las clases, los métodos y las variables pueden ser finales.
- En las clases. No se pueden generar subclases a partir de esta clase.
- En los métodos. No pueden ser sobrescritos.
- En las variables: campos, parámetros o variables locales.
Una variable de referencia como final no puede hacer referencia a otro objeto (aunque puede modificarse el estado del mismo) Un campo puede posponer su inicialización (inicializarse mediante un constructor de la clase) o inicializarse en su declaración. Una vez está inicializado no es posible modificar su valor. El intento de modificarlo provoca un error de compilación.
Si se marca una variable como local se le podrá asignar el valor en cualquier momento dentro del cuerpo del método pero sólo una vez.
Dentro de los parámetros formales de un método si marcamos uno de los parámetros como final, el valor recibido en el método no podrá ser modificado dentro del cuerpo del método dando un error de compilación si se intenta.
Si se utilizan static
y final
conjuntamente como en el caso de ejemplo:
private static final int field;
se puede considerar el campo como una constante. Las constantes no se pueden reasignar y se producirá un error de compilación si se intenta.
Enumeraciones
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,
SATURDAY;
}
Un tipo enumerado es un tipo cuyos campos son un conjunto de constantes. Proporciona una comprobación de rango en tiempo de compilación. El compilador interpreta la Enum como una clase Java por lo que es posible declararla fuera de una clase o dentro de ella como una clase interna. Todas las enumeraciones extienden implícitamente de la clase Enum. Las enumeraciones pueden ser importadas estáticamente:
import static package.Day.*;
Esto permite no ser necesario que el nombre de la enumeración preceda la constante.
Una enumeración proporciona una comprobación de rango en tiempo de compilación. Si se intenta asignar un valor que no se encuentra en la enumeración se produce un error de compilación. Debido a que los tipos enumerados son como una clase Java además de declarar constantes, un tipo enumerado puede contener:
- campos
- métodos
- constructores privados. El constructor de una enumeración es privado por lo que no es posible crear instancias de una enumeración. Los argumentos del constructor se suministran después de cada valor declarado:
public enum Day {
SUNDAY("Sunday"),
MONDAY("Monday"),
TUESDAY("Tuesday"),
WEDNESDAY("Wednesday"),
THURSDAY("Thursday"),
FRIDAY("Friday"),
SATURDAY("Saturday");
private final String name;
private Day(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Cuándo hay campos, métodos o constructores, la lista de constantes de la enumeración debe terminar con un punto y coma.
Las enumeraciones pueden implementar interfaces pero no pueden extender otras enumeraciones. Una posible utilidad de esto es «esconder» la enumeración referenciando a la interfaz:
public enum Day implements IDayOfWeek
{
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,
SATURDAY;
}
...
IDayOfWeek dow = Day.SUNDAY;
Clases Anidadas
Es una clase declarada en el cuerpo de otra clase.
import java.util.ArrayList;
public class Coordenadas {
private class Punto {
private int x, y;
public Punto(int x, int y) {
fijarX(x);
fijarY(y);
}
public void fijarX(int x) {
this.x = x;
}
public void fijarY(int y) {
this.y = y;
}
public int retornarCuadrante() {
if (x > 0 && y > 0)
return 1;
else if (x < 0 && y > 0)
return 2;
else if (x < 0 && y < 0)
return 3;
else if (x > 0 && y < 0)
return 4;
else
return -1;
}
}
private ArrayList<Punto> puntos;
public Coordenadas() {
puntos = new ArrayList<Punto>();
}
public void agregarPunto(int x, int y) {
puntos.add(new Punto(x, y));
}
public int cantidadPuntosCuadrante(int cuadrante) {
int cant = 0;
for (Punto pun : puntos)
if (pun.retornarCuadrante() == cuadrante)
cant++;
return cant;
}
}
Pueden dividirse en dos categorías:
Clases Internas.
- Clases miembro: Están declaradas dentro de una clase y fuera de cualquier método. Esta clase tiene acceso a los campos y a los métodos de la clase anterior, así como de los campos y los métodos de la superclase de la que herede.
No es posible declarar ninguna clase miembro estático debido a que una clase miembro es cargada sólo dentro del contexto de una instancia de su clase exterior.
public class DataStructure {
// Create an array
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure() {
// fill the array with ascending integer values
for (int i = 0; i < SIZE; i++) {
arrayOfInts[i] = i;
}
}
public void printEven() {
// Print out values of even indices of the array
DataStructureIterator iterator = this.new EvenIterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
interface DataStructureIterator extends java.util.Iterator<Integer> { }
// Inner class implements the DataStructureIterator interface,
// which extends the Iterator<Integer> interface
private class EvenIterator implements DataStructureIterator {
// Start stepping through the array from the beginning
private int nextIndex = 0;
public boolean hasNext() {
// Check if the current element is the last in the array
return (nextIndex <= SIZE - 1);
}
public Integer next() {
// Record a value of an even index of the array
Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]);
// Get the next even element
nextIndex += 2;
return retValue;
}
}
public static void main(String s[]) {
// Fill the array with integer values and print out only
// values of even indices
DataStructure ds = new DataStructure();
ds.printEven();
}
}
- Clases locales: Declarada dentro de un bloque de código en el cuerpo de un método y sólo es visible dentro del bloque de código en el que se ha definido. En las clases internas locales primero se define la clase y luego se crean uno o más objetos según la necesidad.
public class LocalClassExample {
static String regularExpression = "[^0-9]";
public static void validatePhoneNumber(
String phoneNumber1, String phoneNumber2) {
final int numberLength = 10;
// Valid in JDK 8 and later:
// int numberLength = 10;
class PhoneNumber {
String formattedPhoneNumber = null;
PhoneNumber(String phoneNumber){
// numberLength = 7;
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
public String getNumber() {
return formattedPhoneNumber;
}
// Valid in JDK 8 and later:
// public void printOriginalNumbers() {
// System.out.println("Original numbers are " + phoneNumber1 +
// " and " + phoneNumber2);
// }
}
PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);
PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);
// Valid in JDK 8 and later:
// myNumber1.printOriginalNumbers();
if (myNumber1.getNumber() == null)
System.out.println("First number is invalid");
else
System.out.println("First number is " + myNumber1.getNumber());
if (myNumber2.getNumber() == null)
System.out.println("Second number is invalid");
else
System.out.println("Second number is " + myNumber2.getNumber());
}
public static void main(String... args) {
validatePhoneNumber("123-456-7890", "456-7890");
}
}
- Clases anónimas: Se usan para definir clases sin nombre. Cómo la clase anónima no tiene nombre sólo se puede crear un único objeto ya que las clases anónimas no pueden definir constructores.
public class HelloWorldAnonymousClasses {
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
public void sayHello() {
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
}
public static void main(String... args) {
HelloWorldAnonymousClasses myApp =
new HelloWorldAnonymousClasses();
myApp.sayHello();
}
}
Clases anidadas estáticas.
Se definen mediante el modificador static y sólo pueden ser creadas dentro de otra clase al máximo nivel, es decir, directamente en el bloque de definición de la clase contenedora y no en un bloque más interno.
clase ClaseExterior
{
...
clase ClaseAnidada
{
...
}
}
Weblogic – Doble despliegue de una aplicación J2EE
09-07-2014 - Xavier Salvador
Al trabajar con Weblogic y Eclipse, muchas veces da la impresión de que las aplicaciones se despliegan dos veces.
- Una junto al arranque del servidor y, una vez éste está arrancada, vuelve a hacer el deploy correspondiente.
- Parece ser que el problema está en la carpeta tmp del server que no se borra durante los reinicios del servidor.
NOTA: Todos los cambios que se detallan a continuación han sido realizado en Windows 8.
Para solucionarlo se puede modificar el script de arranque de startWebLogic.cmd
añadiendo la instrucción rd de MS-DOS para borrar la carpeta tmp antes de iniciar el servidor.
La modificación quedaria de este modo:
@ECHO OFF
@REM WARNING: This file is created by the Configuration Wizard.
@REM Any changes to this script may be lost when adding extensions to this configuration.
SETLOCAL
set DOMAIN_HOME=C:OracleMiddlewareuser_projectsdomainscomercio_domain
@REM Borrar tmp
rd /S /Q %DOMAIN_HOME%serversAdminServertmp
call "%DOMAIN_HOME%binstartWebLogic.cmd" %*
ENDLOCAL
La modificación del fichero de arranque se ha producido mediante el servidor Bea Weblogic en su versión 9.2 MP4.
NOTA: Se pueden aplicar dichos cambios también en los ficheros de arranque de Linux (extensión .sh) o de otros sistemas operativos. El principio de eliminación de la carpeta temporal sirve independientemente de cuál sea el sistema operativo.
OCP7 06 – Genéricos y colecciones – Introducción
04-07-2014 - Xavier Salvador
OCP7 09 – Pricipios básicos de E/S
03-07-2014 - Xavier Salvador
Streams
El término define una corriente de datos de una fuente a un destino.
Todos los datos fluyen a través de un ordenador desde una entrada (fuente) hacia una salida (destino).
Los fuentes y destinos de datos son nodos de los flujos en la comunicación del ordenador. Todos los flujos presentan el mismo modelo a todos los programas Java que los utilizan:
- flujo de entrada: para leer secuencialmente datos desde una fuente (un archivo, un teclado por ejemplo). Llamado también como input stream.
- flujo de salida: para escribir secuencialmente datos a un destino (una pantalla, archivo, etc). Llamado también como outputstream. Estos nodos pueden ser representados por una fuente de datos, un programa, un flujo, etc..
Flujos de Datos (Bytes y carácteres)
La tecnología Java admite dos tipos de datos en los flujos: bytes y carácteres.
En el lenguaje Java los flujos de datos se detallan mediante clases que forman jerarquías según sea el tipo de dato char Unicode de 16 bits o byte de 8 bits.
A su vez, las clases se agrupan en jerarquías según sea su función de lectura (Read) o de escritura (Write).
La mayoría de las clases que se utilizan con Streams
se encuentran ubicadas en el paquete java.io
. En la cabecera del código fuente debe escribirse el importe del paquete import java.io.*
;
- Métodos básicos de lectura de Streams
- Clase InputStream (Bytes)
- int read()
- int read(byte[] buffer)
- int read(byte[] buffer, int offset, int length)
- Clase Reader (Caracteres)
- int read()
- int read(char[] buffer)
- int read(char[] buffer, int offset, int length)
- Clase InputStream (Bytes)
- Métodos básicos de escritura de Streams
- Clase OutputStream (Bytes)
- void write(int c)
- void write(byte[] buffer)
- void write(byte[] buffer, int offset, int length)
- Clase Writer (Caracteres)
- void write(int c)
- void write(char[] buffer)
- void write(char[] buffer, int offset, int length)
- void write(String string)
- void write(String string, int offset, int length)
- Clase OutputStream (Bytes)
Lectura/escritura en ficheros
Los tipos fundamentales de nodos o elementos a los que puede entrar y salir un flujo de datos que se pueden encontrar en el JDK 1.7 de Java son los siguientes:
Todos los flujos deben cerrarse una vez haya finalizado su uso, forzando un close
dentro de la cláusula finally
.
Flujos en Memoria Intermedia
Para la lectura de archivos cortos de texto es mejor utilizar FileInputStream
en conjunción con FileReader
. A continuación se añaden algunos ejemplos con código fuente para la memoria intermedia.
Ejemplo TestBufferedStreams
package bufferedstreams;
import java.io.*;
public class TestBufferedStreams {
public static void main(String[] args) {
try (
BufferedReader bufInput =
new BufferedReader(new FileReader("src\bufferedstreams\file1.txt"));
BufferedWriter bufOutput =
new BufferedWriter(new FileWriter("src\bufferedstreams\file2.txt"))
){
String line = bufInput.readLine();
while (line != null) {
bufOutput.write(line, 0, line.length());
bufOutput.newLine();
line = bufInput.readLine();
}
} catch (IOException e) {
System.out.println("Exception: " + e);
}
}
}
Ejemplo TestCharactersStreams
package bufferedstreams;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TestCharactersStreams {
public static void main(String[] args) {
try (FileReader input = new FileReader("src\bufferedstreams\file1.txt");
FileWriter output = new FileWriter("src\bufferedstreams\file2.txt")) {
int charsRead;
while ((charsRead = input.read()) != -1) {
output.write(charsRead);
}
} catch (IOException e) {
System.out.println("IOException: " + e);
}
}
}
Entrada y salida estándar
Existen en Java 7 tres flujos estándar principales:
- System.in. Campo estático de entrada de tipo InputStream lo que permite leer desde la entrada estándar.
- System.out. Campo estático de salida de tipo PrintStream lo que permite escribir en la salida estándar.
- System.err. Campo estático de salida de tipo PrintStream lo que permite escribir en el error estándar.
A continuación se indican los métodos principales print
y println
de la clase PrintStream
- Métodos
print
con parámetros distintos- void print(boolean b) void print(char c) void print(char[] s) void print(double d) void print(float f) void print(int i) void print(long l) void print(Object obj) void print(String s)
- Métodos
println
con parámetros distintos void println() void println(boolean x) void println(char x) void println(char[] x) void println(double x) void println(float x) void println(int x) void println(long x) void println(Object x) void println(String x)
Ambos métodos son métodos sobrecargados de la clase PrintStream. A continuación se añade un ejemplo con código fuente para la entrada y salida estándar.
Ejemplo KeyboardInput
import java.io.*;
public class KeyboardInput {
public static void main(String[] args) {
try (BufferedReader in = new BufferedReader(new InputStreamReader(System.in))) {
String s = "";
while (s != null) {
System.out.print("Type xyz to exit: ");
s = in.readLine().trim();
System.out.println("Read: " + s);
System.out.println("");
if (s.equals("xyz")) {
System.exit(0);
}
}
} catch (IOException e) {
System.out.println("Exception: " + e);
}
}
}
Persistencia
La persistencia consiste en el proceso de serialización (secuencia de bytes) y la deserialización (reconstrucción del objeto obteniendo una copia a partir de los bytes) de un objeto en Java.
Un objeto tiene capacidad de persistencia cuándo puede almacenarse en disco o mediante cualquier otro dispositivo de almacenamiento o enviado a otra máquina y mantener su estado actual correctamente.
Dentro de una aplicación Java, cualquier clase que quiera ser serializada debe implementar la interfaz java.io.Serializable, marcador utilizado para indicar que la clase puede ser serializada.
Puede producirse la excepción NotSerializableException cuándo un objeto no se puede serializar.
Los campos marcados con los modificadores static o transient no pueden ser serializados por lo que al deserializar un objeto dichos campos apuntaran a un valor nulo o cero al finalizar la reconstrucción del objeto. A continuación se añade un ejemplo con código fuente para obtener la persistencia de los datos de un estudiante. Se incluyen la definición del objeto Student, y las clases para la persistencia junto a la clase de ejecución.
Ejemplo DeserializeMyClass
package persistence;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserializeMyClass {
public static void main(String[] args) {
MyClass myclass = null;
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("file1.ser"))) {
myclass = (MyClass) in.readObject();
} catch (ClassNotFoundException | IOException e) {
System.out.println("Exception deserializing file1.ser: " + e);
}
System.out.println("a = " + myclass.a);
System.out.println("b = " + myclass.b);
System.out.println("cad1 = " + myclass.getCad1());
System.out.println("cad2 = " + myclass.getCad2());
}
}
Ejemplo MyClass
package persistence;
import java.io.Serializable;
public class MyClass implements Serializable {
public int a = 0;
private String cad1 = "";
static int b = 0;
private transient String cad2 = "";
Student student = new Student();
public String getCad1() {
return cad1;
}
public void setCad1(String cad1) {
this.cad1 = cad1;
}
public String getCad2() {
return cad2;
}
public void setCad2(String cad2) {
this.cad2 = cad2;
}
}
Ejemplo SerializeMyClass
package persistence;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializeMyClass {
public static void main(String[] args) {
MyClass myclass = new MyClass();
myclass.a = 100;
myclass.b = 200;
myclass.setCad1("Hello World");
myclass.setCad2("Hello student");
try (ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("file1.ser"))) {
o.writeObject(myclass);
} catch (IOException e) {
System.out.println("Exception serializing file1.ser: " + e);
}
}
}
Ejemplo Student
package persistence;
public class Student {
String name = "Darío";
int age = 3;
}
Recordatorio
Las clases BufferedReader
y BufferedWriter
aumentan la eficacia de las operaciones de entrada y salida.
Estas clases permiten gestionar el búfer y escribir o leer línea por línea.
A continuación se añade un ejemplo sencillo utilizando un BufferedReader
para leer la cadena xyz
y finalizar la ejecución.1.-Ejemplo utilizando BufferedReader
try (BufferedReader in = new BufferedReader(
new InputStreamReader(system.in)))) {
String s = "";
System.out.print("Type xyz to exit");
s = in.readline().trim();
System.out.print("Read "+s);
// ...
}
OCP7 12 – Conexión JDBC en Java 7
03-07-2014 - Xavier Salvador
Introducción
JDBC (Java Database Connectivity) es un acrónimo que identifica la API mediante la cuál las aplicaciones Java pueden conectarse a sistemas gestores de bases de datos (BBDD). Esta conexión se obtiene por la utilización de interfícies de conexión llamadas controladores JDBC (o conocidos también como drivers). Estas bases de datos acostumbran a ser en general relacionales, aunque también existen otros drivers para otros tipos de BBDD (nosql, ficheros planos, hojas de cálculo, etc).
OCP7 08 – Excepciones (I)
03-07-2014 - Antonio Archilla
Tipos de Excepciones
Excepciones comprobadas (checked).
Representan errores producidos durante la ejecución de un programa por condiciones inválidas en el flujo esperado. Estos errores pueden ser previsibles o esperables y por eso se puede definir un flujo alternativo para tratarlos. Es el caso, por ejemplo, de errores de conexión de red, errores en la localización de ficheros, conexión a base de datos, etc. En estos casos, se puede aplicar una política de re-intentos o bien informar al usuario del error de forma controlada si se trata de un entorno interactivo.
Los métodos están obligados a tratar de alguna manera las excepciones de este tipo producidas en su implementación, ya sea relanzándolas, apilándolas o tratándolas mediante un bloque try/catch
.
Exception
y subclases, excepto RuntimeException
y subclases.
Excepciones no comprobadas (unchecked).
Representan errores producidos durante la ejecución de un programa de los que no se espera una posible recuperación o no se pueden tratar. Se incluyen entre estos casos errores aritméticos, cómo divisiones entre cero, excepciones en el tratamiento de punteros, cómo el acceso a referencias nulas (NullPointerException) u errores en el tratamiento de índices, cómo por ejemplo el acceso a un índice incorrecto de un array.
Este tipo de errores pueden ocurrir en cualquier lugar de la aplicación y no se requiere su especificación en la firma de los métodos correspondientes o su tratamiento
a través de bloques try/catch
(aunque es posible hacerlo) lo que facilita a la legibilidad del código.
RuntimeException
, Error
y subclases de éstas.
En concreto la excepción no comprobada Error
representa errores producidos por condiciones anormales en la ejecución de una aplicación que nunca deberían darse.
En su mayoría se trata de errores no recuperables y por esta razón, este tipo de excepciones no extienden de Exception y si de Throwable
con el propósito que no sean capturadas accidentalmente
por ningún bloque try/catch
que pueda impedir la finalización de la ejecución. A nivel de compilación, estos se tratan de igual forma que las excepciones no comprobadas,
por lo que no hay la obligación de declarar su lanzamiento en las firmas de los métodos.
Ejemplos:
- VirtualMachineError: Indica que se ha producido un error que impide a la máquina virtual seguir con la ejecución, sea porque se ha roto o porque no puede conseguir los recursos necesarios para hacerlo, cómo por ejemplo, por falta de memoria (OutOfMemoryError), porque se haya producido un desborde de la pila (StackOverflowError) o porque se haya producido un error interno (InternalError).
- LinkageError: Indica incompatibilidades con una dependencia (clase) que ha sido modificada después de la compilación.
- AssertionError: Indica un error en una aserción.
Jerarquía de Excepciones
La jerarquía de las excepciones en Java 7 puede visualizarse en el siguiente esquema:
La superclase de todas las excepciones es Throwable
.
La clase Exception
sirve como superclase para crear excepciones de propósito específico, es decir, adaptado a nuestras necesidades.
La clase Error
está relacionada con errores de compilación, del sistema o de la JVM. Normalmente estos errores son irrecuperables.
RuntimeException
(Excepciones Implícitas): Excepciones muy frecuentes relacionadas con errores de programación. Existen pocas posibilidades también de recuperar situaciones anómalas de este tipo.
Lanzamiento de Excepciones
Para el lanzamiento de una excepción debe ejecutarse el siguiente código:
// Crear una excepcion
MyException me = new MyException("Myexception message");
// Lanzamiento de la excepción
throw me;
Bloque try-catch
El bloque que puede lanzar una excepción se coloca dentro de un bloque try
. Se escribe un bloque catch
para cada excepción que se quiera capturar.
Ambos bloques se encuentran ligados en ejecución por lo que no debe existir una separación entre ellos formando una estructura try-catch
conjunta e indivisible.
Pueden asociarse varios bloques catch
a un mismo bloque try
.
import java.util.*;
public class ExTryCatch {
public static void main(String[] args){
int i=-3;
try{
String[] array = new String[i];
System.out.println("Message1");
}
catch(NegativeArraySizeException e){
System.out.println("Exception1");
}
catch(IllegalArgumentException e){
System.out.println("Exception2");
}
System.out.println("Message2");
}
}
Bloque Finally
Cuándo se agrupan excepciones al acceder a uno de los catch
el resto de catch
no se ejecutarán y puede provocar un error en la liberación de recursos utilizados en un programa.
Java cuenta con un mecanismo para evitar esto de forma consistente en el bloque de código finally
el cuál siempre se ejecuta.
import java.util.*;
public class ExFinally {
public static void main(String[] args){
int i=5;
try{
String[] array = new String[i];
}
catch(NegativeArraySizeException e){
System.out.println("Exception1");
}
catch(IllegalArgumentException e){
System.out.println("Exception2");
}
finally{
System.out.println("This always executes");
}
}
}
OCP7 05 – Herencia en las interfaces Java
01-07-2014 - Xavier Salvador
Uso de las interfaces Java
Una interfaz representa una alternativa a la herencia multiple de objetos. Son similares a las clases abstractas ya que contienen únicamente métodos públicos y abstractos. Ninguno de sus métodos pueden ser implementados (ni siquiera con un conjunto vacío de llaves). La declaración de una interfaz es similar a la declaración de una clase. Se usa la palabra reservada interface. Para la implementación de una interface se añade implements a la clase que implementa la interfaz. Una interfaz puede utilizarse como un tipo de referencia. Puede utilizarse el operador instanceof con las interfaces para detectar si un objeto es del tipo de referencia indicado por la interfície implementada. Interfaces de Marcador: definen un tipo concreto pero no describen los métodos que deben ser implementados por una clase, sólo sirven para la comprobación de tipos.
Existen dos tipos:
java.io.Serializable
és una interfaz de marcador utilizado por la biblioteca de E/S de Java para determinar si un objeto puede tener su estado serializado.
Como convertir de un tipo de dato al tipo de la interfaz
Antes de generar una excepción en la conversión de tipos de unos objetos a otros objetos se comprueba que dicha conversión sea posible mediante la utilización del operador instanceof (ya comentado anteriormente).
En general, cuándo se utilicen referencias, éstas deben utilizar el tipo más genérico posible, es decir, que sirvan para cualquier tipo de interfaz o clase padre. Así la referencia no se vincula a una clase particular.
Una clase puede heredar de una clase padre e implementar una o varias interfaces pero siempre en este orden: primero hereda – extends – y después implementa – implements – separando las interfaces mediante comas.
Una interfaz puede heredar de otra interfaz. Java no permite la herencia múltiple de clases pero sí la herencia múltiple de interfaces:
Si escribimos una clase que hereda de una clase que implementa una interfaz, entonces la clase que estamos escribiendo hereda también de dicha interfaz. La refactorización consiste en realizar modificaciones en el código para mejorar su estructura interna sin alterar su comportamiento externo.
Composición
Este patrón de diseño permite la creación de objetos más complejos a partir de objetos más simples. Se crea una nueva clase con referencias a otras clases. A esta nueva clase le agregaremos los mismos métodos que tienen las demás clases.
public class ComplexClass {
private Single1 c1 = new Single1();
private Single2 c2 = new Single2();
private Single3 c3 = new Single3();
}
Referencia al polimorfismo
Vamos a describir un ejemplo de polimorfismo. Si existe una clase nueva llamada Hombre que dispone de un método addCoche con la configuración de clases establecida en la siguiente imagen:
No se le puede pasar como argumento al método addCoche de Hombre cualquier tipo de coche. Solución: Para soportar el polimorfismo en las composiciones cada clase usada en la composición debe disponer de una interfaz definida y así se le podrá pasar cualquier tipo de coche al método en cuestión.
OCP7 13 – Localización
01-07-2014 - Xavier Salvador
Localización
La localización o regionalización es el proceso mediante el cual un producto internacionalizado se configura para una determinada región, aprovechando las opciones que la internacionalización previa de este producto ha permitido (i18n). Por ejemplo, la internacionalización puede permitir utilizar distintos formatos de fecha, y la localización consiste en escoger el adecuado para una región específica.