Search code examples
javajsonapifilteringpredicate

How to construct predicates dynamically in Java


I am not sure if that is possible or not and after a lot of research I ended up here to ask for your help or even guidance. So, let's say I have a json array that has 10 different types of objects inside the array. This is a json that is being retrieved through an API with sports games. What I need to do is filtering through these objects in my application. I am using JAVA and so far I have ended up that I will use stream filter and predicates. I am aware that I can create different types of predicates and put them in the stream.filter() function, but is it possible to do it somehow dynamically?

For example, I need to filter this array by time. This predicate will be

return p -> p.getTime() > 1;

And then:

return match.stream().filter( predicate ).collect(Collectors.<Match>toList());

What if another filter has another one condition which is team name. Is it possible to add some how the other predicate and also add the "AND" "OR" condition between those two? I need to do this dynamically using one filter function with different predicates.

Is there a way to make something like a custom query to store it in a database and retrieve it and use it like a predicate? Or the predicate itself is it possible to be stored in a database?

If I am completely wrong on this please guide me to find another way to do this. Otherwise a help would be appreciated. Thank you and happy new year to all. :)


Solution

  • This is an interesting problem. And I think this will not be uncommon face as well considering data lake scenarios.

    I think, as suggested in a comment above, the way to apply is to have a Predicate. You may have a predicate that applies the conditions as AND or OR and then supply it to the stream processor. Like this (assuming that you have a base class Data to which you have mapped your API output):

    /* Create the predicate with the conditions. Showing 2 here with an "AND" combination. */
    Predicate<? extends Data> p = d -> d.getTime() > 1;
    p.and( d -> d.getName().equals( "Football" ) ); //Consider ".or()" here, if that is what you need.
    
    /* Supply this predicate to the stream processor. */
    match.stream().filter( p ).collect(Collectors.<Match>toList());
    

    Using an and() call is the same as calling .filter() one after the other on the stream processor. Something like this:

    stream.filter(...).filter(...)...
    

    So, you will be able to construct such a stream call in a for loop.

    Is there a way to make something like a custom query to store it in a database and retrieve it and use it like a predicate? Or the predicate itself is it possible to be stored in a database?

    You may do this within your Predicate itself. That is, instead writing the logic as shown above, you may make a database call to fetch you Java code. However, you will have to do dynamic compilation using JavaCompiler. That may be a bit complicated. However, you may consider a JVM-based scripting language like Groovy for such things.