javacassandradatastax-java-driveruser-defined-typesspring-data-cassandra

Cannot write to table with UDT, getting "Cannot resolve UserDefinedType for [devices]"


These are the dependencies I have installed in my spring project

//cassandra
implementation 'org.springframework.data:spring-data-cassandra:3.1.2'
implementation 'io.projectreactor:reactor-core'
implementation 'com.datastax.cassandra:cassandra-driver-core:3.10.2'
implementation 'com.datastax.oss:java-driver-mapper-runtime:4.13.0'
implementation 'com.datastax.oss:java-driver-core:4.13.0'
implementation 'com.datastax.cassandra:cassandra-driver-mapping:3.6.0'
java --version
openjdk 11.0.18 2023-01-17 LTS
OpenJDK Runtime Environment Corretto-11.0.18.10.1 (build 11.0.18+10-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.18.10.1 (build 11.0.18+10-LTS, mixed mode)

For my entity class

import com.datastax.driver.core.DataType;
import com.xxx.pai.gm.ws.core.model.Widgets;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.cassandra.core.cql.Ordering;
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
import org.springframework.data.cassandra.core.mapping.CassandraType;
import org.springframework.data.cassandra.core.mapping.Column;
import org.springframework.data.cassandra.core.mapping.Frozen;
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.core.mapping.Table;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Table("shortcut_widgets")
public class ShortcutWidgetEntity {
    @PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED, ordering = Ordering.ASCENDING)
    @Column("customerId")
    private String customerId;

    @Frozen
    @Column("device_list")
    @CassandraType(type = CassandraType.Name.LIST, userTypeName = "device_list", typeArguments = CassandraType.Name.UDT)
    List<Devices> deviceList;
}

And UDT

import com.datastax.driver.mapping.annotations.Field;
import com.datastax.driver.mapping.annotations.UDT;
import com.xxx.pai.gm.ws.core.controller.request.ShortcutWidgets;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.cassandra.core.mapping.UserDefinedType;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@UserDefinedType("device_list")
public class Devices {
    private Long bannerId;
    private String uniqueId;
    private String type;
    private String imageUrl;
    private String darkImageUrl;
    private String url;
    private String title;
    private Integer metaDataSourceId;
}

I am unable to write data into the tables, and UDT, which are as follows:

create TYPE device_list( bannerId bigint, uniqueId text, type text, 
        imageUrl text, darkImageUrl text, url text, title text, 
        metaDataSourceId int );

CREATE TABLE shortcut_widgets (
    customerId text PRIMARY KEY,
    device_list frozen<list<device_list>>
);

The repository where I am trying to write data is

@Repository
public class ShortcutWidgetsRepository {
    private static final String KEYSPACE_NAME = "shortcuts";
    private final MeterRegistry meterRegistry;
    private final ReactiveCassandraTemplate template; 

    public ShortcutWidgetsRepository(
    @Qualifier("cassandraTemplate1") ReactiveCassandraTemplate template,
    MeterRegistry meterRegistry) {
        this.template = template;
        this.meterRegistry = meterRegistry;
    }

    public Mono<ShortcutWidgetEntity> saveWidget(ShortcutWidgetEntity shortcutWidgetEntity) {
        return template.insert(shortcutWidgetEntity);
    }
}

The error I am facing is "Cannot resolve UserDefinedType for \[device_list\]"

I have tried changing versions of dependencies, tried following this blog https://www.linkedin.com/pulse/guide-cassandra-object-mapper-spring-nikunj-pandya/, but there were issues injecting Session bean using the dependencies I have now. Can anyone help me, How to solve this error?


Solution

  • I have solved this issue by using SimpleUserTypeResolver. You can see it here

    @Primary
      @Bean
      public CassandraMappingContext mappingContext() {
        CassandraMappingContext mappingContext = new CassandraMappingContext();
        mappingContext.setUserTypeResolver(
            new SimpleUserTypeResolver(Objects.requireNonNull(cassandraSession().getObject())));
        return mappingContext;
      }
    
      @Bean
      @Primary
      public CassandraConverter converter() {
        return new MappingCassandraConverter(mappingContext());
      }
    
      @Bean
      @Override
      public ReactiveCassandraTemplate reactiveCassandraTemplate() {
        return new ReactiveCassandraTemplate(reactiveCassandraSession(), converter());
      }