Spring 数据 MongoDB - 视图、@CompoundIndex 和注解继承

Spring Data MongoDB - Views, @CompoundIndex and annotation inheritance

我 运行 遇到一个问题,试图结合 MongoDB 视图和 @CompoundIndex 来利用继承。假设我有一个集合 items 和一个名为 itemsView 的集合视图。我在我的模型中代表这些实体是这样的:

@Document(collection = "items")
@CompoundIndex(name = "view_active_available" def = "{active: 1, quantity: 1}")
public class Item {
    // Adding index on collection that view definition will leverage
}

然后,对于视图,我想扩展 Item class 以便我可以在从视图读取时利用其成员 getters/setters 等,如下所示:

@Document(collection = "itemsView")
public class ItemAvailable extends Item {
     // Now I can read from the view but treat them as `Item` instances
}

知道无法在视图上创建索引,我检查了 Spring 数据 MongoDB 来源的 @CompoundIndex 注释并发现:

/**
 * Mark a class to use compound indexes.
 * ...
 */
@Target({ ElementType.TYPE })
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface CompoundIndex {
    ...
}

完美,@CompoundIndex 不是 @Inherited 所以我认为这应该可以正常工作。所以我构建并启动了我的应用程序,遗憾的是 运行 变成了这个:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemsView': Invocation of init method failed; nested exception is org.springframework.data.mongodb.UncategorizedMongoDbException: Command failed with error 166: 'Cannot create indexes on a view'

所以,Spring 毕竟是在尝试在视图上创建索引。

我正在尝试完成的工作似乎是处理视图(及其实体,毕竟它们只是 "normal" 非视图实体)时的常见设计挑战。

为什么将非继承的 @CompoundIndex 注释应用于子class?


更新:经过大量调试后,我相信这可能是 Spring 数据 MongoDB 中的错误。 MongoPersistentEntintyIndexResolver 有一个 potentiallyCreateCompoundIndexDefinitions 方法,该方法显式检查 @CompoundIndexes@CompoundIndex 在相关 class (实体)上是否存在。它通过调用 Spring Data 的 BasicPersistentEntity.findAnnotation 方法来实现。该方法向上遍历继承链以查找指定的注释,如果找到则返回它 ,而不管它在 class 层次结构中的何处找到 。没有检查 potentiallyCreateCompoundIndexDefinitions(或其他任何地方)以查看是否在 superclass 上找到注释,如果是,则是否存在 @Inherited 注释。

Spring 框架在查找注解时使用自己的逻辑,并默认检查已实现的接口和超 class 类型。 @Inherited 没有任何改变。

无论如何,我记得当我 运行 在类似的问题中时,无法避免继承复合索引。

Spring 数据 MongoDB 的 MongoPersistentEntityIndexResolver calls an internal private method potentiallyCreateCompoundIndexDefinitions, passing in the BasicPersistentEntity it's examining. That method in turn calls the entity's findAnnotation method which finally defers to AnnotatedElementUtils.findMergedAnnotation.

来自 class 的文档:

Support for @Inherited

Methods following get semantics will honor the contract of Java's @Inherited annotation except that locally declared annotations (including custom composed annotations) will be favored over inherited annotations. In contrast, methods following find semantics will completely ignore the presence of @Inherited since the find search algorithm manually traverses type and method hierarchies and thereby implicitly supports annotation inheritance without a need for @Inherited.

因此,根据本文档,我遇到的行为是正确的。但是我认为这是 Spring 数据 MongoDB 的错误 - 为了正确尊重 @Inherited 它需要调用其中一种 get 注释方法而不是 find方法以防止继承非 @Inherited 注释。