关于尝试将复合主键与 cassandra 和 spring-data-cassandra 一起使用时的异常

About an exception when trying to use a composite primary key with cassandra and spring-data-cassandra

我正在玩 spring-data 和 cassandra,看看如何编写一个服务,该服务必须在 cassandra 环中存储来自 REST 服务的数据,没问题,但是当我尝试检索时来自 cassandra 的数据,我想使用复合主键,但我遇到了 ClassCastException。

我已经在之前的 in SO a similar problem, but the solution is not working for me. I already saw 中看到过,但这与 spring-data-cassandra 相关,没有 spring-data-rest.

这是@Table 注释 class:

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import java.time.LocalDateTime;
import java.util.Map;
import javax.validation.constraints.NotNull;

@Table(value=AdminUserCassandraTable.tableName)
public class AdminUserCassandraTable {

@org.springframework.data.annotation.Transient
public static final String tableName = "AdminUser";

@PrimaryKey
private AdminUserPK id;

private String tenantId;

private String orgId;

private boolean superAdmin;

@NotNull
private String password;

private String emailAddress;


private Map<String, String> metadata;

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime lastModified;

public AdminUserCassandraTable() {
    this.id = null;
}

@Override public String toString() {
    return "AdminUserCassandraTable{" +
            "id=" + id +
            ", tenantId='" + tenantId + '\'' +
            ", orgId='" + orgId + '\'' +
            ", superAdmin=" + superAdmin +
            ", password='" + password + '\'' +
            ", emailAddress='" + emailAddress + '\'' +
            ", metadata=" + metadata +
            ", createdAt=" + createdAt +
            ", lastModified=" + lastModified +
            '}';
}

...

}

这是 AdminUserPK:

import java.io.Serializable;
import java.util.UUID;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import com.datastax.driver.core.DataType;


@PrimaryKeyClass
public class AdminUserPK implements Serializable{

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

@PrimaryKeyColumn(name = "username", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
@CassandraType(type = DataType.Name.TEXT)
private String username;

// 
public AdminUserPK() {
    this.id = null;
    this.username = null;
}

public AdminUserPK(UUID id, String username) {
    this.id = id;
    this.username = username;
}
...
getters, setters, equals and hashCode methods.
}

这是 AdminUserRepository:

import java.util.Optional;
import java.util.UUID;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.Query;
import org.springframework.data.cassandra.repository.TypedIdCassandraRepository;
import unicon.matthews.admin.AdminUser;
import unicon.matthews.admin.service.AdminUserCassandraTable;
import unicon.matthews.admin.service.AdminUserPK;

public interface AdminUserRepository extends TypedIdCassandraRepository<AdminUserCassandraTable, AdminUserPK> {

**The problem must be here, with this @Query.**
@Query("select * from AdminUser where id = ?0 and username = ?1")
Optional<AdminUser> findByIdAndUsername(final UUID id,final String userName);

}

最后是引发异常的测试用例:

import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.util.Version;
import org.springframework.test.context.junit4.SpringRunner;
import example.springdata.cassandra.util.CassandraKeyspace;
import unicon.matthews.admin.AdminUser;
import unicon.matthews.admin.service.AdminUserCassandraTable;
import unicon.matthews.admin.service.AdminUserPK;
import unicon.matthews.admin.service.repository.AdminUserRepository;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = unicon.matthews.admin.service.repository.CassandraConfiguration.class)
public class AdminUserRepositoryTests {

    final String userName = UUID.randomUUID().toString();
    final UUID _id = UUID.randomUUID();


    @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost().atLeast(Version.parse("3.0"));

    @Autowired AdminUserRepository repository;

    @Before
    public void setUp() throws Exception {

        repository.deleteAll();
        AdminUserCassandraTable aPojo = new AdminUserCassandraTable();
        AdminUserPK adminUserPK = new AdminUserPK();
        adminUserPK.setId(_id);
        adminUserPK.setUsername(userName);
        aPojo.setId(adminUserPK);
        aPojo.setEmailAddress("some@company.com");
        aPojo.setOrgId("orgId");
        aPojo.setPassword("pass");
        aPojo.setTenantId("tenantId");
        aPojo.setCreatedAt(LocalDateTime.now());
        aPojo.setLastModified(null);
        // OJITO! metadatos a null...
        aPojo.setMetadata(null);
        aPojo.setSuperAdmin(Boolean.FALSE);
        repository.save(aPojo);
        assertTrue(repository.count() > 0);
    }


    @Test
    public void testFindByIdAndUsername() {

        Optional<AdminUser> loadedUserName = repository.findByIdAndUsername(_id,userName);
        assertNotNull(loadedUserName);
        assertEquals("something went wrong!",userName,loadedUserName.get().getUsername());
    }
}

例外情况是:

