Tabla de Contenidos

11 - Librerías

En casi todos los lenguajes de programación existe el concepto de librerías. Una librería se puede entender como un conjunto de clases, que poseen una serie de métodos y atributos. Lo realmente interesante de estas librerías es que nos permiten reutilizar código, es decir que podemos hacer uso de los métodos, clases y atributos que componen la librería evitando así tener que implementar nosotros mismos esas funcionalidades.

Por ejemplo, cuando queremos imprimir algo por pantalla estamos usando el método System.out.print(). En realidad, la clase System pertenece a la librería java.lang, que es la librería estándar de Java, con lo que no hace falta importarla. También hemos usado en nuestros ejemplos las clases List y ArrayList y sus métodos. Estas clases está definidas en la librería java.util, que, al no pertenecer a la librería estándar, tenemos que importar para poder utilizarla.

package ejemplos.T09;

import java.util.ArrayList;
import java.util.List;

public class Librerias {
    
    public static void main(String[] args) {
        List<Integer> numeros = new ArrayList<>();

        System.out.println("Hola mundo");
    }
}

Lo más interesante de las librerías en Java, es que nosotros también podemos crearlas y hacer uso de ellas al interior de nuestros proyectos. Pero antes de ver como crear e importar librerías, necesitamos tener claro otro concepto relacionado: los paquetes.

Paquetes

Los paquetes (package) son el mecanismo que usa Java para facilitar la modularidad del código. Un paquete puede contener una o más definiciones de interfaces y clases, distribuyéndose habitualmente como un archivo. Para utilizar los elementos de un paquete es necesario importar este en el módulo de código en curso, usando para ello la sentencia import.

Los paquetes Java equivalen a directorios. Es decir, cada miembro del paquete (separado por puntos) se traduce a un directorio en el sistema de archivos. Por ejemplo, un paquete declarado como:

package net.fpmislata.graficos2d;

debe almacenarse en:

net\fpmislata\graficos2d

Crear paquetes

Para crear un paquete en Java, simplemente debemos definir su nombre al principio del fichero mediante la palabra reservada package. Como vimos en los primeros temas, este proceso lo podemos simplificar si utilizamos algún IDE. Por ejemplo, en VSC podemos usar la orden New Package para crear un nuevo paquete. Cualquier clase que creemos dentro de ese paquete ya tendrá incorporado la definición del paquete al principio del fichero:

Por supuesto, puedes crear paquetes dentro de otros paquetes, generando así una estructura jerárquica de tus clases. El nombre de los subpaquetes (paquetes contenidos en otros) se compondrán del identificador del contenedor seguido de un punto y el nombre del subpaquete. De existir niveles adicionales se agregarían los distintos identificadores separados por puntos, formando así el nombre completo del paquete.

A la hora de nombrar paquetes, normalmente se pone el nombre de dominio inverso de nivel superior. Por ejemplo, com.fpmislata.nombrePaquete. Esto se hace principalmente para que no coincida con los nombres de otros paquetes que importamos.

Importar paquetes

Para poder importar paquetes, tenemos que usar la cláusula import para poder usar su contenido. Por ejemplo, si queremos usar las clases List y ArrayList, debemos importar antes los paquetes donde están definidos:

package ejemplos.T09;

import java.util.ArrayList;
import java.util.List;

public class Librerias {
    
    public static void main(String[] args) {
        List<Integer> numeros = new ArrayList<>();

        System.out.println("Hola mundo");
    }
}

La cláusula import puede utilizarse para importar un elemento concreto de un paquete (como en el ejemplo anterior) o importar todas las clases definidas en el mismo mediante *:

import java.util.*;

De esta forma, tendríamos acceso a todos los elementos del paquete java.util.

Hasta ahora hemos importado paquetes de las librerías definidas en Java, pero también podemos importar paquetes creados por nosotros mismos. Por ejemplo, crea dos paquetes llamados paqueteA y paqueteB, y dentro dos clases en cada uno: claseA y claseB:

package paqueteA;

import paqueteB.ClaseB;

public class ClaseA {

    public static void main(String[] args) {
        ClaseB otraClase = new ClaseB();
    }
    
}

