Apache Cassandra With Java: Introduction to UDT
The Apache Cassandra User-defined types (UDTs) might be beneficial to the Java programming model. In this post, we'll explore how to take advantage of it.
Join the DZone community and get the full member experience.
Join For FreeApache Cassandra User-defined types (UDTs) can attach multiple data fields, each named and typed, to a single column. The fields used to create a UDT may be any valid data type, including collections and other existing UDTs. Once created, UDTs may be used to define a column in a table. In this post, we'll explore how to use Cassandra's feature with Java.
In simple words, UDT is a type where you can get as much information as you can; for example, give e-commerce in the column family product, there is the option to create a UDT Money where the data are the currency with the value.
CREATE TYPE commerce.money (
currency text,
amount decimal
);
It fits perfectly in the OOP model; specifically, we need to create a type or a DDD aggregate in the entity model.
Before, go further in detail on Apache Cassandra UDT, it essential to highlight that Cassandra is not a relational database. Thus, denormalization is your friend, and Cassandra does not have the support to left join.
The model should follow the query-driven modeling instead of the normalization.
This tutorial will create a Company
entity to explore the UDT feature. This Company entity has five fields:
- The company's name.
- The company's cost, where it will create a Money type.
- The languages that the company speaks.
- The company's contact in the social media.
- The headquarter, a set of a Headquarter with city and country.
Cassandra is not schemeless. Thus, it is natural to create the structure before using this. So, the script below is a CQL to create the types, money
and headquarter
, then the Company
as column family.
x
CREATE TYPE IF NOT EXISTS developers.money (currency text, amount decimal);
CREATE TYPE IF NOT EXISTS developers.headquarter (city text, country text);
CREATE COLUMNFAMILY IF NOT EXISTS developers.Company (name text PRIMARY KEY, cost FROZEN<money>, languages set<text>, contacts map<text, text>, headquarters set<FROZEN<headquarter>>);
In the Cassandra integration with Java, this tutorial uses Jakarta NoSQL once it is a standard to Jakarta EE specification.
The UDT creation isn't different from a normal entity; therefore, it will use the Entity and Column annotations, similar to JPA.
x
import jakarta.nosql.mapping.Column;
import jakarta.nosql.mapping.Entity;
import java.util.Objects;
public class Headquarter {
private String city;
private String country;
//...
}
The Money
types have two fields one represents the currency and the amount. Java has a specific kind to describes coin, the Currency class. Once Cassandra does not support it, we'll create a convert to move this class data to String.
xxxxxxxxxx
public class Money {
MoneyConverter.class) (
private Currency currency;
private BigDecimal amount;
//...
}
public class MoneyConverter implements AttributeConverter<Currency, String> {
public String convertToDatabaseColumn(Currency attribute) {
return attribute.getCurrencyCode();
}
public Currency convertToEntityAttribute(String dbData) {
return Currency.getAvailableCurrencies().stream()
.filter(c -> dbData.equals(c.getCurrencyCode()))
.findAny().orElse(null);
}
}
The types of models are ready to use in the Company class. This entity will have trivial annotations such as Entity
, Id
, and Column
. Furthermore, there is an annotation to identify whose that entity is a UDT. The UDT annotation requires an attribute to define the type name.
xxxxxxxxxx
public class Company {
"name") (
private String name;
"money") (
private Money cost;
private Set<String> languages;
private Map<String, String> contacts;
"headquarter") (
private Set<Headquarter> headquarters;
//...
}
The Company
class is ready to use. The next step is storage and retrieves information using the CassandraTemplate
. As with any service, make sure that there is a Cassandra instance running. The easiest way is with docker with the command below:
xxxxxxxxxx
docker run -d --name casandra-instance -p 9042:9042 cassandra
x
public class App5 {
public static void main(String[] args) {
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
CassandraTemplate template = container.select(CassandraTemplate.class).get();
Currency currency = Currency.getInstance(Locale.US);
Company company = Company.builder()
.withName("SouJava")
.addLanguage("Portuguese")
.addLanguage("English")
.addLanguage("Italian")
.addLanguage("Spanish")
.addHeadquarter(Headquarter.of("Salvador", "Brazil"))
.addHeadquarter(Headquarter.of("Sao Paulo", "Brazil"))
.addHeadquarter(Headquarter.of("Leiria", "Portugal"))
.add("twitter", "otaviojava")
.add("linkedin", "otaviojava")
.withCost(Money.of(currency, BigDecimal.valueOf(10_000)))
.build();
template.insert(company);
Optional<Company> soujava = template.find(Company.class, "SouJava");
System.out.println("the company is " + soujava);
}
}
private App5() {
}
}
In this tutorial, we talked about Cassandra's UDT feature and how to use it as a collection or a single field with Jakarta NoSQL.
Source: https://github.com/JNOSQL/demos/tree/master/artemis-demo-java-se/cassandra
Opinions expressed by DZone contributors are their own.
Comments