Polymorphism è un fondamental concetto del programmazione orientata a oggetti, che permette di trattare oggetti di diversi tipi come istanze di una superclassa comune. Questa flexibilità è essenziale per la creazione di sistemi che possono essere facilmente estesi e mantenuti. Mentre i tradizionali database SQL combinati con Jakarta Persistence (JPA) possono gestire i dati polimorfi, i database NoSQL offrono evidenti vantaggi. Diversamente dal SQL, che richiede definizioni di schema rigide, i database NoSQL adottano un approccio schema-less, supportando intrinsecamente strutture di dati dinamiche e flexible. Questa flexibilità diventa particolarmente attraente quando è integrata con Jakarta NoSQL, uno strumento che fornisce un robusto supporto per la definizione e la gestione di polimorfi campi attraverso convertitori custom.
In molte aziende, c’è un comune necessità di gestire diversi tipi di oggetti dati. Per esempio, un platform e-commerce può gestire diverse modalità di pagamento come carte di credito, digital wallets e bonificazioni bancarie, ciascuna con specifiche proprietà. Analogamente, asset management systems in large corporations deal with different types of assets like real estate, machinery and intellectual property, each with its own unique properties. I sistemi sanitari devono ospitare diverse tipologie di dati, da informazioni personali a registrazioni mediche e risultati di test. Utilizzando database NoSQL con polimorfi campi, è possibile memorizzare e gestire in modo coerente questi diversi tipi di dati. La natura schema-less del database NoSQL facilita l’adattamento alle mutevoli necessità rispetto a database relazionali.
Questa guida mostrerà come utilizzare Jakarta NoSQL per gestire campi polimorfici utilizzando convertitori personalizzati. Includeremo codice di esempio per l’integrazione dei servizi REST utilizzando Helidon e Oracle NoSQL. Questo esempio dimostrerà l’applicazione pratica del polimorfismo nella gestione efficiente di vari tipi di dati in un ambiente di database NoSQL senza schema.
Utilizzo del polimorfismo con NoSQL e Jakarta NoSQL
Questa guida esplorerà le capacità NoSQL e senza schema nel mondo Java utilizzando Oracle NoSQL, Java Helidon e Rest API. Creeremo un’entità Machine
in cui forniremo un campo engine
che convertiremo in JSON. Grazie alla naturale flessibilità di Oracle NoSQL e al suo design senza schema, questo approccio funziona in modo fluido.
Il primo passo è creare il progetto Helidon, dove puoi utilizzare Helidon Starter: Helidon Starter.
Dopo aver creato un progetto conforme a Microprofile, il passo successivo è includere il driver Oracle NoSQL: Oracle NoSQL Driver.
Nel file delle proprietà, poiché eseguiremo in locale, abbiamo bisogno di due proprietà: una per definire la connessione host e la seconda per definire il nome del database:
jnosql.document.database=machines
jnosql.oracle.nosql.host=http://localhost:8080
Aggiorna anche la porta per utilizzare 8181:
server.port=8181
Ecco la traduzione in italiano:
docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce
Usando Docker, semplifichiamo il processo di configurazione e assicuriamo che la nostra istanza di Oracle NoSQL sia in esecuzione in un ambiente controllato. Questa configurazione fornisce un approccio pratico per scopi di sviluppo e test, evidenziando la flessibilità di distribuire Oracle NoSQL in diversi ambienti, inclusa l’infrastruttura cloud.
Dopo aver impostato la configurazione e il database, il passaggio successivo prevede la definizione dell’Entità
e la creazione dell’implementazione del Convertitore
. In questo esempio, dimostreremo l’integrazione fluida di Jakarta NoSQL e Jakarta JSON-B, mostrando come le diverse specifiche Jakarta possano lavorare insieme in modo efficace.
Il primo passo è definire l’entità Macchina
, che incorpora un campo Motore
polimorfico.
@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;
// Getter e setter
}
Successivamente, definiamo la classe Motore
, specificando i tipi e le implementazioni utilizzando JsonbTypeInfo
per gestire il polimorfismo:
@JsonbTypeInfo(
key = "type",
value = {
@JsonbSubtype(alias = "gas", type = GasEngine.class),
@JsonbSubtype(alias = "electric", type = ElectricEngine.class)
}
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
// Attributi comuni del motore
// Getter e setter
}
Il convertitore del motore potrebbe cambiare a seconda del provider; può funzionare come Stringa
, Map<Stringa, Oggetto>
, BSON
, ecc.
Dopo aver impostato la configurazione e il database, il prossimo passo è creare il ponte applicazione e database. Eclipse JNoSQL integra due specifiche, Jakarta NoSQL e Jakarta Data, utilizzando un’unica interfaccia per raggiungere questo obiettivo. Le annotazioni gestiscono i passaggi necessari.
In primo luogo, definiamo l’interfaccia MachineRepository
:
@Repository
public interface MachineRepository extends BasicRepository<Machine, String> {
@Query("from Machine where engine.type = :type")
List<Machine> findByType(@Param("type") String type);
}
Questa interfaccia repository ci permette di cercare elementi direttamente all’interno dei dati JSON senza alcun problema, e puoi estenderla ulteriormente senza creare una struttura rigida.
Successivamente, definiamo il controller per esporre questa risorsa:
@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);
}
}
Questo controller espone endpoint per la gestione delle macchine, inclusi l’ottenimento delle macchine per tipo e la paginazione.
Infine, esegui l’applicazione e inserisci i dati utilizzando i seguenti comandi curl
:
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
}'
Questa configurazione ti permette di cercare per tipo all’interno del JSON, e la paginazione è facilmente implementabile. Per maggiori informazioni sulle tecniche di paginazione, consulta questo articolo.
Con alcuni dati inseriti, puoi esplorare e comprendere come funziona la ricerca:
- Ottieni macchine con paginazione
- Ottieni tutte le macchine
- Ottieni macchine a gas
Considerazioni finali
L’integrazione del polimorfismo con i database NoSQL utilizzando Jakarta NoSQL e Jakarta JSON-B offre flessibilità ed efficienza nella gestione di diversi tipi di dati. Sfruttando la natura senza schema di NoSQL, questo approccio semplifica lo sviluppo e migliora l’adattabilità dell’applicazione. Per l’esempio completo e il codice sorgente, visita soujava/helidon-oracle-json-types.
Source:
https://dzone.com/articles/intro-to-polymorphism-with-db-engines-in-nosql