如何确保 CassandraOperations.selectOneById() 初始化 POJO 中的所有字段?

How can I ensure CassandraOperations.selectOneById() initializes all fields in the POJO?

我正在使用 Spring Data Cassandra 1.3.4.RELEASE 来保存我拥有的 class 实例。 class 写在 Groovy 中,但我认为这并不重要。我已经实现了一个 CrudRepository,并且正在将 CassandraOperations 的一个实例注入回购实现 class。我可以成功插入、删除和执行大多数其他操作。但是,有一个场景我 运行 打破了我的测试用例。我的实体 class 看起来像这样:

@Table("foo")
class FooData {
  @PrimaryKey("id")
  long id
  @Column("created")
  long updated
  @Column("name")
  String name
  @Column("user_data")
  String userData
  @Column("numbers")
  List numberList = []
}

在我的测试用例中,我恰好在调用CassandraOperations.insert(entity)之前只设置了'id'和'updated'等几个字段,所以大部分在实体中都是null插入时的实例。但是 numberList 字段不为空,它是一个空列表。在 insert() 之后,我直接调用 CassandraOperations.selectOneById(FooData.class, id)。我得到一个 FooData 实例,并且在我保存它时初始化的字段填充了数据。但是,我在测试中检查了内容相等性,但它失败了,因为空列表在从 CassandraOperations.selectOneById() 返回的 POJO 中没有作为空列表返回。它实际上是空的。我认为这可能是某种 Cassandra 优化。它似乎发生在实例化 POJO/entity 的 CGLIB 代码中。这是一个已知的 "feature" 吗?是否有一些注释可以标记 'numberList' 字段以指示它不能为空?任何线索表示赞赏。谢谢。

简而言之

Cassandra 将空集合存储为 null 并且 Spring 数据 Cassandra 会覆盖已初始化的字段。

说明

Cassandra list/set 类型的列将一个空集合表示为 null。 list/set(从 Java/Groovy 看)是空的还是 null 并不重要。因此,存储一个空列表会在 null 中产生。从这里无法判断在保存值时状态是 null 还是空的。

Spring Data Cassandra 使用从结果集中检索到的值覆盖 所有 字段,因此您的预初始化字段设置为 null。 我创建了一个工单 DATACASS-266 来跟踪这个问题的状态。

解决方法

Spring 数据尽可能使用设置器,以便您有机会进行干预。一个非常简单的 null 守卫可以是:

public void setMyList(List<Long> myList) { if(myList == null){ this.myList = new ArrayList<>(); return; } this.myList = myList; }

作为 mp911de 答案的重要补充,您必须设置 @org.springframework.data.annotation.AccessType(AccessType.Type.PROPERTY) 才能使此解决方案起作用。