Summary
I have two Java classes, each of which has a corresponding table and UDT in Cassandra. For these two classes, I want to be able to access data from the other class in a single query, so I have two corresponding tables and each of these tables has a column referencing the other class's UDT. How do I implement this using the Java driver?
DSE v.6.8
Java driver v.4.6
This seems to me like it should be a fairly common use case, but I'm having a hard time finding a solution online, at least for Java Driver v.4.6. Or it is just that I'm thinking about this totally wrong, in which case please let me know the best practice for a solution to this.
Either way, I'm providing more details below in case it provides clarity regarding what my question is.
My Objective
I have two java classes (Podcast and Episode). For these two classes, I want to be able to access data from the other class in a single query. Podcasts have many episodes, and episodes has a single podcast.
For example, it looks something like:
USE podcast_analysis_tool; CREATE TABLE podcasts_by_language ( language text, primary_genre text, feed_url text, author text, episodes list<frozen<episode>>, PRIMARY KEY (language, primary_genre, feed_url) ); CREATE TYPE podcast ( language text, primary_genre text, feed_url text, author text, episodes list<frozen<episode>> ); CREATE TABLE episodes_by_order_in_podcast ( podcast_api text, podcast_api_id text, order_num int, keywords set<text>, podcast frozen<podcast>, PRIMARY KEY ((podcast_api, podcast_api_id), order_num) ); CREATE TYPE episode ( podcast_api text, podcast_api_id text, order_num int, keywords set<text>, podcast frozen<podcast> );
I am using the Java driver mapper and I think I have it mostly setup, except for in regard to these UDTs. When I try to instantiate the dao, I get the following error:
java.lang.IllegalArgumentException: The CQL ks.table: podcast_analysis_tool.podcasts_by_language defined in the entity class: dataClasses.Podcast declares type mappings that are not supported by the codec registry: Field: episodes, Entity Type: dataClasses.Episode, CQL type: UDT(podcast_analysis_tool.episode) at com.datastax.oss.driver.internal.mapper.entity.EntityHelperBase.throwMissingTypesIfNotEmpty(EntityHelperBase.java:196) at com.datastax.oss.driver.internal.mapper.entity.EntityHelperBase.throwMissingTableTypesIfNotEmpty(EntityHelperBase.java:185) at dataClasses.PodcastHelper__MapperGenerated.validateEntityFields(PodcastHelper__MapperGenerated.java:517) at cassandraHelpers.PodcastDaoImpl__MapperGenerated.initAsync(PodcastDaoImpl__MapperGenerated.java:92) at cassandraHelpers.PodcastDaoImpl__MapperGenerated.init(PodcastDaoImpl__MapperGenerated.java:132) at cassandraHelpers.InventoryMapperImpl__MapperGenerated.lambda$1(InventoryMapperImpl__MapperGenerated.java:39) at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) at cassandraHelpers.InventoryMapperImpl__MapperGenerated.podcastDao(InventoryMapperImpl__MapperGenerated.java:39) at dataClasses.Podcast.getDao(Podcast.java:125) at Main.processOnePodcast(Main.java:204) at Main.main(Main.java:22)
Potential Solutions
1) Set up each class as both a table and a UDT
The way it is currently, my Podcast class and Episode class are both labeled as tables only. I.e., for Episodes:
@Entity @CqlName("episodes_by_order_in_podcast") public class Episode { ...
The same fields exist on the table that exist on the UDT. This being the case, can I add another annotation to the same class, so it is recognized as both a table and a type? It seems like this is a potential solution, when just reading the docs on dao schema validation. Maybe something like:
@SchemaHint(targetElement = UDT)
@SchemaHint(targetElement = TABLE)
public class Episode {
...
Seems a little messy, but is this possible?
2) Separate java classes for the UDT and the table
If each class can only be either a table or a UDT, should I just have one base class and then maybe two child classes, one for the table and one for the UDT?
3) Codec
Or, could I just solve this whole thing by leaving my current class alone, but adding a custom codec to map my Episode/Podcast classes to a UDT?
If so, how do I do this? Do I need to write out a full custom codec for each one? I found this solution that seems quite simple and intuitive, but it refers to a class MappingManager
that does not seem to exist in 4.6 as far as I can tell.
Java driver v.2.1 seems like it had a very straightforward way of inferring the UDT from the class automatically, but I'm having a hard time finding out how to do this in v.4.6.