Search code examples
javajpagenericscriteria

Join depending on generic type


My RefineByBasicTaskType should add the same criteria for different CriteriaQuery types. T could be a Task or a Appointment. The only difference is, that there is no join needed if T is a Task.

How can I use my RefineByBasicTaskType class for multiple types?

public class RefineByBasicTaskType<T> extends AbstractRefinement<T> {

private BasicTaskType basicTaskType;

public Predicate addCriteriaQuery(CriteriaQuery<T> criteria, CriteriaBuilder builder, Root<T> taskRoot) {
    
    if (T instanceof Task) {
        return refineByBasicTaskType(builder,
                                     taskRoot);
    }

    return refineByBasicTaskType(builder,
                                 fetchOrCreateFirstJoin(taskRoot,"task"));
}...

Solution

  • From a proper object oriented point of view you are trying to re-invent mechanisms that are already possible with inheritance:

    public abstract class RefineByBasicTaskType<T> extends AbstractRefinement<T> {
    
      public abstract Predicate addCriteriaQuery(CriteriaQuery<T> criteria, CriteriaBuilder builder, Root<T> root);
    }
    
    public class RefineByTask extends RefineByBasicTaskType<Task> {
      
      @Override
      public Predicate addCriteriaQuery(CriteriaQuery<Task> criteria, CriteriaBuilder builder, Root<Task> root) {
        return refineByBasicTaskType(builder, root);
      }
    }
    
    public class RefineByWhatever extends RefineByBasicTaskType<Whatever> {
      
      @Override
      public Predicate addCriteriaQuery(CriteriaQuery<Whatever> criteria, CriteriaBuilder builder, Root<Whatever> root) {
        return refineByBasicTaskType(builder, fetchOrCreateFirstJoin(root, "task"));
      }
    }
    

    Edit: If you don't want to use inheritance you should be able to get the Java type from the Root object so you could also replace your if-statement with:

    if (taskRoot.getJavaType().equals(Task.class)) {
      // ...
    }