Sunday, November 20, 2022

Spring boot 3 with Hibernate 6

Spring Boot 3.0


Spring boot 3 Features :
  • Spring Boot 3.0 will require Java 17
  • Jakarta EE 9 a new top-level jakarta package, replacing EE 8’s javax top-level package. It will also be the first version of Spring Boot that makes use of Jakarta EE 9 APIs (jakarta.*) instead of EE 8 (javax.*). 
  • Since Spring Boot 2.4 changed the way that application.properties and application.yaml files were loaded.

Hibernate ORM 6.0


Hibernate  Compatibility :

There are several layers of working with persistent data in Java/Spring:

Demo

Spring boot 3 with hibernate 6, Docker MariaDB and YAML file configuration.


Technology

  • Spring Boot 3.0.0
  • Hibernate 6
  • Java 17
  • Docker
  • Maven 
  • IntelliJ IDEA

Project Structure






















Configuration Spring Boot project 


pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.henry</groupId>
<artifactId>spring3-hibernate6</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring3-hibernate6</name>
<description>Spring boot 3 with hibernate 6 configuration</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.5.Final</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

application.yml


server:
port: 9000
servlet:
context-path: /
spring:
datasource:
url: jdbc:mariadb://localhost:3306/test1
username: root
password: mypass
driver-class-name: org.mariadb.jdbc.Driver
jpa:
database-platform: org.hibernate.dialect.MySQL5Dialect
show-sql: true

Model

package com.henry.model;

import jakarta.persistence.*;
import lombok.*;


@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;

}

Repository


  • UserRepositoryCustom
package com.henry.repository;

public interface UserRepositoryCustom {

public Integer getSum(int a, int b);
}
  • UserRepository
package com.henry.repository;

import com.henry.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User,Long>, UserRepositoryCustom {

Optional<User> findByFirstName(String firstName);

}

  • UserRepositoryCustomImpl
package com.henry.repository.impl;

import com.henry.repository.UserRepositoryCustom;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.hibernate.Session;
import org.hibernate.jdbc.ReturningWork;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;

public class UserRepositoryCustomImpl implements UserRepositoryCustom {

@PersistenceContext
private EntityManager entityManager;

@Override
public Integer getSum(int a, int b) {

Session session = entityManager.unwrap(Session.class);

int result = session.doReturningWork(new ReturningWork<Integer>() {
@Override
public Integer execute(Connection connection) throws SQLException {
CallableStatement call = connection.prepareCall("{ ? = call get_sum(?,?) }");
call.registerOutParameter(1, Types.INTEGER); // or whatever it is
call.setInt(2, a);
call.setInt(3, b);
call.execute();
return call.getInt(1); // propagate this back to enclosing class
}
});

return result;
}
}

Service

  • UserService
package com.henry.service;

import com.henry.model.User;

import java.util.List;

public interface UserService {
User save(User user);

List<User> findAll();

Integer getSum(int a, int b);
}

  • UserServiceImpl
package com.henry.service.impl;

import com.henry.model.User;
import com.henry.repository.UserRepository;
import com.henry.service.UserService;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

private final UserRepository userRepository;

public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public User save(User user) {
return userRepository.save(user);
}

@Override
public List<User> findAll() {
return userRepository.findAll();
}

@Override
public Integer getSum(int a, int b) {
return userRepository.getSum(a,b);
}
}


Controller

  • UserController
package com.henry.controller;

import com.henry.model.User;
import com.henry.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@GetMapping("/hello")
public String helloWorld() {

return """
Hello World,
multi-line,
text block.
""";
}

@GetMapping
public List<User> findAll() {
return userService.findAll();
}

@GetMapping("/sum/{a}/{b}")
public Integer getSum(@PathVariable int a, @PathVariable int b) {
return userService.getSum(a, b);
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public User addUser(@RequestBody User user) {
return userService.save(user);
}

}


Test Class


package com.henry;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.henry.model.User;
import com.henry.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@WebMvcTest
public class UserControllerTests {

@Autowired
private MockMvc mockMvc;

@MockBean
private UserService userService;

@Autowired
private ObjectMapper objectMapper;

@Test
public void givenUserObject_whenCreateUser_thenReturnSavedUser() throws Exception{

// given - precondition or setup
User user = User.builder()
.firstName("Henry")
.lastName("Xiloj")
.build();
given(userService.save(any(User.class)))
.willAnswer((invocation)-> invocation.getArgument(0));

// when - action or behaviour that we are going test
ResultActions response = mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)));

// then - verify the result or output using assert statements
response.andDo(print()).
andExpect(status().isCreated())
.andExpect(jsonPath("$.firstName",
is(user.getFirstName())))
.andExpect(jsonPath("$.lastName",
is(user.getLastName())));

}

