Introducción a pruebas con JUnit y Mockito

Cuando tu mvn verify da 0 errores

Uno de los puntos más importantes y a la vez más descuidados en la educación superior en Guatemala en TI (al menos desde mi punto de vista), es la correcta implementación de pruebas de software.

Como parte de nuestras capacitaciones internas, en Nabenik decidimos compartir nuestra capacitación de introducción a JUnit y Mockito. La capacitación está enfocada a ser útil para cualquier framework de integración basado en JUnit, incluyendo Arquillian y Spring Testing, por lo que se utiliza JUnit 4, pero los conceptos son útiles para JUnit 5 por igual.

Comenzamos con la parte teórica y las motivaciones de las pruebas de software automáticas:

Posteriormente exploramos el uso de JUnit con IntelliJ IDEA (pero aplicable a cualquier IDE).

Luego controlamos las pruebas utilizando las anotaciones Before, BeforeClass, After y AfterClass

Y finalizamos con creación de Mocks utilizando Mockito

Nuevo esquema de licenciamiento y versiones de Java

El día 22 de febrero de 2019 GuateJUG llevó a cabo su reunión mensual. Diferente de otras reuniones en la desconferencia nuestra intención fue realizar un dialogo honesto acerca de lo que está pasando con Java, especialmente por la nueva licencia a partir de Oracle JDK 8u202 con todos los miembros del JUG.

La presentación utilizada durante la discusión fue una traducción de la original de Volker Simonis del equipo de la JVM en SAP.

Así mismo grabamos el audio de ambiente para los interesados (nótese que estuvimos acompañados de Dua Lipa):

Algunos puntos importantes que todos piensan que vale la pena comunicar:

  • El cambio de licencia afectara a versiones superiores a Java 8u202
  • Si se quiere utilizar Oracle JDK para Java 8 (superior a 8u202) o Java 11 en producción, es obligatorio pagar un soporte de $25 al mes
  • Si se quiere utilizar Oracle JDK para Java 8 o Java 11 en desarrollo, no se paga nada
  • En muchos casos -i.e. WebLogic- el soporte de la JVM ya está incluido en el contrato comercial
  • Si no se quiere utilizar Oracle JDK las JVM son intercambiables con Open JDK ya que Oracle JDK es en si una compilación de Open JDK con soporte comercial de Oracle. Adicionalmente Oracle ya liberó sus características «premium» y están disponibles para todo el mundo
  • La mejor analogía para entender los nuevos esquemas de soporte: Oracle JDK = Red Hat, Open JDK = Fedora, OpenJDK LTS de terceros = CentOS
  • Entre las ofertas de OpenJDK con soporte comercial (gratuito y pagado) encontramos a Oracle, Red Hat, AdoptOpenJDK/IBM, Azul Systems, Amazon, Liberica JDK, entre otros.

Como de costumbre vale la pena resaltar que todos estos datos están sujetos a cambios y la ultima palabra la tendrá su representante de ventas autorizado de Oracle :).

Adicionalmente varios usuarios actuales comentaron software que ya probaron o utilizan en producción con alguna de las variantes de OpenJDK.

  • Payara Application Server
  • IntelliJ IDEA
  • Android Studio
  • Apache TomEE
  • Eclipse IDE
  • Netbeans IDE
  • Spring Boot

Uso de Java(JVM) en Guatemala (2019)

En línea con el cambio y las nuevas políticas de licenciamiento de Oracle el grupo de usuarios Java de Guatemala se propuso realizar un primer censo del uso de Java (como JVM en Guatemala).

Los resultados fueron recolectados durante un periodo de tiempo de 10 días desde 01-02-2019 hasta 10-02-2019.

Datos generales de la encuesta:

  • Días de entrevista: 10
  • Estimativa de confianza para un grupo de 1000 desarrolladores: 95% con un margen de error de 8%
  • Personas participantes: 136

Los datos están disponibles en un ZEPL público para que cualquier persona pueda auditarlos/utilizarlos/encontrar curiosidades, los mismos fueron analizados en Spark/Scala porque . . . JVM :).

TL:DR La JVM más utilizada es Java 8 de Oracle, la cual está sujeta a cambios en el licenciamiento a partir de versiones posteriores a Java 8u202.

¿Que tanto saben las personas que existen otras JVM alternativas?

Respuesta: 3 de cada 4 sabe de la existencia de otras JVM.

¿Cual es la versión de JVM más utilizada en Guatemala?

Respuesta: Java 8 seguido de Java 7, cuyo ultimo lanzamiento público fue realizado en 2015 :O.

¿Cual es el proveedor de JDK que más se utiliza en Guatemala (producción)?

Respuesta: Oracle JDK

Disponible Eclipse Glassfish 5.1.0

Originalmente este post iba a ser más serio y ser contribuido al site de Jakarta EE, pero recordé que las contribuciones solo pueden ser en inglés.

