Using user-defined types (UDT) with Apache Cassandra in Spring Boot 3.x
Tags: java, kotlin, cassandra, spring
Published: 2023-02-11 07:24:02

---
title: Using user-defined types (UDT) with Apache Cassandra in Spring Boot 3.x
published: true
date: 2023-01-27 11:57:22 UTC
tags: java,kotlin,cassandra,spring
canonical_url: https://blog.dripto.xyz/using-user-defined-types-udt-with-apache-cassandra-in-spring-boot-3x
cover_image: https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/jK5h-gZdAvc/upload/9f2c0a5fe8cddbf6621768185acb5186.jpeg?w=1600&h=840&fit=crop&crop=entropy&auto=compress,format&format=webp
---

Apache Cassandra is a highly scalable and distributed NoSQL database that is well-suited for handling large amounts of data. One of the powerful features of Cassandra is the ability to use user-defined types (UDT) to model complex data structures. In this blog post, we will learn how to use UDTs with Spring Boot 3.x to interact with a Cassandra database.

## Creating the data model in cassandra

First, let's create a simple UDT in Cassandra. You can do this by running the following command in the Cassandra shell (imagining `test` being the cassandra keyspace):

```sql
CREATE TYPE test.address (
    street text,
    city text,
    zip text
);

```

This creates a UDT called "address" with three fields: street, city, and zip.

Next, we will create a table that uses this UDT. For example, we can create a table called "users" with the following command:

```sql
CREATE TABLE test.users (
    id int PRIMARY KEY,
    name text,
    address frozen<address>
);

```

This table has three columns: id, name, and address. The "address" column is the UDT type here. When defining a user-defined type column, it is best practice to utilize the `frozen` keyword. This ensures that the user-defined type value cannot be partially updated, but must be completely overwritten. By using the 'frozen' keyword, Cassandra treats the value of the user-defined type as a single, immutable block of data, similar to a binary large object (BLOB).

## Setup spring boot 3.x application

Now that we have our UDT and table set up, we can start using them with Spring Boot. Head to `start.spring.io` to create a spring boot 3.x project with cassandra or add the following dependency to the existing spring boot projects.

Gradle:

```kotlin
  implementation("org.springframework.boot:spring-boot-starter-data-cassandra")

```

Maven:

```xml
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>

```

We also need to configure the Cassandra connection in our application.yml file:

```yaml
spring:
  data:
    cassandra:
      contact-points: localhost
      port: 9042
      keyspace-name: test

```

## Setup data model in Spring boot application

Once we have the dependency and configuration in place, We also need to create a POJO class that represents our "users" table:

```kotlin
import org.springframework.data.cassandra.core.mapping.PrimaryKey
import org.springframework.data.cassandra.core.mapping.Table

@Table
data class User (
    @PrimaryKey
    val id: Int,
    val name: String,
    /**
     * @CassandraType annotation is not required by default and is redundant. but can be added if requried.
     * @CassandraType(type = CassandraType.Name.UDT, userTypeName = "address")
     */
    val address: Address
)

```

And a POJO class that represents our `address` UDT:

```kotlin
import org.springframework.data.cassandra.core.mapping.UserDefinedType

@UserDefinedType("address")
data class Address (
    val street: String,
    val city: String,
    val zip: String
)

```

we also need to create a Cassandra repository to interact with our `users` table. For example:

```kotlin
import org.springframework.data.cassandra.repository.CassandraRepository

interface UserRepository : CassandraRepository<User, Int>

```

## Use the repository to call Cassandra

With these classes in place, we can now use the UserRepository to perform CRUD operations on the `users` table. For example, we can save a new user with:

```kotlin
@Configuration
class App {
    @Bean
    fun runner(userRepository: UserRepository) = ApplicationRunner{
        val user = User(1, "John Doe", Address("Street name", "Berlin", "12345"))
        userRepository.save(user)
    }
}

```

## Conclusion

We hope this tutorial gave you a good idea on how to use user-defined types (UDT) with Apache Cassandra in Spring Boot 3.x. We've shown you how to create a UDT and table in Cassandra, and how to use them with Spring Boot to perform CRUD operations on the table.

Using UDTs can be a powerful way to model complex data structures in Cassandra, and Spring Boot makes it easy to work with these structures in a Java application. With the right configuration and setup, you can easily start using UDTs in your projects to improve the scalability and performance of your data storage.

Be sure to follow best practices when working with UDTs, such as using frozen types and avoiding unnecessary nesting to minimize the complexity. Remember also to keep in mind that UDTs are not supported in some version of Cassandra and not all the drivers support it.

As always, feel free to leave a comment or reach out if you have any questions or need further help. Happy coding!