java.lang.ClassCastException: Cannot cast unicon.matthews.admin.service.AdminUserPK to java.lang.String
at java.lang.invoke.MethodHandleImpl.newClassCastException(MethodHandleImpl.java:361)
at java.lang.invoke.MethodHandleImpl.castReference(MethodHandleImpl.java:356)
at unicon.matthews.admin.AdminUser_Accessor_cmi9qy.setProperty(Unknown Source)
at org.springframework.data.cassandra.repository.query.DtoInstantiatingConverter.doWithPersistentProperty(DtoInstantiatingConverter.java:101)
at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:346)
at org.springframework.data.cassandra.repository.query.DtoInstantiatingConverter.convert(DtoInstantiatingConverter.java:92)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:221)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:209)
at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:221)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:162)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingConverter.convert(CassandraQueryExecution.java:178)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingExecution.execute(CassandraQueryExecution.java:143)
at org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(AbstractCassandraQuery.java:113)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy96.findByIdAndUsername(Unknown Source)
at unicon.mattheews.admin.service.repository.test.AdminUserRepositoryTests.testFindByIdAndUsername(AdminUserRepositoryTests.java:120)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=15=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.rules.ExternalResource.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)

问题一定与 AdminUserRepository 接口有关,与 @Query 有关,但是我如何将 UUID 和复合来自参数的主键的字符串传递给 spring-data- 的最终主键卡桑德拉需求?

现在可以了,我可以在 Cassandra 中使用复合键 table。 我必须将 PrimaryKeyColumn 字段放在相同的 @Table 注释 pojo 中,而不是 Primary Class 并且复合键的类型必须是 String 或 Long 或您认为的任何类型。我无法使用 UUID class,但我可以接受它。

这是@Table 注释 class:

import org.springframework.cassandra.core.Ordering;
import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.cassandra.mapping.CassandraType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.Table;
import java.time.LocalDateTime;
import java.util.Map;
import javax.validation.constraints.NotNull;
import com.datastax.driver.core.DataType;

@Table(value=AdminUserCassandraTable.tableName)
public class AdminUserCassandraTable {

@org.springframework.data.annotation.Transient
public static final String tableName = "AdminUser";

@PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
@CassandraType(type = DataType.Name.TEXT)
private String id;

@PrimaryKeyColumn(name = "username", ordinal = 1, type = PrimaryKeyType.CLUSTERED,ordering = Ordering.ASCENDING)
@CassandraType(type = DataType.Name.TEXT)
private String username;

@Column("tenant_id")
private String tenantId;

@Column("org_id")
private String orgId;

@Column("is_superAdmin")
private boolean superAdmin;

@NotNull
@Column("password")
private String password;

@Column("email_address")
private String emailAddress;

@Column("metadata")
private Map<String, String> metadata;

@CreatedDate
@Column("created_at")
private LocalDateTime createdAt;

@LastModifiedDate
@Column("last_modified")
private LocalDateTime lastModified;

public static String getTableName() {
    return tableName;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getTenantId() {
    return tenantId;
}

public void setTenantId(String tenantId) {
    this.tenantId = tenantId;
}

public String getOrgId() {
    return orgId;
}

public void setOrgId(String orgId) {
    this.orgId = orgId;
}

public boolean isSuperAdmin() {
    return superAdmin;
}

public void setSuperAdmin(boolean superAdmin) {
    this.superAdmin = superAdmin;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public String getEmailAddress() {
    return emailAddress;
}

public void setEmailAddress(String emailAddress) {
    this.emailAddress = emailAddress;
}

public Map<String, String> getMetadata() {
    return metadata;
}

public void setMetadata(Map<String, String> metadata) {
    this.metadata = metadata;
}

public LocalDateTime getCreatedAt() {
    return createdAt;
}

public void setCreatedAt(LocalDateTime createdAt) {
    this.createdAt = createdAt;
}

public LocalDateTime getLastModified() {
    return lastModified;
}

public void setLastModified(LocalDateTime lastModified) {
    this.lastModified = lastModified;
}
}

CassandraRepository 看起来像:

import java.util.Optional;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.Query;
import unicon.matthews.admin.AdminUser;
import unicon.matthews.admin.service.AdminUserCassandraTable;

public interface AdminUserRepository extends CassandraRepository<AdminUserCassandraTable> {

@Query("select * from AdminUser where username = ?0 ALLOW FILTERING")
Optional<AdminUser> findByUsername(final String userName);

@Query("select * from AdminUser where id = ?0 ALLOW FILTERING")
Optional<AdminUser> findById(final String id);

@Query("select * from AdminUser where id = ?0 and username = ?1")
Optional<AdminUser> findByIdAndUsername(final String id,final String userName);
}

服务看起来和以前一样。

谢谢你,祝你有愉快的一天!