Así que le agregué algo música a la versión en español. ¡Larga vida al pez!

Un poco de historia

Comencemos . . .

Glassfish es uno de esos proyectos que demuestra la verdadera naturaleza del software Open Source, con una premisa simple:

Siempre que exista una comunidad, el proyecto Open Source sobrevivirá a su «fabricante»

Tuxtor

Como bien relata Wikipedia, Glassfish originalmente fue un proyecto de Sun Microsystems para proporcionar un servidor de aplicaciones Java Open Source, liberando el código de lo que entonces conocíamos como Sun Java System Application Server que horrible era ese nombre.

Dato curioso: Fue acá que inicié mi carrera como desarrollador Java.

Sun Java System Application Server

Una de las razones por las cuales Glassfish fue ganando terreno es que luego de la liberación recibió un lavado de cara, fue el servidor de aplicaciones de referencia, viviendo su época dorada implementando OSGi, liberándose de algunos módulos y convirtiéndose en uno de los servidores de aplicaciones más utilizados incluso después de su «primer muerte».

Hoy en día pocas personas lo recuerdan, pero la aparición de Glassfish hizo que muchos de nosotros por fin pensáramos en el servidor de referencia como un ciudadano de primer nivel y no solo un recurso para aprendizaje.

Implementación de referencia

Y a todo esto, ¿Que significa que Glassfish fuera la implementación de referencia?

Cuando Sun Microsystems lanzó al mundo Java, una de sus primeras acciones para popularizar el lenguaje fue permitir que otros lo utilizaran y que pudieran crear sus propias implementaciones, existiendo tres estándares:

  • Java 2 ME – Para aplicaciones móviles (y luego micro)
  • Java 2 SE – Para cualquier tipo de aplicación de escritorio
  • Java 2 EE – Para aplicaciones enterprise, enfocadas a la naciente internet

A partir de acá el raciocinio es simple. Para desarrollar/evolucionar un standard de código, se necesita . . . código. Por lo que Glassfish siempre fue el primer servidor de aplicaciones sobre el cual se probaban/mejoraban/pulían e implementaban los cambios al standard que se convertiría en Java EE a secas (sin el dos). La primer resurrección

La transición

Luego de que varios proyectos Open Source perecieran ante la venta de Sun Microsystems a Oracle (Open Office, Hudson, Open Solaris), Glassfish se mantuvo en aguas firmes y sobrevivió a la transición. En su momento y a pesar de la existencia de WebLogic, Oracle aprovechó la fama de Glassfish ofreciendo paquetes de soporte comercial.

Y luego en 2013 todo se derrumbó.

Oracle anunció que a pesar de que seguiría siendo la implementación de referencia, Glassfish no contaría más con soporte comercial (lo cual dio nacimiento eventualmente a Payara).

En la época (2013), escribí un articulo denominado «la paradoja de Glassfish» que tiene más detalles al respecto.

Y nos vamos . . . a Eclipse

https://www.youtube.com/watch?v=i68sHKXnGuM

Luego de la publicación de Java EE 8 en 2017 y varios llamados de atención entre Oracle y la comunidad, Oracle anunció en Java One que donaría Java EE a la fundación Eclipse, cediendo por tanto el liderazgo de los estándares, incluyendo:

  • Las implementaciones de referencia (las bibliotecas que conforman Glassfish)
  • Los TCK (que hasta el momento eran de código cerrado)
  • La propiedad intelectual de los estandares ya existentes (y el derecho a utilizar el paquete javax.*).

El año de la transición

Transferir un proyecto de la magnitud de Java EE es algo que ha pasado pocas veces en la historia de la computación, para ponerlos en perspectiva, Java EE sin los test tiene más lineas de código que Firefox, 13.5 millones de líneas de código en 95 mil archivos.

Como relatá Dmitry Kornilov en Oracle Developers, transferir un proyecto de este tipo fue un esfuerzo sin precedentes. Y he de decir, Oracle ha sido vital para que este proceso sea posible, como bien se demuestra en las contribuciones.

¿Que significa realmente Eclipse Glassfish 5.1.0?

Durante la transición hay varios factores implicados pero a nivel de código la nueva versión significa lo siguiente:

  • El código ha sido transferido a Eclipse (39 proyectos y 88 repositorios)
  • Se han creado diversos sub-proyectos para cada componente
  • Se ha aplicado la licencia obligatoria de todos los proyectos en la fundación Eclipse, la Eclipse Public License
  • Se tienen nuevas coordenadas de Maven
  • Ya es posible compilar Glassfish y sus componentes mediante la estructura de integración continua de Eclipse

Además de algunos bugs mayores este lanzamiento no cambia mucho respecto a la version original de Glassfish 5. La idea de este release es demostrar que Eclipse es capaz de dar un nuevo acuario al pez. Y que el proyecto sobrevivirá bajo Jakarta EE.