package paqueteB;

public class ClaseB {
    
    public ClaseB() {
        System.out.println("Creando la clase B");
    }
}

Asegúrate que la visibilidad del constructor de ClaseB sea public, ya que al estar definido en otro paquete tenemos que hacerlo accesible desde el exterior.

Si ejecutas la aplicación, verás como se crear el objeto de ClaseB y se ejecuta su constructor:

Creando la clase B

Librerías externas

Hasta ahora hemos incorporado a nuestro proyecto librerías básicas de Java (java.util, por ejemplo). En este punto, vamos a crear nuestras propias librerías para poder incorporarlas a otros proyectos. Para eso, vamos a crear un nuevo proyecto llamado libreriaExterna. Cambia el nombre de la clase inicial App por Calculadora y añade el siguiente contenido:

package com.fpmislata.libreriaExterna;

public class Calculadora {
    
    public int sumar(int numero1, int numero2) {
        return numero1 + numero2;
    }

    public int restar(int numero1, int numero2) {
        return numero1 - numero2;
    }

    public int multiplicar(int numero1, int numero2) {
        return numero1 * numero2;
    }

    public int dividir(int numero1, int numero2) {
        return numero1 / numero2;
    }

}

Como ves, nuestro proyecto no tiene clase inicial ni método main(), simplemente contiene una clase llamada Calculadora que nos permite hacer las operaciones básicas sobre dos enteros (sumar, restar, multiplicar y dividir).

Asegúrate de añadir el nombre del package al principio del archivo para después poder hacer referencia a él cuando importemos la librería.

La plataforma Java ofrece la capacidad de empaquetar las aplicaciones en un único archivo que facilita su gestión. Existen diversas formas de empaquetar las aplicaciones Java, pero la más común es en forma de archivos con la extensiónn .jar (Java ARchive). Para crear un archivo JAR desde VSC, debemos seleccionar el segundo icono de JAVA PROJECTS:

Si miramos la carpeta de nuestro proyecto, veremos que nos ha creado el archivo libreriaExterna.jar:

Ahora ya podemos usar nuestra librería en los proyectos que queramos. Lo podemos hacer de diferentes formas. Por ejemplo, crea un nuevo proyecto. En el panel del proyecto Java, añade la referencia a nuestro archivo .jar mediante Referenced Libraries:

En la clase principal del proyecto, ya podemos usar la clase Calculadora de nuestra librería (tenemos que importar la librería en nuestra clase principal, obviamente):

package ejemplos.T09.importar_librerias_externas;

import com.fpmislata.libreriaExterna.Calculadora;

public class Main {

    public static void main(String[] args) {
        Calculadora calc = new Calculadora();

        System.out.println(calc.sumar(3, 4));
    }
    
}

7

También podemos guardar los archivos .jar en la carpeta lib de la raíz de nuestro proyecto. La ventaja es que al guardar una copia del archivo .jar no nos afectan los posibles cambios a las librerías externas (sobre todo si son de terceros). La desventaja es que nuestros proyectos pesan más, al tener incorporados más archivos.

Si queremos incorporar librerías de terceros, seguimos el mismo procedimiento. Podemos bajarnos los archivos .jar e incorporarlos a nuestro proyecto. Otra opción es utilizar algún gestor de proyecto con gestión de dependencias como veremos a continuación.

Gestores de proyectos

Un gestor de proyecto nos ayuda a, entre otras cosas, gestionar todas las dependencias de forma automática. Imagínate que estás trabajando en un proyecto y se incorpora otra persona. Para poder empezar a trabajar en el proyecto desde su máquina, debería buscar y descargar todas las dependencias. Además, si alguna librería con la que estás trabajando se actualiza, deberías volver a descargarla para incorporar los cambios. Los gestores de dependencias te facilitan toda esa tarea.

Otro problema es que, a menudo, las librerías que nos descargamos dependen de otras librerías, con lo que deberíamos descargarnos éstas también. Con un gestor de dependencias, este proceso también se hace de forma automática.

En Java existen 3 gestores de proyectos que se han convertido en los más utilizados (sobre todo 2 de ellos):

