Search code examples
javagenericspolymorphismravendbquerydsl

Using generics to return a RavenDB StreamResult


I am struggling to keep my code compact and most importantly, staying true to the "don't repeat yourself" principle when dealing with RavenDB's querydsl types (i.e. types I have stored in the db). I have two cases which force me to copy/paste methods or litter the code with if statements:

  • I would like to pass a generic querydsl type to the method as an argument
  • I would like to return a generic querydsl type from a method

First case: something like this

public int RetrieveStuff(<myGenericType>)
{
    QGenericType qgt= QGenericType.GenericType;
    IRavenQueryable<GenericType> query = session.query(GenericType.class, "GenericType/ByName");
}

Second case:

public CloseableIterator<StreamResult<GenericType>> RetrieveMoreStuff(String id)
{
    doSomething();
    return Session.advanced().stream(query); //type depends on the operation
}

Since I can't compile the methods as indicated above, I am forced to create a separate (yet functionally identical) method for each type ! Like this:

private CloseableIterator<StreamResult<supertype>> retrieveStuff();
private CloseableIterator<StreamResult<subtype1>> retrieveStuff1();
private CloseableIterator<StreamResult<subtype2>> retrieveStuff2();

etc.

I'm unclear on the following:

  • Is this a Java generics-related issue, or do the Querydsl types strongly "bind" to the types they are given when created ? In other words, is the type onto which the Querydsl type "maps" inseparably linked from the Querydsl type ?
  • Why can't I do this: IRavenQueryable<supertype> query = session.query(subtype.class, "Something/ByName") ?
  • Is it possible at all to apply polymorphism in this way with querydsl types and the types stored in RavenDB ? If I store a supertype and its subtype(s) in RavenDB, can I somehow make the interaction with the collections generic in the querying code ?

If it is possible in principle, I would very much appreciate a valid method signature and minimal code inside to get the query working.

Thank you very much for your help.


Solution

  • You can use:

    IRavenQueryable<? extends Animal> query = session.query(Dog.class) 
    

    However to model polymorphic query you should use WhereEntityIs in your index: Example: https://github.com/ravendb/ravendb-jvm-client/blob/7845a881d917e1be56aa6913aa5aba85cedd7190/Raven.Client.Java/src/test/java/net/ravendb/client/connection/WhereEntityIsTest.java#L16

    The only purpose of QueryDSL is to avoid strings in queries (type safe). It can be used for addressing simple properties, as well as nested. Example: https://github.com/ravendb/ravendb-jvm-client/blob/68ca05f0f3e158ec1702d64eca11d1e6b5dc8a17/Raven.Client.Java/src/test/java/net/ravendb/tests/querying/UsingDynamicQueryWithRemoteServerTest.java#L127