user2525691
user2525691

Reputation: 33

Customize a Spring MongoRepository - filter by class

I´ve got several Java documents that are stored in the same collection "app" in mongodb. My intention is use it for the common persistence actions (insert, find, delete...). The problem comes when I try to define repositories for only one of the classes as the repository that I´ve defined will search all the entities, and what I need is a repository where I can call to all the mongorepository standard functions (find, findAll, findby...). My explanation can be hard to understand, this is what I have now:

Base document:

@Document(collection = "app")
@NoRepositoryBean
public abstract class AbstractApplicationDocument {    
    @Id
    public String mongoId;
    // more variables, getters, setters...
}

One of the subdocuments (there will be many).

@EqualsAndHashCode(callSuper=true)
public class ClientApplicationDocument extends AbstractApplicationDocument
{
    @Id
    public String mongoId;    
}

Base Repository

@NoRepositoryBean
public interface ApplicationRepository<T, ID extends Serializable>  extends MongoRepository<T, ID>  {

}

Extended repository (where I want to filter by class)

public interface HttpClientRepository extends ApplicationRepository<HttpClientDocument, String> {
}

Sample of temporary solution that I'd like to avoid if I can reuse the MongoDb utilities

@Component
public class HttpClientRepositoryImpl {

    @Autowired
    private HttpClientRepository clientRepo;

    @Autowired
    private MongoTemplate mongo;

    public List<HttpClientDocument> findAll() {    
        Query query = new Query();
        query.addCriteria(Criteria.where("_class").is(HttpClientDocument.class.getName()));
        mongo.getConverter();
        return mongo.find(query, HttpClientDocument.class,"app");
    }
}

Relevant information in gradle. I add this because I've seen some solutions that are not valid for me. Probably because they are using different libraries:

compile("org.springframework.boot:spring-boot-starter-data-mongodb:${springBootVersion}")
compile ("org.springframework:spring-context-support:4.1.8.RELEASE");

Is there any simple solution?

Upvotes: 3

Views: 7975

Answers (1)

mp911de
mp911de

Reputation: 18137

You can customize Spring Data repositories in many ways. You can provide custom repository base classes or provide custom implementation classes.

For your question in particular, SimpleMongoRepository does not restrict query on the _class field. You can see below an example for a custom repository base class that restricts the findAll query method to use only the declared entity type.

You would be required to apply that pattern also for other methods which are declared on the MongoRepository level that you want to restrict to the particular class type.

@EnableMongoRepositories(repositoryBaseClass = MyMongoRepository.class)
static class Config {
}

static class MyMongoRepository<T, ID extends Serializable> extends SimpleMongoRepository<T, ID> {

    private final MongoEntityInformation<T, ID> metadata;
    private final MongoOperations mongoOperations;

    public MyMongoRepository(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
        super(metadata, mongoOperations);
        this.metadata = metadata;
        this.mongoOperations = mongoOperations;
    }

    @Override
    public List<T> findAll() {

        Query query = new Query();
        query.restrict(this.metadata.getJavaType());

        return this.mongoOperations.find(query, this.metadata.getJavaType(), this.metadata.getCollectionName());
    }
}

findAll queries restrict now the class type and queries for a e.g. ModelRepository extends MongoRepository<Model, String> would look like:

{ "_class" : { "$in" : [ "com.example.Model"]}}

Query methods with @Query can be used to pass in the class type (@Query("{'_class': ?0}")) but there's no way to contrain the class type for derived query methods (List<Model> findByFirstnameAndLastname(…)).

There's an open ticket in our Jira related to restricting types of the repository. That particular ticket is related to polymorphic queries but in its essence, it's related to type restrictions on query methods.

Upvotes: 5

Related Questions