// JUnit test for Get All users REST API
@Test
public void givenListOfUsers_whenGetAllUsers_thenReturnUsersList() throws Exception{
// given - precondition or setup
List<User> listOfUsers = new ArrayList<>();
listOfUsers.add(User.builder().firstName("User1").lastName("User1").build());
listOfUsers.add(User.builder().firstName("User2").lastName("User2").build());
given(userService.findAll()).willReturn(listOfUsers);

// when - action or the behaviour that we are going test
ResultActions response = mockMvc.perform(get("/api/users"));

// then - verify the output
response.andExpect(status().isOk())
.andDo(print())
.andExpect(jsonPath("$.size()",
is(listOfUsers.size())));

}

@Test
public void givenEmployeeId_whenGetUsersFunSum_thenReturnUsersObject() throws Exception{
// given - precondition or setup
given(userService.getSum(1,2)).willReturn(3);

// when - action or the behaviour that we are going test
ResultActions response = mockMvc.perform(get("/api/users/sum/{a}/{b}", 1,2));

// then - verify the output
ResultActions resultActions = response.andExpect(status().isOk())
.andDo(print());


}
}


Downloading and installing MariaDB


docker run --name mariadbtest -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mypass -d mariadb/server:10.3

sudo docker exec -it mariadbtest /bin/bash

mysql -u root -p

create database test1;

Script


DROP TABLE IF EXISTS users;
CREATE TABLE users (id bigint primary key, first_name varchar(128), last_name varchar(128));

DROP FUNCTION IF EXISTS get_sum;

DELIMITER //

CREATE function get_sum (a INT,
                        b INT)
returns INT DETERMINISTIC
begin
  DECLARE total_value INT;

  SET total_value = a + b;

  RETURN total_value;
end;  //

DELIMITER ;


Run & Test



Run Spring Boot application with command: mvn test -Dtest=UserControllerTests. by console, IntelliJ etc.

