Class UnknownQueryParameterFilter

java.lang.Object
ubic.gemma.rest.providers.UnknownQueryParameterFilter
All Implemented Interfaces:
jakarta.ws.rs.container.ContainerRequestFilter

@Provider @Component public class UnknownQueryParameterFilter extends Object implements jakarta.ws.rs.container.ContainerRequestFilter
Rejects a request that carries a query parameter the matched resource method cannot bind, rather than ignoring it.

JAX-RS drops an undeclared query parameter silently, which turns a typo or a wrong parameter name into a confidently-wrong answer instead of an error: GET /datasets?ids=1,2,3&limit=200 dropped ids and answered with the whole corpus, reported under a totalElements covering every dataset. There is no JAX-RS or Jersey setting for this (Jersey 3.1 exposes none), so it is enforced here.

Why the accepted set cannot go stale

The accepted set is not written down anywhere. It is read, per route, from Invocable.getParameters() — the very Parameter objects Jersey uses to bind values into the method's arguments. Adding a @QueryParam to a resource method therefore widens what this filter accepts in the same edit, and there is no second list to update. Consequences that follow from reading Jersey's own model rather than re-deriving one by reflection:
  • @BeanParam is expanded, because Jersey models it as a Parameter.BeanParameter holding the nested parameters (none are used in this module today; the recursion is what keeps that true if one is added).
  • Parameters inherited from a superclass or interface are already resolved into the invocable, so a route that declares its parameters on a base type is not wrongly narrowed.
  • Anything Jersey binds from somewhere other than the query string — path, header, cookie, matrix, entity — is simply not in the accepted set and is not looked for in the query string either.

What is deliberately not checked

  • A method annotated AllowsUnknownQueryParameters, or declared in a class so annotated: it reads the query string itself, so no declared set describes what it accepts.
  • A method handed the raw UriInfo, for the same reason — it can read any parameter, so no parameter can be shown to be ignored. Derived from the signature rather than from a list, so a new pass-through route is covered the moment it is written.
  • OPTIONS, so a CORS preflight — which the browser sends to the same URL, query string included — can never be answered with a 400. CorsFilter short-circuits preflights ahead of Jersey today; this does not depend on that staying true.
  • Every request, when gemma.rest.rejectUnknownQueryParameters is false. The setting is the rollback: it takes a restart, not a redeploy.
Author:
gemma
  • Constructor Summary

    Constructors
    Constructor
    Description
    UnknownQueryParameterFilter(boolean enabled)
    The inline default matters: the mocked REST test contexts resolve placeholders from a fixed list rather than from default.properties, so a bare ${...} here fails container startup for every JerseyTest in the module, not just a test of this filter.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    filter(jakarta.ws.rs.container.ContainerRequestContext requestContext)
     

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • UnknownQueryParameterFilter

      @Autowired public UnknownQueryParameterFilter(@Value("${gemma.rest.rejectUnknownQueryParameters:true}") boolean enabled)
      The inline default matters: the mocked REST test contexts resolve placeholders from a fixed list rather than from default.properties, so a bare ${...} here fails container startup for every JerseyTest in the module, not just a test of this filter.
  • Method Details

    • filter

      public void filter(jakarta.ws.rs.container.ContainerRequestContext requestContext)
      Specified by:
      filter in interface jakarta.ws.rs.container.ContainerRequestFilter