¿Puedo utilizar Eclipse Glassfish 5.1.0?

Por supuesto, tanto el pom con las nuevas coordenadas como la distribución en zip ya estan disponibles para su uso en:

https://projects.eclipse.org/projects/ee4j.glassfish/downloads

Como no tenia una demo preparada sin MicroProfile, decidí hacer algo más divertido, conectar Apache Netbeans 10 con Glassfish 5.1.0 sobre OpenJDK 8 de AdoptOpenJDK y probar que el mundo no es el mismo de antes



Tips para mejorar tu carrera como desarrollador

Gracias a una invitación de CUNOC, tuve la oportunidad de preparar una charla diferente de todas las que doy. En esta oportunidad hablé de como «mejorar tu carrera como desarrollador».

En su momento estuve a punto de declinar esta charla ya que no me sentía con autoridad para impartirla ni se me hace muy comodo impartirla, especialmente porqué no me considero un desarrollador élite ni mucho menos un Tycoon. Sin embargo la invitación era específicamente para figurar como «role-model» de futuras generaciones de ingenieros en sistemas.

Por este motivo decidí enfocar la charla en que cosas he hecho mal y que cosas me hubiera gustado saber al momento de estar y salir de la universidad. También un par de comentarios acerca de como pueden convertirse en Java Champion.

La grabación es de la misma charla en Java Day Guatemala 2018, probablemente sea la ultima vez que la de, espero que sea útil o al menos se diviertan 😁.

Habilitar el repositorio Maven de Oracle para realizar conexiónes via JDBC

En estos mini tutoriales «de vuelta a clases» demostraremos como preparar nuestra instalación de Maven para descargar dependencias desde el repositorio Maven de Oracle. Posteriormente, realizaremos un proyecto simple para demostrar una conexión con Oracle y nuestra nueva dependencia de Maven.

Introducción práctica a las novedades de Jakarta EE 8 con Payara 5

El presente tutorial fue escrito para uno de los hackdays de la comunidad hispana Java, pueden encontrar el original en el siguiente GitHub.

En esencia se brinda una demostración de algunas de las novedades más importantes de Java EE 8, específicamente:

  • Retrocompatibilidad
  • JAX-RS 2.1 Reactive client
  • JSON Binding
  • JSON-P (Processing y Patching)
  • CDI 2.0 (Async events)

El tutorial esta dividido en 4 secciones:

  1. Configuración e instalación de un entorno de desarrollo Java EE 8
  2. Creación y despliegue de una aplicación con Java EE 7
  3. Actualización de la aplicación de Java EE 7 a Java EE 8
  4. Implementación de nuevas características en Java EE 8

Como referencia se ha creado un repositorio de demostración con cada uno de los pasos delimitados mediante commits de Git en https://github.com/tuxtor/jmovies

Configuración e instalación de un entorno de desarrollo Java EE 8

Instalación de NetBeans

Como primer paso debemos descargar el instalador de NetBeans correspondiente a nuestro sistema operativo, específicamente la versión para Java EE.

i1

Dado que el instalador esta pensado para todo publico, el mismo funciona como un asistente con una serie de pasos donde el usuario debe confirmar licencia, directorio de instalación y en el caso del instalador para Windows y Linux también se ofrecen como opciones la instalación de Tomcat y Glassfish 4.

i2

Instalación de Payara

Luego de instalar NetBeans deberemos descargar Payara. Como en la mayoría de servidores de aplicaciones, se distribuye al publico un Zip que contiene todo lo necesario para ejecutar nuestra instalación:

i3

Al momento de escribir este tutorial, la ultima versión disponible al publico es la versión 5.182 la cual generara un archivo denominado payara-5.182.zip, para «instalarlo» basta con descomprimir el archivo y recordar la ruta. En el caso de Windows y para evitar inconvenientes de permisos, se recomienda instalarlo en un directorio propiedad del usuario -e.g. Documentos-.

Instalación de plugins de Payara

Para dar soporte a Payara en nuestra instalación de NetBeans, deberemos descargar los plugins de Payara desde NetBeans Plugins Portal, como resultado obtendremos un archivo zip 1529324925_PayaraPlugins_1.3 que contendrá cinco archivos con extensión .nbm correspondientes a los complementos de Payara.

Luego, en la sección de plugins de NetBeans (Tools -> Plugins), debemos agregar nuestros complementos recién descargados (en la pestaña Downloaded): i4

i5

i6

Al finalizar NetBean solicitara el reinicio del IDE.

Conexión de NetBeans con Payara

Al reiniciar el IDE, debemos movilizarnos hacia la pestaña Services, específicamente en el apartado Servers, y mediante click derecho seleccionaremos la opción «Add Server».

Luego, debemos elegir Payara Server para tener soporte a la ultima versión de Payara.

pn1

Ubicamos la ruta donde hemos descomprimido nuestro archivo zip de Payara

