O polimorfismo, um conceito fundamental na programação orientada para objectos, permite que objectos de diferentes tipos sejam tratados como instâncias de uma superclasse comum. Esta flexibilidade é essencial para criar sistemas que possam ser facilmente alargados e mantidos. Embora as bases de dados SQL tradicionais, em combinação com Jakarta Persistence (JPA), possam tratar dados polimórficos, as bases de dados NoSQL oferecem vantagens distintas. Ao contrário das bases de dados SQL, que exigem definições de esquema rigorosas, as bases de dados NoSQL adoptam uma abordagem sem esquema, suportando inerentemente estruturas de dados dinâmicas e flexíveis. Essa flexibilidade se torna especialmente atraente quando integrada ao Jakarta NoSQL, uma ferramenta que oferece suporte robusto para definir e gerenciar campos polimórficos por meio de conversores personalizados.
Em muitos aplicativos corporativos, há uma necessidade comum de gerenciar diferentes tipos de objetos de dados. Por exemplo, uma plataforma de comércio eletrónico pode gerir vários métodos de pagamento, como cartões de crédito, carteiras digitais e transferências bancárias, cada um com atributos específicos. Do mesmo modo, os sistemas de gestão de activos em grandes empresas lidam com diferentes tipos de activos, como imóveis, máquinas e propriedade intelectual, cada um com propriedades únicas. Os sistemas de cuidados de saúde têm de acomodar vários tipos de dados, desde informações pessoais a registos médicos e resultados de testes. A utilização de bases de dados NoSQL com campos polimórficos pode armazenar e gerir estes diversos tipos de dados de forma coesa. A natureza sem esquema das bases de dados NoSQL também facilita a adaptação a requisitos variáveis do que as bases de dados relacionais.
Este tutorial mostrará como usar o Jakarta NoSQL para gerenciar campos polimórficos usando conversores personalizados. Incluiremos código de exemplo para integrar serviços REST usando Helidon e Oracle NoSQL. Este exemplo demonstrará a aplicação prática do polimorfismo no gerenciamento eficiente de vários tipos de dados em um ambiente de banco de dados NoSQL sem esquema.
Usando Polimorfismo Com NoSQL e Jakarta NoSQL
Este tutorial explorará os recursos NoSQL e sem esquema no mundo Java usando Oracle NoSQL, Java Helidon e Rest API. Criaremos uma entidade Machine
onde fornecerá um campo engine
que converteremos para JSON. Graças à flexibilidade natural do Oracle NoSQL e ao seu design sem esquema, essa abordagem funciona perfeitamente.
O primeiro passo é criar o projeto Helidon, onde você pode usar o Helidon Starter: Helidon Starter.
Após criar um projeto compatível com Microprofile, a próxima etapa é incluir o driver Oracle NoSQL: Oracle NoSQL Driver.
No arquivo de propriedades, como vamos executar localmente, precisamos de duas propriedades: uma para definir a conexão do host e a segunda para definir o nome do banco de dados:
jnosql.document.database=machines
jnosql.oracle.nosql.host=http://localhost:8080
Além disso, atualize a porta para usar 8181:
server.port=8181
O próximo passo é configurar e executar o Oracle NoSQL. Para facilitar, usaremos o Docker, mas é importante observar que o Oracle NoSQL também é compatível com o deployment em nuvem na infraestrutura da Oracle:
docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce
Ao usar Docker, simplificamos o processo de configuração e garantimos que nossa instância do Oracle NoSQL esteja sendo executada em um ambiente controlado. Esta configuração fornece uma abordagem prática para fins de desenvolvimento e teste, destacando a flexibilidade de implantar o Oracle NoSQL em diferentes ambientes, incluindo a infraestrutura de nuvem.
Após configurar a configuração e o banco de dados, a próxima etapa envolve definir a Entidade
e criar a implementação do Conversor
. Neste exemplo, demonstraremos a integração perfeita do Jakarta NoSQL e do Jakarta JSON-B, mostrando como as diferentes especificações do Jakarta podem trabalhar juntas de maneira eficaz.
A etapa inicial é definir a entidade Máquina
, que incorpora um campo Motor
polimórfico.
@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 e setters
}
Em seguida, definimos a classe Motor
, especificando os tipos e as implementações usando JsonbTypeInfo
para lidar com o polimorfismo:
@JsonbTypeInfo(
key = "type",
value = {
@JsonbSubtype(alias = "gas", type = GasEngine.class),
@JsonbSubtype(alias = "electric", type = ElectricEngine.class)
}
)
@JsonbVisibility(FieldAccessStrategy.class)
public abstract class Engine {
// Atributos comuns do motor
// Getters e setters
}
O conversor do motor pode mudar de acordo com o provedor; pode funcionar como String
, Map<String, Object>
, BSON
, etc.
Após configurar a configuração e o banco de dados, a próxima etapa é criar a aplicação e a ponte do banco de dados. O Eclipse JNoSQL integra duas especificações, Jakarta NoSQL e Jakarta Data, usando uma única interface para alcançar isso. Anotações lidam com as etapas necessárias.
Primeiro, definimos a interface MachineRepository
:
@Repository
public interface MachineRepository extends BasicRepository<Machine, String> {
@Query("from Machine where engine.type = :type")
List<Machine> findByType(@Param("type") String type);
}
Essa interface de repositório nos permite pesquisar elementos diretamente dentro dos dados JSON sem problemas, e você pode estendê-la ainda mais sem criar uma estrutura rígida.
Em seguida, definimos o controlador para expor esse recurso:
@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);
}
}
Esse controlador expõe endpoints para gerenciar máquinas, incluindo a obtenção de máquinas por tipo e paginação.
Finalmente, execute o aplicativo e insira dados usando os seguintes comandos 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
}'
Essa configuração permite que você pesquise por tipo dentro do JSON, e a paginação é facilmente implementada. Para mais informações sobre técnicas de paginação, consulte este artigo.
Com alguns dados inseridos, você pode explorar e entender como a pesquisa funciona.
- Obter máquinas com paginação
- Obter todas as máquinas
- Obter máquinas de gas
Pensamentos finais
A integração de polimorfismo com bases de dados NoSQL usando Jakarta NoSQL e Jakarta JSON-B oferece flexibilidade e eficiência na gestão de tipos de dados diversos. Ao aproveitar a natureza esquemaless de NoSQL, essa abordagem simplifica o desenvolvimento e melhora a adaptabilidade do aplicativo. Para o exemplo completo e o código fonte, visite soujava/helidon-oracle-json-types.
Source:
https://dzone.com/articles/intro-to-polymorphism-with-db-engines-in-nosql