private <T extends ObjectFilter> Restriction findAndCreateRestriction(
      T filter, InterpretationContext context, Restriction parent) throws QueryException {

    Validate.notNull(filter, "filter");
    Validate.notNull(context, "context");

    LOGGER.trace("Determining restriction for filter {}", filter);

    ItemPathResolver helper = context.getItemPathResolver();
    JpaEntityDefinition baseEntityDefinition;
    if (parent != null) {
      baseEntityDefinition = parent.getBaseHqlEntityForChildren().getJpaDefinition();
    } else {
      baseEntityDefinition = context.getRootEntityDefinition();
    }
    Restriction restriction =
        findAndCreateRestrictionInternal(filter, context, parent, helper, baseEntityDefinition);

    LOGGER.trace("Restriction for {} is {}", filter.getClass().getSimpleName(), restriction);
    return restriction;
  }
 public <T extends Object> Matcher<T> findMatcher(T value) {
   return findMatcher(value != null ? (Class<T>) value.getClass() : null);
 }
  private <T extends ObjectFilter> Restriction findAndCreateRestrictionInternal(
      T filter,
      InterpretationContext context,
      Restriction parent,
      ItemPathResolver resolver,
      JpaEntityDefinition baseEntityDefinition)
      throws QueryException {

    // the order of processing restrictions can be important, so we do the selection via handwritten
    // code

    if (filter instanceof AndFilter) {
      return new AndRestriction(context, (AndFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof OrFilter) {
      return new OrRestriction(context, (OrFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof NotFilter) {
      return new NotRestriction(context, (NotFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof InOidFilter) {
      return new InOidRestriction(context, (InOidFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof OrgFilter) {
      return new OrgRestriction(context, (OrgFilter) filter, baseEntityDefinition, parent);
    } else if (filter instanceof TypeFilter) {
      TypeFilter typeFilter = (TypeFilter) filter;
      JpaEntityDefinition refinedEntityDefinition =
          resolver.findRestrictedEntityDefinition(baseEntityDefinition, typeFilter.getType());
      return new TypeRestriction(context, typeFilter, refinedEntityDefinition, parent);
    } else if (filter instanceof ExistsFilter) {
      ExistsFilter existsFilter = (ExistsFilter) filter;
      ItemPath path = existsFilter.getFullPath();
      ItemDefinition definition = existsFilter.getDefinition();
      ProperDataSearchResult<JpaEntityDefinition> searchResult =
          resolver.findProperDataDefinition(
              baseEntityDefinition, path, definition, JpaEntityDefinition.class);
      if (searchResult == null) {
        throw new QueryException(
            "Path for ExistsFilter ("
                + path
                + ") doesn't point to a hibernate entity within "
                + baseEntityDefinition);
      }
      return new ExistsRestriction(
          context, existsFilter, searchResult.getEntityDefinition(), parent);
    } else if (filter instanceof RefFilter) {
      RefFilter refFilter = (RefFilter) filter;
      ItemPath path = refFilter.getFullPath();
      ItemDefinition definition = refFilter.getDefinition();
      ProperDataSearchResult<JpaReferenceDefinition> searchResult =
          resolver.findProperDataDefinition(
              baseEntityDefinition, path, definition, JpaReferenceDefinition.class);
      if (searchResult == null) {
        throw new QueryException(
            "Path for RefFilter ("
                + path
                + ") doesn't point to a reference item within "
                + baseEntityDefinition);
      }
      return new ReferenceRestriction(
          context,
          refFilter,
          searchResult.getEntityDefinition(),
          parent,
          searchResult.getLinkDefinition());
    } else if (filter instanceof PropertyValueFilter) {
      PropertyValueFilter valFilter = (PropertyValueFilter) filter;
      ItemPath path = valFilter.getFullPath();
      ItemDefinition definition = valFilter.getDefinition();

      ProperDataSearchResult<JpaPropertyDefinition> propDefRes =
          resolver.findProperDataDefinition(
              baseEntityDefinition, path, definition, JpaPropertyDefinition.class);
      if (propDefRes == null) {
        throw new QueryException(
            "Couldn't find a proper restriction for a ValueFilter: " + valFilter.debugDump());
      }
      // TODO can't be unified?
      if (propDefRes.getTargetDefinition() instanceof JpaAnyPropertyDefinition) {
        return new AnyPropertyRestriction(
            context,
            valFilter,
            propDefRes.getEntityDefinition(),
            parent,
            propDefRes.getLinkDefinition());
      } else {
        return new PropertyRestriction(
            context,
            valFilter,
            propDefRes.getEntityDefinition(),
            parent,
            propDefRes.getLinkDefinition());
      }
    } else if (filter instanceof NoneFilter
        || filter instanceof AllFilter
        || filter instanceof UndefinedFilter) {
      // these should be filtered out by the client
      throw new IllegalStateException(
          "Trivial filters are not supported by QueryInterpreter: " + filter.debugDump());
    } else {
      throw new IllegalStateException("Unknown filter: " + filter.debugDump());
    }
  }