pn2

Utilizaremos los valores predeterminados para dominio

pn3

Al finalizar, estaremos listos para iniciar Payara por primera vez, si la instalación es satisfactoria podemos dirigirnos hacia la url http://localhost:8080 donde Payara debe estar en ejecución:

pn0

pn4

Creación y despliegue de una aplicación con JavaEE 7

Para la siguiente demostración crearemos una aplicación web utilizando Netbeans IDE 8.2 de acuerdo al siguiente esquema:

arch

El objetivo de la aplicación es la elaboración de un backend para aplicaciones SPA (para fines demostrativos el siguiente repositorio contiene una aplicación en AngularJS), con la cual podremos crear un listado de películas favoritas, para agregar, modificar y eliminar películas (CRUD).

Creando el proyecto

Como primer paso debemos agregar un nuevo proyecto de tipo Web Application para Maven web Java EE, por defecto NetBeans 8.2 genera una aplicación compatible con Java EE 7 en el perfil web, se incluyen screenshots de referencia de una nueva aplicación denominada jmovies mediante los cuales se 1- selecciona el proyecto, 2- se establecen los datos del proyecto en Java y 3- se selecciona el entorno de ejecución:

Selección de tipo de proyecto

proy1

Creación de proyecto

proy2

Selección de entorno de ejecución

proy3

Por ultimo, configuraremos nuestro proyecto para dar soporte a Java 8. Para esto, debemos abrir el archivo pom.xml en el cual se encuentran las definiciones de dependencias y tareas para la construcción de nuestro proyecto. Al abrirlo, debemos reemplazar las lineas:

<source>1.7</source>
<target>1.7</target>

Por

<source>1.8</source>
<target>1.8</target>

Creando la capa de persistencia de datos

En esta ocasión utilizaremos una entidad en Java que representa una tabla relacional de base de datos, para esta demostración utilizaremos Apache H2, el cual se encuentra disponible en Payara 5.

Como parte del estandard de Java EE, los servidores de aplicaciones deben implementar una base de datos relacional en memoria que permita elaborar pruebas, demostraciones y servir de soporte para procesos de integración continua. Sobre esta capa utilizaremos tres APIs fundamentales en las aplicaciones de JavaEE:

  • JPA: ORM y mecanismo de mapeo desde bases de datos relacionales hacia el paradigma orientado a objetos
  • EJB: Para la creación de componentes con una arquitectura orientada a servicios, incluyendo transaccionalidad, manejo de ciclo de vida e inyección de dependencias
  • Bean Validation: Validaciones declarativas para la integridad de nuestra aplicación

Creando la entidad de persistencia

La primera vez que ejecutemos nuestra aplicación notaremos que no existe una estructura de base de datos y la misma sera creada en base a una entidad Java, abordaje denominado «code first».

Como primer paso debemos activar JPA en nuestro proyecto mediante la adición de un archivo de configuración estandard, específicamente persistence.xml mediante el cual crearemos una unidad de persistencia denominada jmovies_PU. Las unidades de persistencia son las encargadas de vincular la conexión hacia una base de datos relacional para poder utilizar el recurso mediante inyección de dependencias en código Java.

Para esto, debemos crear el archivo en src/main/resources/META-INF/persistence.xml con el siguiente contenido:

<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="jmovies_PU" transaction-type="JTA">
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
      <property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/>
      <property name="javax.persistence.schema-generation.scripts.create-target" value="jmoviesCreate.ddl"/>
      <property name="javax.persistence.schema-generation.scripts.drop-target" value="jmoviesDrop.ddl"/>
    </properties>
  </persistence-unit>
</persistence>

Note que al utilizar la unidad de persistencia por defecto, no es necesario seleccionar un origen JTA.

Una vez lista la unidad de persistencia, agregaremos una nueva entidad en Java denominada Movie cuyas propiedades representan las columnas de una tabla en base de datos relacional, las anotaciones en Java representan metadatos que indican las restricciones que aplican para cada una de las columnas -e.g. sin nulos, tamaño máximo-.

  • imdb(codigo): String
  • nombre: String
  • descripcion: String

entity1 entity2

@Entity
@XmlRootElement
public class Movie implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
    private static final long serialVersionUID = 1L;
    @Version
    @Column(name = "version")
    private int version;

    @Column
    @NotNull
    private String nombre;

    @Column
    @Size(max = 2000)
    private String descripcion;

    @Column
    @NotNull
    private String imdb;

    //Getters y setters . . .

Como referencia visualizar el estado del proyecto en el commit c0caddc.

Creando un Data Access Object/Repositorio de datos

Los Data Access Objects (DAO), son un patrón común en frameworks en Java, especialmente en Spring y Java EE, su objetivo es proporcionar un objeto en forma de repositorio de datos que permita realizar operaciones de altas, bajas y cambios de información, para utilizarlo como un servicio desde cualquier otro punto de la aplicación.

