-1

I'm running into an issue trying to leverage inheritance in combination with MongoDB views and @CompoundIndex. Say I have a collection items and a view of that collection called itemsView. I'm representing these entities in my models like so:

@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
}

Then, for the view I want to extend the Item class so that I can leverage its members, getters/setters, etc. when reading from the view, as such:

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

Knowing that it's not possible to create indexes on views I checked the Spring Data MongoDB source for the @CompoundIndex annotation and found:

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

Perfect, @CompoundIndex is not @Inherited so this should work fine, I thought. So I built and fired up my app and sadly ran into this:

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'

So, Spring is trying to create the index on the view after all.

What I'm trying to accomplish seems like it must be a common design challenge when working with views (and their entities, which are just a "normal" non-view entities after all).

Why is the non-inherited @CompoundIndex annotation getting applied to the subclass?


Update: After doing extensive debugging I believe this may be a bug in Spring Data MongoDB. MongoPersistentEntintyIndexResolver has a potentiallyCreateCompoundIndexDefinitions method which explicitly checks for the presence of @CompoundIndexes and @CompoundIndex on the class (entity) in question. It does so by calling Spring Data's BasicPersistentEntity.findAnnotation method. That method traverses up the inheritance chain looking for the specified annotation, returning it if it's found regardless of where in the class hierarchy it was found. There's no checking in potentiallyCreateCompoundIndexDefinitions (or anywhere else) to see if the annotation was found on a superclass and if so whether or not the @Inherited annotation was present.

1
  • Have to wonder why this got downvoted Commented Nov 22, 2019 at 21:54

2 Answers 2

0

Spring Framework uses its own logic while looking for annotations and by default inspects implemented interface and super-class types. @Inherited doesn't change anything.

Anyway, as I remember when I ran in a similar issue, there's no way of avoiding inheriting compound indexes.

Sign up to request clarification or add additional context in comments.

2 Comments

The sense of my answer, maybe not clearly, is that the absence of @Inherited doesn't imply that annotation has not to be searched in the hierarchies. And that's because of the find logic.
0

Spring Data MongoDB's 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.

From the docs for that 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.

So the behavior I'm experiencing is correct per this documentation. However I believe this is a bug with Spring Data MongoDB - to properly respect @Inherited it needs to call one of the get annotation methods instead of the find method in order prevent inheritance of non-@Inherited annotations.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.