Inleiding tot polymorfisme met database-engines in NoSQL met Jakarta NoSQL

Polymorfisme, een fundamenteel concept in objectgeoriënteerd programmeren, maakt het mogelijk om objecten van verschillende typen te behandelen als instanties van een gemeenschappelijke superklasse. Deze flexibiliteit is essentieel voor het maken van systemen die gemakkelijk kunnen worden uitgebreid en onderhouden. Hoewel traditionele SQL-databases in combinatie met Jakarta Persistence (JPA) polymorfe gegevens kunnen verwerken, bieden NoSQL-databases duidelijke voordelen. In tegenstelling tot SQL-databases, die strikte schema-definities vereisen, hanteren NoSQL-databases een schema-loze aanpak, waardoor dynamische en flexibele datastructuren inherent ondersteund worden. Deze flexibiliteit wordt vooral aantrekkelijk wanneer deze wordt geïntegreerd met Jakarta NoSQL, een tool die robuuste ondersteuning biedt voor het definiëren en beheren van polymorfe velden door middel van aangepaste converters.

In veel bedrijfstoepassingen is het vaak nodig om verschillende typen gegevensobjecten te beheren. Een e-commerce platform kan bijvoorbeeld verschillende betalingsmethoden verwerken, zoals creditcards, digitale portemonnees en bankoverschrijvingen, elk met specifieke attributen. Op dezelfde manier hebben systemen voor activabeheer in grote bedrijven te maken met verschillende soorten activa zoals onroerend goed, machines en intellectueel eigendom, elk met unieke eigenschappen. Systemen in de gezondheidszorg moeten verschillende soorten gegevens kunnen verwerken, van persoonlijke informatie tot medische dossiers en testresultaten. Door gebruik te maken van NoSQL databases met polymorfe velden kunnen deze verschillende datatypes samenhangend worden opgeslagen en beheerd. Het schema-loze karakter van NoSQL databases maakt het ook gemakkelijker om zich aan te passen aan veranderende eisen dan relationele databases.

Dit zelfstudieprogramma laat zien hoe u Jakarta NoSQL kunt gebruiken om polymorfische velden te beheren met behulp van aangepaste converters. We zullen voorbeeldcode opnemen voor de integratie van REST-services met behulp van Helidon en Oracle NoSQL. Dit voorbeeld zal de praktische toepassing van polymorfisme demonstreren bij het efficiënt beheren van verschillende gegevenstypen in een schema-loze NoSQL-databaseomgeving.

Polymorfisme gebruiken met NoSQL en Jakarta NoSQL

Deze zelfstudie zal de NoSQL- en schema-loze mogelijkheden in de Java-wereld verkennen met behulp van Oracle NoSQL, Java Helidon en Rest API. We zullen een Machine-entiteit maken waarbij we een engine-veld zullen converteren naar JSON. Dankzij de natuurlijke flexibiliteit van Oracle NoSQL en zijn schema-loze ontwerp werkt deze aanpak naadloos.

De eerste stap is het maken van het Helidon-project, waarbij u de Helidon Starter kunt gebruiken: Helidon Starter.

Na het maken van een Microprofile-compatibel project, is de volgende stap het opnemen van de Oracle NoSQL-driver: Oracle NoSQL Driver.

In het eigenschappenbestand, aangezien we lokaal zullen draaien, hebben we twee eigenschappen nodig: één om de hostverbinding te definiëren en de tweede om de databasenaam te definiëren:

Properties files

 

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

Pas ook de poort aan om 8181 te gebruiken:

Properties files

 

server.port=8181

Het volgende stap is het configureren en uitvoeren van Oracle NoSQL. Om het gemakker te maken, zullen we gebruik maken van Docker, maar het is belangrijk op te merken dat Oracle NoSQL ook ondersteuning biedt voor opslag in de cloud op de Oracle-infrastructuur:

Shell

 

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

Door Docker te gebruiken, simplifyeerden we het installatieproces en zorgen we ervoor dat onze Oracle NoSQL-instantie in een gereguleerd milieu draait. Deze setup biedt een praktische aanpak voor ontwikkeling en testdoelen, waardoor de flexibiliteit van het installeren van Oracle NoSQL in verschillende omgevingen, inclusief op cloudinfrastructuur, wordt benadrukt.

Na het configureren van de configuratie en de database is de volgende stap het definiëren van de Entity en het maken van de implementatie van de Converter. In dit voorbeeld zullen we de snelgaande integratie van Jakarta NoSQL en Jakarta JSON-B demonstreren, waaruit blijkt dat verschillende Jakarta-specificaties effectief samen kunnen werken.

Het eerste stap is het definiëren van de Machine entity, die een polymorfe Engine field bevat.

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 and setters
}

Volgend definiëren we de Engine klasse, waarbij we de typen en implementaties specificeren door middel van JsonbTypeInfo om polymorfie te behandelen:

Java

 

@JsonbTypeInfo(
        key = "type",
        value = {
                @JsonbSubtype(alias = "gas", type = GasEngine.class),
                @JsonbSubtype(alias = "electric", type = ElectricEngine.class)
        }
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
    // Algemene engine-attributen

    // Getters and setters
}

De engine-converter kan afhankelijk van de provider verschillen; hij kan werken als String, Map, BSON etc.

Na het instellen van de configuratie en de database is de volgende stap het maken van de applicatie- en databasebrug. Eclipse JNoSQL integreert twee specificaties, Jakarta NoSQL en Jakarta Data, met behulp van één interface om dit te bereiken. Annotaties verwerken de nodige stappen.

Eerst definiëren we de MachineRepository-interface:

Java

 

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

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

Deze repository-interface stelt ons in staat om elementen rechtstreeks binnen de JSON-gegevens te doorzoeken zonder problemen, en je kunt het verder uitbreiden zonder een starre structuur te creëren.

Vervolgens definiëren we de controller om deze resource bloot te leggen:

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);
    }
}

Deze controller exposeert endpoints voor het beheren van machines, inclusief het ophalen van machines per type en paginering.

Voer ten slotte de toepassing uit en voer gegevens in met behulp van de volgende curl-opdrachten:

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
}'

Deze setup stelt je in staat om op type binnen de JSON te zoeken, en paginering is gemakkelijk te implementeren. Voor meer informatie over paginatietechnieken, raadpleeg dit artikel.

Met enkele ingevoerde gegevens kun je verkennen en begrijpen hoe het zoeken werkt.

  • Machines ophalen met paginering
  • Alle machines ophalen
  • Gasmachines ophalen

Slotgedachten

Het integreren van polymorfisme met NoSQL-databases met behulp van Jakarta NoSQL en Jakarta JSON-B biedt flexibiliteit en efficiëntie bij het beheren van diverse gegevenstypen. Door gebruik te maken van de schema-loze aard van NoSQL, vereenvoudigt deze aanpak de ontwikkeling en verbetert de toepassingsadaptatie. Voor het volledige voorbeeld en de broncode, bezoek soujava/helidon-oracle-json-types.

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