module

Noir::TreeSitterJaxRsExtractor

Tree-sitter-backed JAX-RS / Jakarta REST extractor.

Walks @Path resource classes and emits one Endpoint-shaped Route per HTTP-method-annotated method. Recognises:

  • Class-level @ServerEndpoint("/x") — surfaced as GET with protocol = "ws".
  • Application-level @ApplicationPath("/api") for analyzer adapters that need to prefix resource routes.
  • Class-level @Path("/x") — joined onto each method's path (or @Path("/sub") if the method has one).
  • Verb annotations: @GET, @POST, @PUT, @DELETE, @PATCH, @HEAD, @OPTIONS.
  • @Consumes(MediaType.APPLICATION_*) at class or method level to set the body parameter format. Method-level wins.
  • Parameter annotations: @PathParam (skipped — URL carries it), @QueryParam, @HeaderParam, @CookieParam, @FormParam, plus @DefaultValue("x") modifier.
  • @BeanParam — expands the bean class's JAX-RS-annotated fields as parameters with the right param_type, looked up via Noir::TreeSitterJavaDtoIndex-style cross-file resolution.
  • Un-annotated, non-primitive parameters — treated as the request body and expanded against a caller-supplied DTO index (same pipeline as Spring's @RequestBody).

Out of scope for this first cut: meta-annotations, @MatrixParam.

Constants

HTTP_VERB_ANNOTATIONS = {"GET" => "GET", "POST" => "POST", "PUT" => "PUT", "DELETE" => "DELETE", "PATCH" => "PATCH", "HEAD" => "HEAD", "OPTIONS" => "OPTIONS"}

JAX-RS HTTP-method annotations. Simple names are matched; the walker normalises any package-qualified prefix to the trailing segment.

INJECTED_PARAM_TYPES = Set {"routingcontext", "httpserverrequest", "httpserverresponse", "containerrequestcontext", "containerresponsecontext", "securitycontext", "uriinfo", "httpheaders", "resourcecontext", "providers", "sse", "sseeventsink", "asyncresponse", "httpservletrequest", "httpservletresponse", "servletrequest", "servletresponse", "securityidentity", "jsonwebtoken"}

Framework-provided method parameters that can be injected by type in RESTEasy Reactive / Quarkus or are commonly carried by JAX-RS/Servlet @Context / @Suspended. These are never request bodies.

MULTIPART_FORM_PARAM_TYPES = Set {"multipartformdatainput", "multipartinput", "formdatamultipart"}
PARAM_ANNOTATION_FORMAT = {"QueryParam" => "query", "HeaderParam" => "header", "CookieParam" => "cookie", "FormParam" => "form", "FormDataParam" => "form", "RestQuery" => "query", "RestHeader" => "header", "RestCookie" => "cookie", "RestForm" => "form"}

Both standard JAX-RS names and Quarkus's @Rest* aliases map to the same param formats. Listing both here keeps the Quarkus analyzer a thin detector layer on top of this extractor.

PATH_PARAM_ANNOTATIONS = Set {"PathParam", "RestPath"}

@PathParam skip-list — Quarkus's @RestPath is a drop-in alias for the same role. Both are URL-carried and never emitted as request parameters.

PRIMITIVE_TYPES = Set {"boolean", "byte", "char", "short", "int", "long", "float", "double", "void", "string", "object", "integer", "character"}

Java primitive type names (lowercased). Anything else with no parameter annotation gets treated as a request-body DTO.

Instance methods

extract_application_path(source : String) : String | Nil
Source
extract_application_path_from(root : LibTreeSitter::TSNode, source : String) : String | Nil
Source
extract_bean_fields(source : String) : Hash(String, Array(Param))

Read JAX-RS-annotated fields (@QueryParam, @HeaderParam, ...) from every class in the file as {class_name => Params}. Used to power @BeanParam expansion across files.

Source
extract_bean_fields_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, Array(Param))
Source
extract_class_names(source : String) : Array(String)
Source
extract_class_names_from(root : LibTreeSitter::TSNode, source : String) : Array(String)
Source
extract_custom_verb_annotations(source : String) : Hash(String, String)

@HttpMethod("VERB") is JAX-RS's general mechanism for declaring a custom HTTP verb — Jersey/RESTEasy Reactive's QUERY support (and any other non-standard verb a project defines) is just a user annotation type meta-annotated with it:

@HttpMethod("QUERY") @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface QUERY {}

Reads every @interface declaration in source and maps its simple name to the verb it declares. A name that collides with a built-in (HTTP_VERB_ANNOTATIONS) is skipped — the hard-coded table stays authoritative for those.

Source
extract_custom_verb_annotations_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, String)
Source
extract_routes(source : String, dto_index : Hash(String, Array(TreeSitterJavaParameterExtractor::FieldInfo)) = {} of String => Array(TreeSitterJavaParameterExtractor::FieldInfo), bean_index : Hash(String, Array(Param)) = {} of String => Array(Param), subresource_sources : Hash(String, SourceEntry) = {} of String => SourceEntry, *, custom_verb_annotations : Hash(String, String) = {} of String => String, include_callees : Bool = false) : Array(Route)

Public entry point — walks source and returns one Route per JAX-RS endpoint defined in path's file. dto_index maps class_name → fields for cross-file body / @BeanParam expansion (typically built via TreeSitterJavaDtoIndex).

Source
extract_routes_from(root : LibTreeSitter::TSNode, source : String, dto_index : Hash(String, Array(TreeSitterJavaParameterExtractor::FieldInfo)) = {} of String => Array(TreeSitterJavaParameterExtractor::FieldInfo), bean_index : Hash(String, Array(Param)) = {} of String => Array(Param), subresource_sources : Hash(String, SourceEntry) = {} of String => SourceEntry, *, custom_verb_annotations : Hash(String, String) = {} of String => String, include_callees : Bool = false) : Array(Route)

Same as extract_routes, but reuses a Java tree-sitter root the caller already parsed. Analyzer adapters use this when they also need to attach method-body callees without reparsing the file.

Source

Nested types