Introducción al polimorfismo con motores de bases de datos en NoSQL usando Jakarta NoSQL

Polimorfismo, un concepto fundamental en la programación orientada a objetos, permite que objetos de diferentes tipos sean tratados como instancias de una superclase común. Esta flexibilidad es esencial para crear sistemas que puedan ser fácilmente extendidos y mantenidos. Mientras que las bases de datos SQL tradicionales en combinación con Jakarta Persistence (JPA) pueden manejar datos polimórficos, las bases de datos NoSQL ofrecen ventajas distintas. A diferencia de las bases de datos SQL, que requieren definiciones de esquemas estrictos, las bases de datos NoSQL adoptan un enfoque sin esquema, soportando de manera inherente estructuras de datos dinámicas y flexibles. Esta flexibilidad se vuelve especialmente atractiva cuando se integra con Jakarta NoSQL, una herramienta que proporciona un soporte robusto para definir y gestionar campos polimórficos a través de convertidores personalizados.

En muchas aplicaciones empresariales, existe una necesidad común de gestionar diferentes tipos de objetos de datos. Por ejemplo, una plataforma de comercio electrónico puede manejar varios métodos de pago como tarjetas de crédito, billeteras digitales y transferencias bancarias, cada uno con atributos específicos. De manera similar, los sistemas de gestión de activos en grandes corporaciones manejan diferentes tipos de activos como bienes raíces, maquinaria y propiedad intelectual, cada uno con propiedades únicas. Los sistemas de salud deben acomodar varios tipos de datos, desde información personal hasta registros médicos y resultados de pruebas. Utilizar bases de datos NoSQL con campos polimórficos puede almacenar y gestionar estos diversos tipos de datos de manera cohesionada. La naturaleza sin esquema de las bases de datos NoSQL también facilita la adaptación a los requisitos cambiantes en comparación con las bases de datos relacionales.

Este tutorial mostrará cómo usar Jakarta NoSQL para administrar campos polimórficos utilizando conversores personalizados. Incluiremos código de muestra para integrar servicios REST utilizando Helidon y Oracle NoSQL. Este ejemplo demostrará la aplicación práctica del polimorfismo en la gestión eficiente de diversos tipos de datos en un entorno de base de datos NoSQL sin esquema.

Uso del polimorfismo con NoSQL y Jakarta NoSQL

Este tutorial explorará las capacidades NoSQL y sin esquema en el mundo de Java utilizando Oracle NoSQL, Java Helidon y API Rest. Crearemos una entidad Máquina donde proporcionará un campo motor que convertiremos a JSON. Gracias a la flexibilidad natural de Oracle NoSQL y su diseño sin esquema, este enfoque funciona sin problemas.

El primer paso es crear el proyecto Helidon, donde puede usar el Helidon Starter: Helidon Starter.

Después de crear un proyecto compatible con Microprofile, el siguiente paso es incluir el controlador de Oracle NoSQL: Oracle NoSQL Driver.

En el archivo de propiedades, dado que lo ejecutaremos localmente, necesitamos dos propiedades: una para definir la conexión de host y la segunda para definir el nombre de la base de datos:

Properties files

 

jnosql.document.database=machines
jnosql.oracle.nosql.host=http://localhost:8080

También, actualice el puerto para usar 8181:

Properties files

 

server.port=8181

El siguiente paso es configurar y ejecutar Oracle NoSQL. Para facilitar el proceso, utilizaremos Docker, pero es importante tener en cuenta que Oracle NoSQL también admite el despliegue en la nube en la infraestructura de Oracle:

Shell

 

docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce

Al usar Docker, simplificamos el proceso de configuración y aseguramos que nuestra instancia de Oracle NoSQL se esté ejecutando en un entorno controlado. Esta configuración proporciona un enfoque práctico para fines de desarrollo y pruebas, resaltando la flexibilidad de implementar Oracle NoSQL en diferentes entornos, incluida la infraestructura de la nube.

Después de configurar la configuración y la base de datos, el siguiente paso implica definir la Entidad y crear la implementación del Convertidor. En este ejemplo, demostraremos la integración sin problemas de Jakarta NoSQL y Jakarta JSON-B, mostrando cómo diferentes especificaciones de Jakarta pueden trabajar juntas de manera eficaz.

El paso inicial es definir la entidad Máquina, que incorpora un campo Motor polimórfico.

Java

 


@Entity
@JsonbVisibility(FieldAccessStrategy.class)
public class Machine {

    @Id
    private String id;

    @Column
    @Convert(EngineConverter.class)
    private Engine engine;

    @Column
    private String manufacturer;

    @Column
    private int year;

    // Getters y setters
}

A continuación, definimos la clase Motor, especificando los tipos e implementaciones utilizando JsonbTypeInfo para manejar el polimorfismo:

Java

 