Para generar un DAO utilizaremos nuevamente NetBeans y crearemos un Session Bean de tipo Stateless como base. El bean nos garantiza la reutilización en memoria del componente y un manejo del ciclo de vida automático del repositorio de datos. Posteriormente y a través de un EntityManager que representa nuestra unidad de persistencia, crearemos métodos para la creación, lectura y eliminación de datos, siendo MovieDao el responsable directo de comunicación con la base de datos relacional:

dao1 dao2

@Stateless
public class MovieDao {
    @PersistenceContext(unitName = "jmovies_PU")
    private EntityManager em;

    public void create(Movie entity) {
        em.persist(entity);
    }

    public void deleteById(Long id) {
        Movie entity = em.find(Movie.class, id);
        if (entity != null) {
            em.remove(entity);
        }
    }

    public Movie findById(Long id) {
        return em.find(Movie.class, id);
    }

    public Movie update(Movie entity) {
        return em.merge(entity);
    }

    public List<Movie> listAll(Integer startPosition, Integer maxResult) {
        TypedQuery<Movie> findAllQuery = em.createQuery(
            "SELECT DISTINCT m FROM Movie m ORDER BY m.id", Movie.class);
        if (startPosition != null) {
            findAllQuery.setFirstResult(startPosition);
        }
        if (maxResult != null) {
            findAllQuery.setMaxResults(maxResult);
        }
    return findAllQuery.getResultList();
    }
}

Como referencia visualizar el estado del proyecto en el commit d1a2428.

Creando un API REST

Para exponer la funcionalidad de nuestro backend crearemos un Endpoint en REST utilizando los verbos de HTTP para cada una de las operaciones de creación (POST), actualización (PUT), eliminación (DELETE) y consulta(GET). Para esto necesitaremos:

  • Crear una clase activadora, donde definiremos la base de nuestra API en REST
@ApplicationPath("/rest")
public class RestApplication extends Application {

}
  • Crear una clase en Java denominada MovieEndpoint, donde definiremos los métodos de nuestro backend, note que para la persistencia inyectamos como recurso nuestro EJB el cual administra toda la lógica de persistencia de datos.
@RequestScoped
@Path("/movies")
@Produces("application/json")
@Consumes("application/json")
public class MovieEndpoint {

    @EJB
    MovieDao movieDao;

    @POST
    public Response create(Movie movie) {
        movieDao.create(movie);
        return Response
                .created(UriBuilder.fromResource(MovieEndpoint.class).path(String.valueOf(movie.getId())).build())
                .build();
    }

    @GET
    @Path("/{id:[0-9][0-9]*}")
    public Response findById(@PathParam("id") final Long id) {

        Movie movie = movieDao.findById(id);
        if (movie == null) {
            return Response.status(Status.NOT_FOUND).build();
        }
        return Response.ok(movie).build();
    }

    @GET
    public List<Movie> listAll(@QueryParam("start") final Integer startPosition,
            @QueryParam("max") final Integer maxResult) {
        final List<Movie> movies = movieDao.listAll(startPosition, maxResult);
        return movies;
    }

    @PUT
    @Path("/{id:[0-9][0-9]*}")
    public Response update(@PathParam("id") Long id, Movie movie) {
        movie = movieDao.update(movie);
        return Response.ok(movie).build();
    }

    @DELETE
    @Path("/{id:[0-9][0-9]*}")
    public Response deleteById(@PathParam("id") final Long id) {
        movieDao.deleteById(id);
        return Response.noContent().build();
    }
}

Como referencia visualizar el estado del proyecto en el commit e61cba9.

Probando nuestra aplicación con Java EE 7

Al finalizar nuestra aplicación, debemos compilarla y desplegarla sobre el servidor de aplicaciones, para probar los métodos del API tenemos dos caminos

  1. Utilizar un cliente REST ligero en un navegador web, por ejemplo uno de los clientes más populares en Firefox es RESTClient
  2. Utilizar un cliente independiente como Postman

Utilizaremos RESTClient para ejecutar las pruebas sobre el backend recién publicado, la URL padrón para un servidor de aplicaciones nuevo es http://localhost:8080/jmovies. Asi mismo utilizaremos JSON como el formato de comunicación con el backend, utilizando la siguiente muestra de una película con su código IMDB:

{
"nombre":"The Matrix",
"imdb":"tt0133093",
"descripcion":"Ghost in the shell para gringos"
}

Primero debemos configurar el cliente para utilizar JSON como formato de comunicación:

test71

Al ejecutar una primera consulta, notamos que la base de datos ha sido inicializada sin datos:

test72

Prodecemos a insertar un primer dato utilizando POST:

test73

Si lanzamos nuevamente una consulta GET, notaremos que los datos han sido insertados satisfactoriamente en la base de datos:

test74

