Mostrando entradas con la etiqueta Java SE 6. Mostrar todas las entradas
Mostrando entradas con la etiqueta Java SE 6. Mostrar todas las entradas

sábado, 5 de octubre de 2019

Java Annotations: Types y Bean Validation

Hoy vamos a hablar de las Type Annotations y como hacer las nuestras propias validaciones de codiga a traves de ellas. 

Basicamente las Type Annotations es la posibilidad a partir de Java 8 de utilizarlas cada vez que indiquemos un tipo de clase. Es decir en: operadores new, cast de objetos, clausulas de implementacion o lanzamiento de excepciones, etc. Y esto es posible gracias al enumerado TYPE_USE, indicadolo en el apartado target.

@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { DNIValidator.class })
public @interface DNI {
 Class<?>[] groups() default {};
 String message() default "DNI must be valid";
 Class<? extends Payload>[] payload() default {};
}

Y para ver un ejemplo practico, anadiremos a esta informacion la de las ConstraintValidator (basadas en la especificacion JSR-380, tambien conociada como Bean Validation 2.0). La cual nos permitira validar el contenido de nuestros objetos en tiempo de ejecucion. 

Para llevar a cabo el ejemplo necesitaremos las librerias
  • hibernate-validator: Que contiene la implementacion de JSR-380.
  • hibernate-validator-annotation-processor: Que permite el procesamiento de las anotaciones.
  •  javax.el: Que habilita el uso de EL para el manejo de mensajes en las anotaciones.
El ejemplo lo basaremos en la anotacion mostrada anteriormente pero para ello antes hay que explicar el resto del codigo que es obligatorio para el correcto funcionamiento.
  • Anotacion Retention: Donde le indicaremos la permanencia de la anotacion. Puede ser @Source que descarta la anotacion durante la compilacion, @Class descarta la anotacion durante la carga de la clase y @Runtime que mantiene siempre la anotacion.
  • Anotacion Constraint: Aqui indicaremos la clase o clases de validacion que queremos asociarle. 
  • Atributo groups: Donde le indicamos la agrupacion jerarquica de la anotacion, permitiendo a la hora de indicar la anotacion, a que grupos se aplica. 
  • Atributo message: Donde indicamos el mensaje de validacion asociado. 
  • Atributo payload: A traves del cual indicamos metadatos asociados a la naotacion. 
El siguiente paso sera la validacion asociada a dicha anotacion. Y la crearemos a traves de una clase que extienda de ConstraintValidator e implemente el metodo isValid

import java.util.regex.*;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class DNIValidator implements ConstraintValidator<DNI, String> {
 private static String REGEX = "\\d{8}[A-HJ-NP-TV-Z]";
 @Override
 public boolean isValid(final String arg0, final ConstraintValidatorContext arg1) {
  Pattern p = Pattern.compile(REGEX);
  Matcher m = p.matcher(arg0);
  return m.matches();
 }
}

Ahora solo nos quedaria la prueba. Para ellos crearemos una clase denominada group que contenga un grupo de personas (un mapa) donde indicaremos la anotacion tipada @DNI. Y posteriormente probaremos la clase y su validacion a traves de JUnit y ValidatorFactory.

public class Group {
 private Map<@DNI String, String> people = new HashMap<>();
 public void addPeople(final String dni, final String name) {
  people.put(dni, name);
 }
}
// ...
public class DNIValidatorTest {
 private Validator validator;
 @Test
 public void ko() {
  Group group = new Group();
  group.addPeople("01234567U", "Daniel");
  Set<ConstraintViolation<Group>> violations = validator.validate(group);
  assertThat(violations.isEmpty(), is(false));
 }
 @BeforeEach
 public void setUp() {
  ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
  validator = factory.getValidator();
 }
}

Un unltimo detall, debemos tener en cuenta que en la propia especificacion se indican multiples anotaciones, como pueden ser: @NotBlank, @Email, @NegativeOrZero, etc. Por lo que conviene echarles un vistazo previamente, no vaya a ser que ya exista aquella que querramos implementar.

martes, 20 de agosto de 2019

Ahorrando código con Google y AutoValue

Hoy vamos a hablar de una librería de Google que nos va a ayudar a ahorrar código necesario pero tedioso de realizar. Algo ya parecido vimos con Lombok aquí, en este caso se trata de AutoValue. Con esta librería podremos crear aquellas clases inmutables, que se les da valor y no son modificadas. 

Para que la anotación @AutoValue tenga el efecto deseado tenemos que crear la clase con una características concretas:
  • Añadir la anotación
  • Indicar que la clase sea abstracta.
  • Indicar métodos abstractos con los nombre de los campos que compongan la clase.
  • Indicar la visibilidad deseada (public o non public) tanto para la clase como para los métodos.
