Does Spring-data-Cassandra 1.3.2.RELEASE support UDT annotations?

Is @UDT ( http://docs.datastax.com/en/developer/java-driver/2.1/java-driver/reference/mappingUdts.html ) supported by Spring-data-Cassandra 1.3.2.RELEASE? If not, how can I add a workaround for this

thank

+1


source to share


2 answers


See here for more details: https://jira.spring.io/browse/DATACASS-172

I ran into the same issue and it looks like it is not (debugging process shows me that spring cassandra data validation for @Table, @Persistent or @PrimaryKeyClass Only annotation and exception for exception otherwise

<P -> The init method call failed; Nested Exception - org.springframework.data.cassandra.mapping.VerifierMappingExceptions: Cassandra objects must have @Table, @Persistent or @PrimaryKeyClass Annotation

But I found a solution. I figured out an approach that allows me to manipulate objects that include UDTs and those that don't. In my application, I am using spring cassandra data project together using datastax direct kernel driver. Repositories that do not contain an object with a UDT use the spring cassanta data approach, and objects that include a UDT use custom repositories. The custom repos use the datastax mapper and they work correctly with the UDT (they are in a separate package, see notes below for why this is necessary):

package com.fyb.cassandra.custom.repositories.impl;

import java.util.List;
import java.util.UUID;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;

import com.datastax.driver.core.ResultSet;
import com.datastax.driver.mapping.Mapper;
import com.datastax.driver.mapping.MappingManager;
import com.datastax.driver.mapping.Result;
import com.google.common.collect.Lists;
import com.fyb.cassandra.custom.repositories.AccountDeviceRepository;
import com.fyb.cassandra.dto.AccountDevice;

public class AccountDeviceRepositoryImpl implements AccountDeviceRepository {

    @Autowired
    public CassandraSessionFactoryBean session;

    private Mapper<AccountDevice> mapper;

    @PostConstruct
    void initialize() {
        mapper = new MappingManager(session.getObject()).mapper(AccountDevice.class);
    }

    @Override
    public List<AccountDevice> findAll() {
        return fetchByQuery("SELECT * FROM account_devices");
    }

    @Override
    public void save(AccountDevice accountDevice) {
        mapper.save(accountDevice);
    }

    @Override
    public void deleteByConditions(UUID accountId, UUID systemId, UUID deviceId) {
        final String query = "DELETE FROM account_devices where account_id =" + accountId + " AND system_id=" + systemId
                + " AND device_id=" + deviceId;
        session.getObject().execute(query);
    }

    @Override
    public List<AccountDevice> findByAccountId(UUID accountId) {
        final String query = "SELECT * FROM account_devices where account_id=" + accountId;
        return fetchByQuery(query);
    }

    /*
     * Take any valid CQL query and try to map result set to the given list of appropriates <T> types.
     */
    private List<AccountDevice> fetchByQuery(String query) {
        ResultSet results = session.getObject().execute(query);
        Result<AccountDevice> accountsDevices = mapper.map(results);
        List<AccountDevice> result = Lists.newArrayList();
        for (AccountDevice accountsDevice : accountsDevices) {
            result.add(accountsDevice);
        }
        return result;
    }
}

      

And the spring data-related repos that are responsible for managing objects that don't include UDT objects look like this:

package com.fyb.cassandra.repositories;

import org.springframework.data.cassandra.repository.CassandraRepository;

import com.fyb.cassandra.dto.AccountUser;
import org.springframework.data.cassandra.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.UUID;

@Repository
public interface AccountUserRepository extends CassandraRepository<AccountUser> {

    @Query("SELECT * FROM account_users WHERE account_id=?0")
    List<AccountUser> findByAccountId(UUID accountId);
}

      

I tested this solution and it works 100%. Also, I added POJOs:

Pojo, which only uses stax data annotation:



package com.fyb.cassandra.dto;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.datastax.driver.mapping.annotations.ClusteringColumn;
import com.datastax.driver.mapping.annotations.Column;
import com.datastax.driver.mapping.annotations.Frozen;
import com.datastax.driver.mapping.annotations.FrozenValue;
import com.datastax.driver.mapping.annotations.PartitionKey;
import com.datastax.driver.mapping.annotations.Table;

@Table(name = "account_systems")
public class AccountSystem {

    @PartitionKey
    @Column(name = "account_id")
    private java.util.UUID accountId;

    @ClusteringColumn
    @Column(name = "system_id")
    private java.util.UUID systemId;

    @Frozen
    private Location location;

    @FrozenValue
    @Column(name = "user_token")
    private List<UserToken> userToken;

    @Column(name = "product_type_id")
    private int productTypeId;

    @Column(name = "serial_number")
    private String serialNumber;   
}

      

Pojo without using UDT and using only spring cassandra data structure:

package com.fyb.cassandra.dto;

import java.util.Date;
import java.util.UUID;

import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.Table;

@Table(value = "accounts")
public class Account {

    @PrimaryKeyColumn(name = "account_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
    private java.util.UUID accountId;

    @Column(value = "account_name")
    private String accountName;

    @Column(value = "currency")
    private String currency;    
}

      

Please note that the entities below use different annotations:

@PrimaryKeyColumn(name = "account_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)and @PartitionKey
@ClusteringColumn and @PrimaryKeyColumn(name = "area_parent_id", ordinal = 2, type = PrimaryKeyType.CLUSTERED)

      

At first glance, this is inconvenient, but it allows you to work with objects that include UDTs, and this is not the case.

One important note. The two repos (which use the UDT and do not need to be in different packages) call spring config, which looks for base packages with repos:

@Configuration
@EnableCassandraRepositories(basePackages = {
        "com.fyb.cassandra.repositories" })
public class CassandraConfig {
..........
}

      

+3


source


The custom data type is now supported by Spring Data Cassandra. Latest version 1.5.0.RELEASE uses Cassandra Data stax driver 3.1.3 and therefore works now. Follow the instructions below to get it working.

How to use UserDefinedType (UDT) function with Spring Data Cassandra:

  • We need to use the latest Spring Cassandra databank (1.5.0.RELEASE)

    group: 'org.springframework.data', name: 'spring-data-cassandra', version: '1.5.0.RELEASE'

  • Make sure it uses below version of the flag:

    datastax.cassandra.driver.version = 3.1.3 spring.data.cassandra.version = 1.5.0.RELEASE spring.data.commons.version = 1.13.0.RELEASE spring.cql.version = 1.5.0.RELEASE

  • Create a custom type in Cassandra: the type name must be the same as defined in the POJO class



Address data type

CREATE TYPE address_type ( 
    id text, 
    address_type text, 
    first_name text, 
    phone text 
);

      

  1. Create a column family with one of the columns as a UDT in Cassandra:

    Employee table:

    CREATE TABLE employee (employee_id uuid, employee_name text, address frozen, primary key (employee_id, employee_name));

  2. In the domain class define a field annotated with -CassandraType and DataType must be UDT:

    @Table ("employee") public class Employee {- from fields - @CassandraType (type = DataType.Name.UDT, userTypeName = "address_type") private address address; }

  3. Create a domain class for a user-defined type: We need to make sure that the column name in the user-defined type schema must be the same as the field name in the domain class.

    @UserDefinedType ("address_type") public class Address {@CassandraType (type = DataType.Name.TEXT) private String id; @CassandraType (type = DataType.Name.TEXT) private String address_type; }

  4. In your Cassandra config, change this:

    @Bean public CassandraMappingContext mappingContext () throws Exception {BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext (); mappingContext.setUserTypeResolver (new SimpleUserTypeResolver (cluster (). getObject (), cassandraKeyspace)); return mappingContext; }

  5. A custom type must have the same name throughout. eg,

    • @UserDefinedType ("address_type")
    • @CassandraType (type = DataType.Name.UDT, userTypeName = "address_type")
    • CREATE TYPE address_type
+1


source







All Articles