De los 3, Maven y Gradle son los más utilizados hoy en día. En nuestro caso, vamos a utilizar Maven, ya que la curva de aprendizaje es más sencilla, además que no vamos a hacer proyectos demasiado complejos.

Maven

Maven es una herramienta de gestión de proyectos de desarrollo utilizada principalmente en Java utilizando conceptos provenientes de Ant. Es profundamente personalizable, permitiendo finalizar tareas complejas de forma rápida y reutilizando los resultados de ejecuciones pasadas.

La configuración de un proyecto se basa en un fichero XML en el cual se declaran los requerimientos para la construcción.

Maven añade principalmente las siguientes funcionalidades a Ant:

Maven trabaja con artefactos. Un artefacto Maven es como una librería Java con añadidos. Contiene las clases propias de la librería pero ademas incluye toda la información necesaria para su correcta gestión (grupo, versión, dependencias…).

Al crear un proyecto de Maven, automáticamente se nos generará una estructura de carpetas muy concreta que ya viene predefinida:

Lo primero que tenemos que hacer es instalar Maven en nuestro equipo. En este enlace tienes las instrucciones para hacerlo.

Vamos a crear un proyecto Maven en VSC. Primero, seleccionamos Create Java Project desde el panel de proyectos:

En tipo de proyecto seleccionamos Maven:

A continuación, nos aparecen varias arquitecturas predefinidas según el tipo de proyecto que vayamos a crear (web, React.js, Spring Boot…). Seleccionamos maven-archetype-quickstart (proyecto Maven simple):

Cuando creamos un proyecto, Maven nos pone por defecto la versión Java 1.8:
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

Podemos cambiar a la versión que queramos modificando las dos líneas. A partir de Java 8, para indicar la versión podemos sustituir las 2 líneas anteriores por:

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

Seleccionamos la versión que queramos utilizar (en nuestro caso, usaremos la última, la 1.4) y el groupId, que es el identificador único de la organización o grupo que crea el proyecto (en nuestro caso com.fpmislata) y el artifactId, que es el identificador único del artefacto principal de este proyecto (se podría decir que es el identificador del módulo dentro de la aplicación), es decir, este será el nombre del jar (escribimos ejemplo_maven).

Lo siguiente será seleccionar la carpeta donde queramos crear nuestro proyecto. Una vez la seleccionemos, VSC nos preguntará la versión del proyecto y tendremos que confirmar para terminar la creación del proyecto:

Si todo ha funcionado correctamente, ya tendremos nuestro proyecto Maven creado con la estructura de carpetas vista anteriormente (la clase principal, por defecto, se llamará App):

Repositorio local y remoto

Vamos a echar un vistazo al archivo pom.xml:

Además de la configuración de la aplicación (groupId, artifactId, version…), tenemos una sección llamada dependencies:

Es en esta sección donde vamos a añadir las librerías que va a utilizar nuestro proyecto. Si te fijas, ya hay una librería añadida: junit. Esta librería nos permite hacer pruebas (testing) a nuestro proyecto. Pero, ¿dónde se almacenan esas librerías?

Como hemos dicho antes, Maven busca las librerías primero en un repositorio local. Este repositorio está situado en <USER_HOME>/.m2/repository (aunque Maven nos permite cambiar esta localización por defecto). Si vemos el contenido del repositorio, encontramos la librería junit:

A la hora de buscar las dependencias de un proyecto, Maven mira el archivo pom.xml y comprueba primero si existen en el repositorio m2 (repositorio local). En caso de que allí no existan, irá al Maven Central Repository (repositorio central) y las descargará en nuestro repositorio local (m2) para que se pueda utilizar en todos los proyectos locales.

Para facilitarnos la búsqueda, podemos acceder a la página de busqueda de repositorios de Maven.

Para saber más sobre repositorios locales y remotos (cambiar la ubicación, crear repositorios remotos…), podéis mirar la página oficial de Maven.

Si salimos a Internet a traves de un proxy, lo tendrémos que configurar en Maven.

Añadiendo dependencias

