Polymorphism est un concept fondamental de la programmation orientée objet. Il permet de traiter des objets de types différents comme instances d’une superclasse commune. Cette flexibilité est indispensable pour créer systèmes qui peuvent être aisément étendus et maintenus. Les bases de données SQL traditionnelles, combinées avec Jakarta Persistence (JPA), peuvent gérer les données polymorphes, mais les bases de données NoSQL offrent des avantages distinctes. À l’inverse des bases de données SQL qui nécessitent des définitions de schémas strictes, les bases de données NoSQL adoptent une approche sans schéma, supportant par nature des structures de données dynamiques et flexible. Cette flexibilité devient particulièrement attrayante lorsqu’elle est intégrée avec Jakarta NoSQL, un outil qui fournit une robuste support pour définir et gérer les champs polymorphes via des convertisseurs customisés.
Dans de nombreuses applications d’entreprises, il y a un besoin courant de gérer les objets de données de types différents. Par exemple, une plateforme de commerce électronique peut gérer divers modes de paiement tels que les cartes de crédit, les porte-monnaie électroniques et les virements bancaires, chacun avec des attributs spécifiques. De même, les systèmes de gestion des actifs dans les grandes sociétés traitent des types d’actifs différents tels que les biens immobiliers, la machinery et la propriété intellectuelle, chacun avec ses propres propriétés unique. Les systèmes de santé doivent accommoder divers types de données, des informations personnelles aux records médicaux et aux résultats de tests. Utiliser les bases de données NoSQL avec des champs polymorphes peut stocke et gérer ces types de données diversifiés en cohésion. La nature sans schéma des bases de données NoSQL facilite l’adaptation aux changements de besoin par rapport aux bases de données relationnelles.
Voici la traduction en français :
Ce tutoriel montrera comment utiliser Jakarta NoSQL pour gérer des champs polymorphes à l’aide de convertisseurs personnalisés. Nous inclurons un exemple de code pour l’intégration de services REST utilisant Helidon et Oracle NoSQL. Cet exemple démontrera l’application pratique du polymorphisme dans la gestion efficace de différents types de données dans un environnement de base de données NoSQL sans schéma.
Utilisation du polymorphisme avec NoSQL et Jakarta NoSQL
Ce tutoriel explorera les capacités NoSQL et sans schéma dans le monde Java à l’aide d’Oracle NoSQL, de Java Helidon et de l’API Rest. Nous créerons une entité Machine
où elle fournira un champ engine
que nous convertirons en JSON. Grâce à la flexibilité naturelle d’Oracle NoSQL et à sa conception sans schéma, cette approche fonctionne de manière transparente.
La première étape consiste à créer le projet Helidon, où vous pouvez utiliser le démarreur Helidon : Démarreur Helidon.
Après avoir créé un projet conforme à Microprofile, l’étape suivante consiste à inclure le pilote Oracle NoSQL : Pilote Oracle NoSQL.
Dans le fichier de propriétés, puisque nous allons l’exécuter localement, nous avons besoin de deux propriétés : une pour définir la connexion hôte et la seconde pour définir le nom de la base de données :
jnosql.document.database=machines
jnosql.oracle.nosql.host=http://localhost:8080
Mettez également à jour le port pour utiliser 8181 :
server.port=8181
Le prochain pas consiste à configurer et à exécuter Oracle NoSQL. Pour faciliter les choses, nous utiliserons Docker, mais il est important de noter que Oracle NoSQL supporte également la déploiement dans le cloud sur l’infrastructure Oracle :
docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce
En utilisant Docker, nous simplifions le processus de configuration et nous nous assurons que notre instance Oracle NoSQL fonctionne dans un environnement contrôlé. Cette configuration offre une approche pratique pour des besoins de développement et de test, soulignant la flexibilité de la déployment d’Oracle NoSQL dans différents environnements, y compris l’infrastructure cloud.
Une fois la configuration et la base de données mises en place, le prochain pas consiste à définir l’Entité
et à créer l’implémentation de la Convertisseur
. Dans cet exemple, nous démontrerons l’intégration fluide de Jakarta NoSQL et Jakarta JSON-B, montrant comment différentes spécifications de Jakarta peuvent travailler ensemble efficacement.
Le premier pas consiste à définir l’Entité Machine
, qui comprend un champ Moteur
polymorphe.
@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
}
Ensuite, nous définissons la classe Moteur
, spécifiant les types et les implémentations en utilisant JsonbTypeInfo
pour gérer la polymorphie :
@JsonbTypeInfo(
key = "type",
value = {
@JsonbSubtype(alias = "gas", type = GasEngine.class),
@JsonbSubtype(alias = "electric", type = ElectricEngine.class)
}
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
// Attributs communs du moteur
// Getters and setters
}
Le convertisseur de moteur peut varier selon le fournisseur ; il peut fonctionner en tant que String
, Map
, BSON
, etc.
Après avoir configuré la configuration et la base de données, l’étape suivante consiste à créer le pont entre l’application et la base de données. Eclipse JNoSQL intègre deux spécifications, Jakarta NoSQL et Jakarta Data, en utilisant une seule interface pour y parvenir. Les annotations gèrent les étapes nécessaires.
Tout d’abord, nous définissons l’interface MachineRepository
:
@Repository
public interface MachineRepository extends BasicRepository<Machine, String> {
@Query("from Machine where engine.type = :type")
List<Machine> findByType(@Param("type") String type);
}
Cette interface de dépôt nous permet de rechercher des éléments directement dans les données JSON sans aucun problème, et vous pouvez l’étendre davantage sans créer une structure rigide.
Ensuite, nous définissons le contrôleur pour exposer cette ressource:
@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);
}
}
Ce contrôleur expose des points de terminaison pour gérer les machines, notamment pour obtenir des machines par type et la pagination.
Enfin, exécutez l’application et insérez des données à l’aide des commandes curl
suivantes:
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
}'
Cette configuration vous permet de rechercher par type dans le JSON, et la pagination est facilement mise en œuvre. Pour en savoir plus sur les techniques de pagination, reportez-vous à cet article.
Avec quelques données insérées, vous pouvez explorer et comprendre le fonctionnement de la recherche.
- Obtenir des machines avec pagination
- Obtenir toutes les machines
- Obtenir les machines à gaz
Pensées finales
L’intégration de la polymorphisme avec les bases de données NoSQL à l’aide de Jakarta NoSQL et de Jakarta JSON-B offre une flexibilité et une efficacité accrues dans la gestion de types de données diverses. En exploitant la nature schéma-libre des NoSQL, cette approche simplifie le développement et améliore l’adaptabilité des applications. Pour l’exemple complet et le code source, veuillez visiter soujava/helidon-oracle-json-types.
Source:
https://dzone.com/articles/intro-to-polymorphism-with-db-engines-in-nosql