Luego podemos actualizar la entidad mediante PUT, note que tanto el id como la versión deben coincidir para poder actualizar satisfactoriamente:

test75

Observamos nuevamente que la actualización es satisfactoria:

test76

Si todas las pruebas son satisfactorias hasta este punto, hemos creado con éxito un backend compatible con cualquier framework SPA vue/angular/react/knockout/jet/etc. Para probar nuestro backend se ha preparado una aplicación con AngularJS en el siguiente respositorio, basta con que copiemos el contenido del directorio dentro de la carpeta src/main/webapp.

spa

Actualización de la aplicación desde Java EE 7 hacia Java EE 8

Nuevamente abrimos nuestro archivo pom.xml y buscamos la dependencia denominada javaee-api:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>

Reemplazamos la version

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>8.0</version>
    <scope>provided</scope>
</dependency>

Listo, ya estamos en JavaEE 8, ¿Esperaban más? :). Commit de referencia c01baf2.

Más información sobre la retrocompatibilidad garantizada de JavaEE

Implementación de nuevas características en Java EE 8

JSON-B

JSON-B es una nueva API para la personalización del proceso de Marshalling/Unmarshalling, denominada informalmente como JAX-B para el mundo JSON. La nueva API define anotaciones que anteriormente solo existitian en las implementaciones (Jackson, Gson), para controlar la creación de propiedades y documentos JSON, así como una simplificación con la interacción con JSON-P (Processig) y JAX-RS.

Como primera prueba modificaremos ligeramente nuestra entidad Movie para agregar una nueva propiedad, denominada precioVenta y utilizaremos las anotaciones @JsonbProperty y @JsonbNumberFormat para modificar declarativamente el Marshalling/Unmarshalling

@Column
@NotNull
@JsonbProperty("nombre-pelicula")
private String nombre;

@Column
@Size(max = 2000)
private String descripcion;

@Column
private String imdb;

@Column
@JsonbProperty("precio-publico")
@JsonbNumberFormat("#0.00")
private Double precioVenta;

Al desplegar podemos realizar nuevamente la prueba de persistencia con la siguiente muestra, note que se incluye la nueva propiedad y la propiedad nombre fue alterada mediante JSON-B

{
"nombre-pelicula":"The Matrix",
"imdb":"tt0133093",
"descripcion":"Ghost in the shell para gringos",
"precio-publico":"1050"
}

jsonb1 jsonb2

Como referencia visualizar el estado del proyecto en el commit 1b38184.

JSON-P Patch

JSON-P es una API que existe desde versiones anteriores de JavaEE 8 y fue actualizada con la inclusión de soporte a JSON Pointer y JSON Patch, para permitir manipulaciones de JSON directamente sobre el texto y sin realizar Marshalling hacia un objeto en Java.

Para probar esta característica agregaremos dos nuevos métodos a nuestro MovieEndpoint.

@GET
@Path("/with-actors/{id:[0-9][0-9]*}")
public Response findWithActors(@PathParam("id") final Long id) {
    Movie movie = movieDao.findById(id);
    if (movie == null) {
        return Response.status(Status.NOT_FOUND).build();
    }

    return Response.ok(createMovieWithActor(movie)).build();
}

private String createMovieWithActor(Movie movie){

    //To json
    String result = JsonbBuilder.create().toJson(movie);

    JsonReader jsonReader = Json.createReader(new StringReader(result));
    JsonObject jobj = jsonReader.readObject();

    //Json-p Patch
    jobj = Json.createPatchBuilder()
        .add("/actores", "mafalda")
        .build()
        .apply(jobj);

    return jobj.toString();
}

Notese que mediante el método createMovieWithActor realizamos 1- Marshalling manual, 2- Unmarshalling hacia JsonObject y 3- Agregamos una nueva propiedad denominada actores, manipulando exclusivamente el objeto JSON. Posteriomente exponemos este método con una nueva ruta mediante findWithActors

jsonp1

Como referencia visualizar el estado del proyecto en el commit 90b7de2.

JAX-RS Reactivo

Uno de los mayores cambios entre la publicación de JavaEE 7 y JavaEE 8 fue la popularización del manifiesto y consecuentemente de los clientes http reactivos, cambió que fue adoptado por JAX-RS.

Para probar esta caracteristica, crearemos un nuevo DAO que se comunicara vía REST para obtener los detalles de una película basándose unicamente en su código de IMDB. Para este ejercicio se requiere obtener una API key en OMDB.

@Stateless
public class OmdbMovieDao {

    private static final String OMDB_KEY = "reemplazarporunallavefuncionalaca";
    private static final String OMDB_BASE_URL = "http://www.omdbapi.com/?apikey=" + OMDB_KEY;

