1

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?

2 Answers 2

2

I noted that you are using Spring Data Cassandra v3.1.2:

implementation 'org.springframework.data:spring-data-cassandra:3.1.2'

You need to review the dependencies in your code because according to the official Spring Data Reference Documentation and the Maven compile dependencies, spring-data-cassandra v3.1.2 requires Cassandra Java driver 4.0 or later.

Also, your UDT class already uses the @UserDefinedType annotation:

@UserDefinedType("device_list")
public class Devices {
    ...
}

so you should NOT use the @CassandraType annotation in your entity class:

public class ShortcutWidgetEntity {
    ...

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

For what it's worth, Aaron Ploetz has a working example for an eCommerce app with the full source code on GitHub. In it you'll see how he has implemented the mapper for the UDT.

Having said all that, I strongly recommend only using UDTs as a last resort. Wherever possible, you should use native CQL types and model your data in regular columns/rows. Unless you have a very specific need to use UDTs, I suggest modelling your data with something like:

CREATE TABLE widgets_by_customer_id (
    customer_id text,
    device_id text,
    ...
    PRIMARY KEY(customer_id, device_id)
)

With this schema, each customer will have one or more rows of devices. This means that (1) you can page through all the devices, (2) you can retrieve a single device without having to retrieve the whole list collection, and (3) it's a lot easier to update the schema (add/drop columns) in the future. Cheers!

Sign up to request clarification or add additional context in comments.

Comments

0

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());
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.