如何确保 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)
才能使此解决方案起作用。
我正在使用 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)
才能使此解决方案起作用。