@AutoValue
public abstract class Book {
    public abstract String name();
    public abstract String author();
    public abstract Integer pages();
}

Y con todo esto, la anotación generará:
  • Un atributo por cada método abstracto.
  • Una implementación de cada uno de los métodos que devuelva el campo. 
  • Un constructor con todos los atributos. 
  • La implementación de los métodos equals, hashCode y toString.
  • La clase implementada tendrá el mismo nombre pero con AutoValue_ como prefijo.
Además es habitual crear un denominado factory method (no confundir con el patr'on), que nos permita generar de forma sencilla una instancia de la clase. Ejemplo:

public static Book valueOf(final String name, final String author, final Integer pages) {
    return new AutoValue_Book(name, author, pages);
}

A continuación veremos un ejemplo de su uso a través de un test JUnit:

@Test
public void metodo() {
    Book book = Book.valueOf("The stars my destination", "Alfred Bester", 214);
    assertThat(book.name(), equalTo("The stars my destination"));
    assertThat(book.author(), equalTo("Alfred Bester"));
    assertThat(book.pages(), equalTo(214));
    //Implementación del hashCode y equals
    assertThat(Book.valueOf("The stars my destination", "Alfred Bester", 214), equalTo(book));
    //Implementación del toString
    assertThat("Book{name=The stars my destination, author=Alfred Bester, pages=214}", equalTo(book.toString()));
}

En su documentación podreis encontrar además una amplia lista de caracteristicas disponibles, entre las que destacamos:
  • Utilizar el patrón Builder para crear instancias de la clase.
  • Utilizar los prefijos get o is en los métodos accesores pero no en el método toString. 
  • Permitir atributos nulos.
  • Aplicar validaciones a los atributos. 
  • Obviar determinados atributos en el equal.
Para poder utilizar solo tenemos que añadir la dependencia y su configuración para el procesamiento de la anotación a través del plugin compiler. Así:

<dependencies>
    <dependency>
      <groupId>com.google.auto.value</groupId>
      <artifactId>auto-value-annotations</artifactId>
      <version>1.6.5</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>com.google.auto.value</groupId>
            <artifactId>auto-value</artifactId>
            <version>1.6.5</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

domingo, 3 de abril de 2016

Utilizando lenguajes de Script dentro de Java

Una de las características más interesantes dentro de Java SE 6 es la posibilidad de usar lenguaje de Script (Phyton, PHP, Ruby o Javascript) dentro del propio Java. Este sería el comienzo para la implementación que vendría después en Java 8 que permitiría el uso de Lambda y el motor Nashorn.

¿Para que nos puede servir ejecutar lenguaje de Script dentro de Java? Pues para distintas funcionalidades como puede ser:
  • Tienes una script con una determinada funcionalidad y la quieres usar dentro de Java para evitarte la duplicidad del código o el trabajo extra.
  • Quieres habilitar un mecanismo para que los clientes puedan ejecutar su propio código de Script. 
A continuación indicaremos algunas posibilidades y ejemplos de lo que se puede hacer. Pero si quieres más información aquí tiene la documentación oficial.

Ejemplo 1: Lo más básico, ejecutar javascript:

// Crear el gestor de motores de script
ScriptEngineManager factory = new ScriptEngineManager();
// Crear el motor de Javascript
ScriptEngine jsEngine = factory.getEngineByName("JavaScript");
// Evaluar el código Javascript
jsEngine.eval("print('Hello, World')");

Ejemplo 2: Ejecutar código de un fichero javascript

jsEngine.eval(new java.io.FileReader("/WEB-INF/js/general.js"));

Ejemplo 3: Crear variables y distintos contextos

// Creamos una variable, por defecto es global
jsEngine.put("x", "hello");
// Evalua el código javascript y pinta "hello"
jsEngine.eval("print(x)");
// Creamos un contexto asociado unicamente a este motor de script concreto
ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(jsEngine.createBindings(), ScriptContext.ENGINE_SCOPE);
Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
// Le damos un valor distinto a la misma variable pero en otro ambito
engineScope.put("x", "world");
// Evaluamos el código anterior e indicamos el nuevo ambito. Pinta "world"
jsEngine.eval("print(x)", newContext);

Ejemplo 4: Invocar funciones y metodos Script

//Creamos una funcion javascript 
String script = "function hello(name) { print('Hello, ' + name); }"
// eevaluamos el script
jsEngine.eval(script);
// javax.script.Invocable is opcional y puede no setar implementada para todos los motores de script
Invocable inv = (Invocable) jsEngine;
// Invocamos la funcion global 'hello' e indicamos su parametro de entrada
inv.invokeFunction("hello", "Scripting!!");

Ejemplo 5: Ejecución de código compilado

//Compilable soporta la re-ejecucion de codigo previamente compilado
Compilable jsCompilable = (Compilable) jsEngine;
CompiledScript script = jsCompilable.compile("function test() { return 10; }; test();");
//Évaluamos el codigo compilado
Object compiledOutput = script.eval();
//Podemos hacer uso del codigo compilado cada vez que queramos
System.out.println(compiledOutput); 

domingo, 24 de enero de 2016

JDBC 4 y BBDD Derby

Hablando de Java SE 6, indicábamos que había novedades en JDBC y además traía incluida una BBDD de poco peso y realizada completamente en Java.

Las novedades de JDBC son:
  • Carga automática del Driver. Ya no es necesario al crear la conexión indicar el driver específico que debe utilizar
  • Nuevas subclases de SQLException. Lo que permite mayor legibilidad, manejo y comprensión de los errores. 
  • Nuevos métodos para las interfaces DatabaseMetaData, Connection y Statement. 
    • Connection ahora tiene nuevos métodos para crear BLOB y otro para comprobar si la conexión es válida.
    • Statement ahora tiene nuevos métodos para saber si proviene de un pool y si ya esta cerrado el statement. 
  • Nuevos métodos en CallableStatement, Statement y ResultSet que permite manejar java.io.InputStream y java.io.Reader.
  • Eventos en Statements que permite al pool de conexiones estar atento a sus eventos asociados: addStatementEventListener y removeStatementEventListener.
  • Añade métodos para el manejo de RowId
En cuanto a Derby, podemos indicar lo que ellos mismos dicen en su página oficial:

  • Ocupa muy poco espacio, alrededor de 2.6 Mb con driver incluido
  • Realizado en Java y en base a los estandares JDBC y SQL
  • Es facil de instalar, desplegar y usar. 

Para demostrarlo vamos a ver un ejemplo. La parte JDBC es igual que con cualquier otra, así que el ejemplo va a ser de como instalarlo en Ubuntu con open-jdk (que es lo que uso):
  • Para empezar lo descargamos y creamos las variables del sistema
sudo apt-get install sun-javadb-client sun-javadb-core
export PATH=$PATH:/usr/share/javadb/bin/
export DERBY_HOME=/usr/share/javadb
  • Ahora a través del comando 'ij' creamos la BBDD y sus esquemas. Con el comando 'dblook' podemos hacer exportación del esquema y con 'sysinfo' ver información del mismo. Simplemente debemos teclear en la consola 'ij'.
  • Y a través de comandos SQL vamos a crear nuestra BBDD y su esquema. 
connect 'jdbc:derby:dbPrueba;create=true';
create table persona (clave integer, nombre varchar(50));
insert into persona (clave, nombre) values (1, 'Nombre');

Una cosa muy importante es indicar el ';' tras los comandos SQL, sino parecerá que no hace nada. 

Con esto ya tendriamos nuestra propia BBDD activa y lista para trabajar con ella. De forma facíl y ligera. 

sábado, 16 de enero de 2016

Novedades en Java SE 6

La idea de este post y sucesivos es que nos podamos poner un poco al día de las características que ha ido incluyendo Oracle en Java y ¿Quien sabe?, igual hasta utilizarlo alguna vez que otra.

En general Java SE 6 tiene muchas y pequeñas novedades. Si estáis interesados las podéis ver todas aqui. Pero lo más destacado es:
  • Mejora en el paquete java.swing, incorporando nuevas clases que permiten realizas acciones de escritorio comunes. 
  • Mejora del rendimiento gráfico en los SO Windows. 
  • La posibilidad de crear servicios web sin necesidad de la versión JEE. Agregando el paquete javax.xml.ws y las anotaciones javax.jws. De esto ya hemos hablado en otros post y sin saber que era una novedad de Java SE 6 :-P. 
  • Incluye una base de datos realizada totalmente en Java, de pequeño tamaño y fácil configuración: Derby. 
  • Soporte para la última versión de JDBC, 4.0.0. 
  • Integración con lenguajes de script (Javascript, PHP, etc).
Posiblemente las características más interesantes sean las últimas y las que necesiten un revisión más completa en su propio post.

Aparte de estas nuevas caracteristicas, ahí otras menores que no influyen tanto pero que si merece la pena mencionarlas:
  • Nueva clase 'Console' que facilita el manejo de entrada y salida de datos por linea de comandos (el tipico método void main(String[] args)). Incluso también puedes leer la contraseña sin necesidad de mostrarla.
  • Creación de nuevas interfaces de Collections: Deque, BlockingDeque, NavigableSet y NavigableMap. Con sus clases correspondientes.
  • Mejora en la depuración y herramientas de depuración como JConsole. 
  • Nueva API (Normalizer) que permite la normalización de texto en Unicode
final String input = "Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ";
System.out.println(Normalizer.normalize(input, Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", ""));
//muestra por pantalla: 'This is a funky String'