'How to save collection of user defined type to ScyllaDB with Spring Data Cassandra?

When I try to save entity with a list or set of user defined type, I get error:

Failed to convert from type [java.util.ImmutableCollections$Set12<?>] to type [com.datastax.oss.driver.api.core.data.UdtValue] for value '[scrubbed.entity.Article$AttachmentInfo@3337c2b5]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [scrubbed.entity.Article$AttachmentInfo] to type [com.datastax.oss.driver.api.core.data.UdtValue]]

That's the definition that is in ScyllaDB database:

CREATE TYPE IF NOT EXISTS attachment_info (
  id        UUID,
  fileName  TEXT,
  mimeType  TEXT,
  sizeBytes BIGINT
);

CREATE TABLE IF NOT EXISTS articles
(
  id          UUID,
  attachments SET<frozen<attachment_info>>,
  PRIMARY KEY (id)
);

Entity in Java:

@Getter
@Setter
@Table("articles")
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class Article {

  @PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
  private UUID id;

  @Column("attachments")
  @CassandraType(type = CassandraType.Name.UDT, userTypeName = "attachment_info")
  private Set<AttachmentInfo> attachments = new HashSet<>();

  @Getter
  @Setter
  @NoArgsConstructor
  @AllArgsConstructor
  @UserDefinedType("attachment_info")
  public static class AttachmentInfo {
    private UUID id;
    private String fileName;
    private String mimeType;
    private Long sizeBytes;
  }
}

And saving to database:

var metadata = new Article.AttachmentInfo();
metadata.setFileName("Filename");
metadata.setId(UUID.randomUUID());
metadata.setMimeType("image/png");
metadata.setSizeBytes(12345L);

var article = new Article();
article.setId(UUID.randomUUID());
article.setAttachments(Set.of(metadata));
articleRepository.insert(article);

Using version 3.2.0 of spring-data-cassandra



Solution 1:[1]

I'm not a Spring expert (just a Scylla expert ;-)), so please forgive me if my answer doesn't work.

It seems to me that the annotation

@Column("attachments")
@CassandraType(type = CassandraType.Name.UDT, userTypeName = "attachment_info")
  private Set<AttachmentInfo> attachments = new HashSet<>();

Is wrong because it tells spring-data-cassandra that the "attachments" column is a UDT, while in fact it isn't - it's a set (of UDTs).

I think that the correct annotation for a set of UDTs would be something like:

@CassandraType(type = DataType.Name.SET, typeArguments = DataType.Name.UDT)

But I'm not sure (I couldn't find an example in documentation) where to put the userTypeName. If I understand the documentation correctly, you don't need the that userTypeName explicitly because you annotated the AttachmentInfo class with a UserDefinedType annotation saying that its scylla name is "attachment_info" and that should hopefully be enough.

Moreover, according to some documentation I read, you may not need the CassandraType annotation on attachements at all, because spring-data-cassandra understands Set<AttachmentInfo> because it knows the primitive type Set, and you already annotated AttachmentInfo as a UDT.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nadav Har'El