[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.798 s - in com.henry.UserControllerTests
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  5.670 s
[INFO] Finished at: 2022-11-20T12:34:18-06:00
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0




Source Code


Here on GitHub.




References.

https://spring.io/blog/2022/05/24/preparing-for-spring-boot-3-0
https://hibernate.org/orm/releases/6.0/
https://jakarta.ee/specifications/persistence/
https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html
https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
https://docs.oracle.com/en/java/javase/17/
https://stackoverflow.com/questions/14621495/what-is-the-difference-between-an-spring-entity-manager-and-spring-data-reposito
https://www.javaguides.net/2022/03/spring-boot-unit-testing-crud-rest-api-with-junit-and-mockito.html



























Wednesday, October 26, 2022

Quarkus Cassandra client CRUD

Quarkus A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards.

Apache Cassandra is an open source NoSQL distributed database trusted by thousands of companies for scalability and high availability without compromising performance. Linear scalability and proven fault-tolerance on commodity hardware or cloud infrastructure make it the perfect platform for mission-critical data.


CREATING A QUARKUS APPLICATION












Integration Quarkus  with Cassandra.

  • Configuration Quarkus and Cassandra.
  • Define Datas models, Repository and Services.
  • Quarkus Resource.

Quarkus Rest  CRUD API 

MethodsUrls
GET/products
GET/products/{id}
POST/products
PUT/products/{id}
DELETE/products

Technology

  • Java 17
  • Quarkus 2.13.3.Final
  • Cassandra 4.0.7 
  • Maven 
  • Postman 
  • IntelliJ IDEA 
  • Docker

Project Structure


Configuration  Quarkus Spring Data PostgreSQL



pom.xml


<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.henry</groupId>
<artifactId>quarkus-cassandra-client</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>2.13.3.Final</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.0.0-M7</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-cassandra-bom</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.quarkus/quarkus-resteasy-reactive-jackson -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.datastax.oss.quarkus</groupId>
<artifactId>cassandra-quarkus-client</artifactId>
</dependency>

<dependency>
<groupId>com.datastax.oss</groupId>
<artifactId>java-driver-mapper-processor</artifactId>
<version>4.15.0</version>
</dependency>

<dependency>
<groupId>com.datastax.oss</groupId>
<artifactId>java-driver-mapper-runtime</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<source>17</source> <!-- (or higher) -->
<target>17</target> <!-- (or higher) -->
<annotationProcessorPaths>
<path>
<groupId>com.datastax.oss</groupId>
<artifactId>java-driver-mapper-processor</artifactId>
<version>4.15.0</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>

application.properties: We can configure multiple keyspace.


quarkus.http.port=9000
quarkus.cassandra.contact-points=localhost:9042
quarkus.cassandra.local-datacenter=datacenter1
keyspace.one=inventory


Data class model


package org.henry.model;

import com.datastax.oss.driver.api.mapper.annotations.Entity;
import com.datastax.oss.driver.api.mapper.annotations.PartitionKey;

import java.util.UUID;

@Entity
public class Product {

@PartitionKey private UUID id;
private String description;

public Product() {}

public Product(UUID id, String description) {
this.id = id;
this.description = description;
}

public UUID getId() { return id; }

public void setId(UUID id) { this.id = id; }

public String getDescription() { return description; }

public void setDescription(String description) { this.description = description; }
}

Repository Interface


package org.henry.repository;

import com.datastax.oss.driver.api.core.PagingIterable;
import com.datastax.oss.driver.api.mapper.annotations.*;
import org.henry.model.Product;

import java.util.UUID;

@Dao
public interface ProductDao {
@Select
Product findById(UUID productId);

@Select
PagingIterable<Product> findAll();

@Update
void update(Product product);

@Insert
void save(Product product);

@Delete
void delete(Product product);
}

Mapper interface

By official documentation: Mapper annotations are used to mark the interface, and indicate what kind of request each method should execute.  

Generating the code


The mapper uses annotation processing: it hooks into the Java compiler to analyze annotations, and generate additional classes that implement the mapping logic. Annotation processing is a common technique in modern frameworks, and is generally well supported by build tools and IDEs; this is covered in detail in Configuring the annotation processor.


Pay attention to the compiler output: the mapper processor will sometimes generate warnings if annotations are used incorrectly.


Using the generated code


One of the classes generated during annotation processing is InventoryMapperBuilder


package org.henry.configuration;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.henry.mapper.InventoryMapper;
import org.henry.mapper.InventoryMapperBuilder;
import org.henry.repository.ProductDao;

import javax.inject.Singleton;

@Singleton
public class Config {

/**
* Call here multiple keyspace with respective DAO
* */
@ConfigProperty(name = "keyspace.one")
String keyspace1;

public CqlSession session(){
CqlSession session = CqlSession.builder().build();
return session;
}

public ProductDao productDao(){
InventoryMapper inventoryMapper = new InventoryMapperBuilder(session()).build();
ProductDao dao = inventoryMapper.productDao(CqlIdentifier.fromCql(keyspace1));
return dao;
}
}

package org.henry.mapper;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.mapper.annotations.DaoFactory;
import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace;
import com.datastax.oss.driver.api.mapper.annotations.Mapper;
import org.henry.repository.ProductDao;

@Mapper
public interface InventoryMapper {
@DaoFactory
ProductDao productDao(@DaoKeyspace CqlIdentifier keyspace);
}


Service Class


package org.henry.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.henry.configuration.Config;
import org.henry.model.Product;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

@ApplicationScoped
public class ProductService {

public static JsonMapper mapper = new JsonMapper();

@Inject
Config config;

public void save(Product product) throws JsonProcessingException {
config.productDao().save(new Product(UUID.randomUUID(), product.getDescription()));
}

public void update(Product product, UUID productId) {
Optional<Product> res = Optional.ofNullable(config.productDao().findById(productId));
if (res.isPresent()) {
res.get().setDescription(product.getDescription());
config.productDao().update(res.get());
}
}

public Product findById(UUID productId) {
return config.productDao().findById(productId);
}

public List<Product> getAll() {
return config.productDao().findAll().all();
}

public void delete(Product product) {
config.productDao().delete(product);
}

}


Quarkus Rest APIs Resource


package org.henry.resource;


import com.fasterxml.jackson.core.JsonProcessingException;
import org.henry.model.Product;
import org.henry.service.ProductService;

import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.UUID;

@Path("/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {

@Inject
ProductService productService;

@POST
public void save(Product product) throws JsonProcessingException {
productService.save(product);
}

@PUT
@Path("{productId}")
public void update(Product product, UUID productId) {
productService.update(product,productId);
}

@GET
@Path("{productId}")
public Product findById(UUID productId) {
return productService.findById(productId);
}

@GET
public List<Product> getAll() {
return productService.getAll();
}

@DELETE
public void delete(Product product) {
productService.delete(product);
}


}


Set up Cassandra


docker pull cassandra

 docker run --name cassandra -p 127.0.0.1:9042:9042 -p 127.0.0.1:9160:9160   -d cassandra

 docker exec -it cassandra /bin/bash

 #cqlsh






Check datacenter name:


cqlsh> use system;
cqlsh:system> select data_center from local;

 data_center
-------------
 datacenter1

(1 rows)
cqlsh:system>


Created keyspaces: inventory.

CREATE KEYSPACE inventory WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}; CREATE TABLE inventory.product(id uuid PRIMARY KEY, description text);


Run & Test


Run Quarkus application with next maven command : 
./mvnw compile quarkus:dev or ./mvnw test (Run test class) by console or IntelliJ.

POST.
http://localhost:9000/products

















PUT.
http://localhost:9000/products/{id}



















DELETE.
http://localhost:9000/products


















GET.
http://localhost:9000/products



















GET.
http://localhost:9000/products/{id}



















Source Code


Here on Github.





References.

https://quarkus.io/guides/cassandra
https://quarkus.io/guides/cdi-reference
https://quarkus.io/guides/config
https://docs.datastax.com/en/developer/java-driver/4.2/manual/mapper/
https://docs.datastax.com/en/developer/java-driver/4.2/manual/mapper/config/
https://docs.datastax.com/en/developer/java-driver/3.0/
https://cassandra.apache.org/_/index.html























Spring boot 3 with Hibernate 6

Spring Boot 3.0 Spring boot 3  Features : Spring Boot 3.0 will require Java 17 Jakarta EE 9 a new top-level jakarta package, replacing EE 8’...