    public CompletionStage<String> findActors(String imdb){

        String requestUrl = OMDB_BASE_URL + "&i=" + imdb;

        //Intentar buscar los detalles
        //Parametrizamos el cliente
        WebTarget target = ClientBuilder.newBuilder()
                .connectTimeout(2, TimeUnit.SECONDS)
                .readTimeout(2, TimeUnit.SECONDS)
                .build()
                .target(requestUrl);

        CompletionStage<String> future = target.request()
                .accept(MediaType.APPLICATION_JSON)
                .rx()
                .get(String.class);
        return future;
    }
}

A partir del DAO podemos observar que al construir nuestra petición utilizando .rx() y .get obtenemos como resultado un objeto de tipo CompletionStage. CompletionStage fue una de las nuevas APIs(y de hecho la única reactiva) integrada en Java 8, por lo que JavaEE 8 la adopta como su mecanismo para la evaluación de CompletableFutures y combinación de resultados entre distintos orígenes.

Al estar listo nuestro nuevo DAO, podemos inyectarlo en MovieEndpoint e integrarlo en el proceso de patching, para combinar los resultados almacenados en la base de datos, con los datos obtenidos desde OMDB de forma reactiva.

@EJB
OmdbMovieDao omdbDao;

//Otros metodos

@GET
@Path("/with-actors/{id:[0-9][0-9]*}")
public void findWithActors(@PathParam("id") final Long id, @Suspended AsyncResponse response) {

    Movie movie = movieDao.findById(id);

    if (movie == null) {
        response.resume(new NotFoundException());
    }
    String movieString = JsonbBuilder.create().toJson(movie);

    CompletionStage<String> omdbInfo = omdbDao.findActors(movie.getImdb());

    omdbInfo.thenApply((omdbResponse) -> {

        JsonReader orgMovieJsonReader = Json.createReader(new StringReader(movieString));
        JsonObject orgMovie = orgMovieJsonReader.readObject();

        JsonReader omdbJsonReader = Json.createReader(new StringReader(omdbResponse));
        JsonObject omdbMovie = omdbJsonReader.readObject();

        //Json-p Patch
        orgMovie = Json.createPatchBuilder()
            .add("/actores", omdbMovie.getString("Actors", "mafalda"))
            .build()
            .apply(orgMovie);

        return orgMovie.toString();
    })
    .thenAccept(response::resume);
}

La respuesta deberá ser transparente al usuario, dependiendo de la velocidad de la conexión se observara que la respuesta sera generada solo al completar la petición hacia OMDB, «reaccionando» a este evento y parchando el JSON original con la nueva información.

jaxrs1

CDI 2.0 (Async events)

Una de las características bastante utilizadas mediante CDI es la creación de eventos y listener, mediante los cuales un componente puede disparar un evento y podemos declarar un método que reacciona al evento. Para probar esta característica necesitaremos:

Agregar soporte a CDI

Podemos utilizar el asistente de NetBeans para generar un archivo beans.xml, el cual activara CDI en todo el proyecto:

beans1

beans2

Agregar un bean que reaccione a los eventos y el evento

La primera pieza de nuestro evento sera un observador con CDI, el método solo genera información en la salida estandard despues de una pausa de 5 segundos, a pesar que nuestro evento sera reactivo, el mismo aun es de tipo blocking por lo que se ejecutara en el mismo thread que dispare el evento.