@JsonbTypeInfo(
        key = "type",
        value = {
                @JsonbSubtype(alias = "gas", type = GasEngine.class),
                @JsonbSubtype(alias = "electric", type = ElectricEngine.class)
        }
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
    // Atributos comunes del motor

    // Getters y setters
}

El convertidor de motores puede cambiar según el proveedor; puede funcionar como String, Map<String, Object>, BSON, etc.

Después de configurar la configuración y la base de datos, el siguiente paso es crear la aplicación y el puente de la base de datos. Eclipse JNoSQL integra dos especificaciones, Jakarta NoSQL y Jakarta Data, utilizando una sola interfaz para lograr esto. Las anotaciones manejan los pasos necesarios.

Primero, definimos la interfaz MachineRepository:

Java

 

@Repository
public interface MachineRepository extends BasicRepository<Machine, String> {

    @Query("from Machine where engine.type = :type")
    List<Machine> findByType(@Param("type") String type);
}

Esta interfaz de repositorio nos permite buscar elementos directamente dentro de los datos JSON sin ningún problema, y puede extenderla aún más sin crear una estructura rígida.

A continuación, definimos el controlador para exponer este recurso:

Java

 


@Path("/machines")
@ApplicationScoped
public class MachineResource {

    private static final Logger LOGGER = Logger.getLogger(MachineResource.class.getName());

    public static final Order<Machine> ORDER_MANUFACTURER = Order.by(Sort.asc("manufacturer"));

    private final MachineRepository repository;

    @Inject
    public MachineResource(@Database(DatabaseType.DOCUMENT) MachineRepository repository) {
        this.repository = repository;
    }

    @GET
    public List<Machine> getMachines(@QueryParam("page") @DefaultValue("1") int page, @QueryParam("page_size") @DefaultValue("10") int pageSize) {
        LOGGER.info("Get machines from page " + page + " with page size " + pageSize);
        Page<Machine> machines = this.repository.findAll(PageRequest.ofPage(page).size(pageSize), ORDER_MANUFACTURER);
        return machines.content();
    }

    @GET
    @Path("gas")
    public List<Machine> getGasMachines() {
        return this.repository.findByType("gas");
    }

    @GET
    @Path("electric")
    public List<Machine> getElectricMachines() {
        return this.repository.findByType("electric");
    }

    @GET
    @Path("{id}")
    public Machine get(@PathParam("id") String id) {
        LOGGER.info("Get machine by id " + id);
        return this.repository.findById(id)
                .orElseThrow(() -> new WebApplicationException("Machine not found with id: " + id, Response.Status.NOT_FOUND));
    }

    @PUT
    public void save(Machine machine) {
        LOGGER.info("Saving a machine " + machine);
        this.repository.save(machine);
    }
}

Este controlador expone endpoints para administrar máquinas, incluida la obtención de máquinas por tipo y paginación.

Finalmente, ejecute la aplicación e inserte datos utilizando los siguientes comandos curl:

Shell

 

curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
"id": "1",
"model": "Thunderbolt V8",
"engine": {
"type": "gas",
"horsepower": 450
},
"manufacturer": "Mustang",
"year": 2021,
"weight": 1600.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
    "id": "2",
    "model": "Eagle Eye EV",
    "engine": {
        "type": "electric",
        "horsepower": 300
    },
    "manufacturer": "Tesla",
    "year": 2022,
    "weight": 1400.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
    "id": "3",
    "model": "Road Runner GT",
    "engine": {
        "type": "gas",
        "horsepower": 400
    },
    "manufacturer": "Chevrolet",
    "year": 2020,
    "weight": 1700.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
    "id": "4",
    "model": "Solaris X",
    "engine": {
        "type": "electric",
        "horsepower": 350
    },
    "manufacturer": "Nissan",
    "year": 2023,
    "weight": 1350.0
}'

curl --location --request PUT 'http://localhost:8181/machines' \
--header 'Content-Type: application/json' \
--data '{
    "id": "5",
    "model": "Fusion Hybrid 2024",
    "engine": {
        "type": "electric",
        "horsepower": 320
    },
    "manufacturer": "Toyota",
    "year": 2024,
    "weight": 1450.0
}'

Esta configuración le permite buscar por tipo dentro del JSON, y la paginación se implementa fácilmente. Para más información sobre las técnicas de paginación, consulte este artículo.

Con algunos datos insertados, puede explorar y entender cómo funciona la búsqueda:

  • Obtener máquinas con paginación
  • Obtener todas las máquinas
  • Obtener máquinas de gas

Pensamientos finales

La integración del polimorfismo con bases de datos NoSQL utilizando Jakarta NoSQL y Jakarta JSON-B ofrece flexibilidad y eficiencia en la gestión de diversos tipos de datos. Al aprovechar la naturaleza sin esquema de NoSQL, este enfoque simplifica el desarrollo y mejora la adaptabilidad de la aplicación. Para el ejemplo completo y el código fuente, visite soujava/helidon-oracle-json-types.

Source:
https://dzone.com/articles/intro-to-polymorphism-with-db-engines-in-nosql