Vamos a añadir una librería a nuestro proyecto para entender como funcionan los repositorios. Para añadir una dependencia, podríamos editar el archivo pom.xml y añadirla, pero VSC nos facilita el proceso. Si nos fijamos en el panel del proyecto Java, tenemos una sección llamada Maven dependencies donde podemos añadir dependencias de forma automática.

Por ejemplo, vamos a añadir la librería gson, de google, que nos permite transformar objetos Java a Json y viceversa. Le damos a añadir dependencia de Maven y escribimos gson en el buscador:

VSC nos mostrará una lista de librerías que coinciden con lo que hemos buscado. Elegimos la de com.google.code.gson y, si miramos ahora el archivo pom.xml vemos que lo ha añadido automáticamente:

Cuando guardamos el archivo, VSC añadirá la dependencia a nuestro proyecto automáticamente:

A partir de ahora, ya podemos utilizar la librería Gson en nuestros proyectos:

package com.fpmislata;

import com.google.gson.Gson;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        Gson gson = new Gson();
        System.out.println( "Hello World!" );
    }
}

¿Qué pasa si abrimos un proyecto con dependencias que no tenemos en nuestro repositorio local? Vamos a hacer la prueba. Renombra la carpeta gson en el directorio del repositorio local (<USER_HOME>/.m2/repository/com/google/code) a gson_2:

Ahora reinicia VSC y vuelve a mirar la carpeta anterior:

Como ves, Maven ha descargado de forma automática la librería desde el repositorio central, ya que no la ha encontrado en el repositorio local. Ésto es muy útil, ya que para empezar a trabajar con un proyecto que contiene librerías externas, solo tenemos que abrirlo y el IDE se encargará de descargar las dependencias necesarias. Eso sí, puede que al abrir proyectos a partir de ahora el IDE tarde un poco más (sobre todo al principio) al necesitar comprobar y descargar las dependencias que no están en el repositorio local.

Ejercicios

Ejercicio 1

Crea un proyecto Maven que contenga 2 paquetes (dentro del paquete original):

En el paquete front crea dos clases:

1.- Listado clientes
2.- Buscar cliente
0.- Salir
----------------------
Opción: 

Ejercicio 2

En el paquete back crea una clase llamada App (mismo nombre que en el front). Esta clase tendrá un método estático response() que devolverá la frase “Respuesta del servidor…”.

Modifica el método request() de la clase front.App para que muestre por pantalla el resultado de la función back.App.response().

Como verás, Java da un error al usar nombres de clases iguales (App). Averigua como solucionar el conflicto entre las clases front.App y front.back

Ejercicio 3

Crea la clase back.controller.CustomerController. Dentro de esta clase, crea el método findAll(), el cuál devolverá la frase “Listado de todos los clientes”.

Haz que el método back.App.response() llame al método anterior si la opción elegida por el usuario es el 1 y la frase “404 .- Recurso no encontrado” si se le pasa cualquier otra opción.

Ejercicio 4

Crea la clase back.domain.Customer con tres propiedades privadas: id, name y nif, los getters correspondientes y el método toString().

Crea una segunda clase back.domain.CustomerService. Esta clase tendrá un método findAll() que creará un listado de clientes (List<Customer>) y lo devolverá (crea tres o cuatro clientes en el listado para probar).

Haz que el método back.controller.CustomerController.findAll() devuelva el listado de clientes generado por el método back.domain.CustomerService.findAll().

El resultado deberá ser algo similar a ésto:

Opción: 1
Clientes:[ {1, Cliente 1, A11111111}, {2, Cliente 2, B22222222}, {3, Cliente 3, C22222222}, {4, Cliente 4, D22222222} ]
1.- Listado clientes

Ejercicio 5

Crea una última clase back.persistence.CustomerDao con el método findAll(). Traslada la creación del listado de clientes (básicamente la implementación del método back.domain.CustomerService.findAll()) a este método y haz que la clase CustomerService llame al método back.persistence.CustomerDao.findAll() y devuelva el resultado.

Ejercicio 6

Implementa la funcionalidad de buscar un cliente por id siguiendo la misma filosofía que la anterior (devolver el listado de todos los clientes).