@Named
public class OmdbMovieObserver {
    public void logMovieLookup(@Observes String imdb){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException ex) {
            Logger.getLogger(OmdbMovieObserver.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Buscando " + imdb);
    }
}

Luego, dentro de OmdbDao agregaremos el evento el cual en este momento aun es de tipo blocking

@Inject
Event<String> lookupMovie;

public CompletionStage<String> findActors(String imdb){

    lookupMovie.fire(imdb);
    //....

Al probar nuevamente el API notaremos que el evento se queda bloqueado después de emitir el evento, por lo que respuesta tardara como mínimo 10 segundos más el tiempo en bajar a la base de datos y consultar a OMDB.

Como referencia visualizar el estado del proyecto en el commit 96e4f18.

Agregar un observador asíncrono

Para corregir la situación anterior, cambiaremos el observador hacia un observador asíncrono

public void logMovieLookup(@ObservesAsync String imdb)

Y también la generación del evento para que el mismo sea asíncrono y utilice su propio thread. Al estar en un application server, también necesitamos de un ManagedExecutorService para la gestión del nuevo thread donde se ejecuta el evento en CDI. Utilizaremos el disponible por defecto en Payara.

public class OmdbMovieDao {

    @Inject
    Event<String> lookupMovie;

    @Resource
    ManagedExecutorService threadPool;

    public CompletionStage<String> findActors(String imdb){

        lookupMovie.fireAsync(imdb, NotificationOptions.ofExecutor(threadPool));

    //....

Al probar nuevamente nuestra API notaremos que el evento CDI se ejecutó en background y no bloquea más la comunicación.

asynccdi

Como referencia visualizar el estado del proyecto en el commit 2d722bd.

[Revisión Libro] Best Developer Job Ever!: 5-step plan to dream jobs, high salaries & career freedom por Bruno Souza

 

Datos:

  • Paginas: 95
  • Editorial: Amazon Digital Services LLC
  • Publicación: Julio 2018
  • Idioma: Inglés

Objetivo

Debo comenzar este párrafo con un comentario personal. Dos de las cosas más importantes que impulsaron mi carrera como arquitecto de software fueron consejos de Bruno:

  • En 2011 decidí enfocarme en apoyar durante mi tiempo libre a comunidades de software Open Source. En ese entonces yo había conocido GuateJUG gracias a participar como organizador en un chapter local de Open Source University Meetup de Sun Microsystems dónde mi principal interés no era Java sino más bien UNIX. Luego de algunos correos que Bruno me respondió amablemente y debo decir bastante entusiasmado, reiniciamos el grupo con una mejor idea de cómo funcionan los grupos de usuarios y pues el resto es historia :).
  • En 2016 Bruno preparaba un artículo de historias geniales en el mundo Java y decidí contribuir mostrando al mundo el tour de las aventuras de Duke, algunos meses después recibimos en San Francisco el Duke’s Choice Award en la categoría educativa. El Oscar de Java.

Ambas cosas me han abierto más oportunidades de las que me abrió la universidad, incluyendo viajes, eventos, amigos, consultorías, conocimiento, comidas exóticas y me ayudaron a decidir que mi «camino Ninja» en TI era en realidad bastante simple y a la vez un reto complejo: «divertirme haciendo software, BUEN software».

Así mismo he visto la carrera de diversos desarrolladores despegar de la misma forma, por lo que tenia motivos para hacer esta revisión 😁.

Sobre el libro

Diferente de algunos libros motivacionales que he leído, en este libro se presenta un abordaje bastante simple sobre un único tópico:

¿Cómo mejorar mi carrera como desarrollador?

El libro tiene una longitud muy muy corta, imagino que impreso no seria más grande que la atalaya, y en mi caso como lector promedio me tomó aproximadamente tres horas leerlo de principio a fin.

El libro está estructurado con los siguientes tópicos:

  1. Establecer tus fortalezas
  2. Definir tus objetivos
  3. Expandir tu red de contactos
  4. Formas correctas de autopromoción
  5. Como obtener mejores entrevistas

Cosas positivas

Si se lee superficialmente los tópicos pareciera que nos encontramos ante un libro enfocado a profesionales de administración de empresas o economía. Sin embargo para cada uno de los consejos Bruno toma el siguiente abordaje:

  • El consejo arranca con una etapa argumentativa, presentando diversas formas de lograr el mismo objetivo en TI y especialmente en desarrollo de software
  • Luego de eso y basado en experiencia en el mundo de TI, Bruno argumenta cuál sería la forma más fácil para acelerar tu carrera en TI
  • Se presentan algunas herramientas, tips y casos de éxito (de los cuales conozco a casi todos) de cómo estos tips fueron aplicados

Podría mejorar

Lastimosamente el libro no sé encuentra en español. Así mismo creo que podría verse beneficiado con un poco más de contenido gráfico y diagrama que faciliten la re-lectura de los consejos.

Para los lectores más amenos o más experimentados, puede parecer informal desde el punto de vista literario. De hecho está escrito haciendo hincapié en varias ocasiones sobre el mismo consejo, casi como una conversación frente a frente. Puede ser positivo o negativo dependiendo del tipo de literatura que estén buscando y al que estén acostumbrados.

¿Quienes deberían leer este libro?

  • Cualquier profesional de TI, especialmente estudiantes iniciando su jornada
  • Reclutadores de TI para entender cómo funciona este mundo

Con pocos (casi nada) de dólares se ahorrarán como 5 años en entender cómo destacar en TI.

Para finalizar, creo que el siguiente extracto resume el contenido del libro:

People can be givers or takers. The givers come in and bring things others can benefit from while the takers take more than they give and ultimately drag the network down by trying to benefit themselves. That’s why givers tend to grow more than takers or matchers.

Creación de APIs REST con Jakarta EE 8, NetBeans 9 y Payara 5 [Videotutorial]

Recientemente tuve la necesidad de iniciar una capacitación a los nuevos miembros del equipo Nabenik.

Para hacerlo divertido decidí grabar parte de estas capacitaciones, en una serie de capsulas cortas. En esta primera entrega se discute:

  • Creación de proyectos con Java / Jakarta EE 8 y NetBeans 9
  • Creación de pool de conexiones con Payara 5 y PostgreSQL 9
  • Creación de persistence unit y mapeos con JPA
  • Creación de endpoints REST y repositorios de datos con patrón Facade
  • Creación de repositorios de datos con EJB

El audio es el original de ambiente (acepto contribuciones para un mic más pro :D). Toda retroalimentación es bienvenida