Skip to content

Replace ad hoc reflection for optional-extension wiring with a ServiceLoader SPI (RESTServer, Annotations) #6723

Description

@duncdrum

Context

The ModuleFactory/IndexFactory SPI work replaced ad hoc Class.forName().getMethod().invoke() reflection (used by a broker pool service to wire the optional vector extension into core) with a small ServiceLoader-discovered interface. That review pass turned up two more instances of the same underlying shape elsewhere in the codebase: core needs optional behavior from an extension module without a hard compile-time dependency, and currently gets it via reflection that's more fragile than a proper SPI would be.

Shape 1: RESTServer → EXQuery RestXQ extension

exist-core/src/main/java/org/exist/http/RESTServer.java's constructor reflectively probes for org.exist.extensions.exquery.modules.request.RequestModule (reading its EXQ_REQUEST_ATTR constant via a reflective field access) and, if present, for org.exist.extensions.exquery.restxq.impl.adapters.HttpServletRequestAdapter, then uses MethodHandles.Lookup + LambdaMetafactory to reflectively build a BiFunction<HttpServletRequest, FilterInputStreamCacheConfiguration, HttpRequest> from a constructor handle — all just to avoid a compile-time dependency from exist-core on the RestXQ extension module. This is considerably more fragile/hard to follow than the pattern already established for modules and indexes.

Fix: a small ExQueryRequestAdapterFactory SPI (ServiceLoader-discovered, mirroring the vector extension's hook interface), implemented by HttpServletRequestAdapter in extensions/exquery/restxq and registered via META-INF/services.

Shape 2: Annotations.java → org.exist.xquery.xUnit.Annotations

exist-core/src/main/java/org/exist/xquery/Annotations.java has a static initializer that force-instantiates a hardcoded class name (org.exist.xquery.xUnit.Annotations) inside a bare catch (final Exception e) {} that silently swallows any exception — not just "class not found," but any genuine bug thrown from that class's own registration path too.

Needs investigation, not a direct port of shape 1's fix: org.exist.xquery.xUnit.Annotations does not exist anywhere in this repository (no xUnit module, no extension providing it). Either:

  • it's dead/vestigial code left over from a removed extension, and should just be deleted, or
  • it's an intentional extension point for an out-of-tree/third-party plugin, in which case the fix isn't "port it to the same SPI as shape 1" but "replace a reflective probe for one hardcoded class name with a real ServiceLoader-based SPI that supports multiple providers and doesn't hide real errors behind a blanket catch."

Acceptance criteria

  • RESTServer's RestXQ request-adapter wiring uses a ServiceLoader-discovered SPI instead of MethodHandles/LambdaMetafactory reflection.
  • Annotations.java's xUnit hook is either removed (if confirmed dead) or converted to a proper SPI with narrowed exception handling (if an active extension point is confirmed to still be wanted).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions