module
Noir::TreeSitterKotlinParameterExtractor
Overview
Tree-sitter-backed parameter extractor for Kotlin Spring.
Mirrors TreeSitterJavaParameterExtractor for the Kotlin AST
(parameter modifiers come before the parameter, primary
constructor properties carry DTO fields, annotation arguments
use value_arguments instead of annotation_argument_list).
Covered:
@PathVariable(skipped — URL carries it)@RequestBody/ messaging@Payload— defaults to "json" (or "form" via consumes=)@RequestParam(value/name = "x", defaultValue = "y")— query@RequestHeader(value/name = "x")/ messaging@Header— header, includingHttpHeaders.X_FOOconstant normalisation@CookieValue(name = "lorem", defaultValue = "ipsum")— cookie- Primitive types (Long/Int/String/Boolean/MultipartFile) emit directly with the declared parameter name
- User-defined classes — DTO field expansion via the
caller-supplied
class_fieldsindex. Kotlin DTOs are usuallydata class Foo(val a, var b)— properties live on the primary constructor and are all exposed as if they werepublicfields with synthesised setters. params = ["x=v"]andheaders = ["X-H=v"]on the method's mapping annotation synthesise extraParams.params=for GET/HEAD/OPTIONS is "query"; otherwise "form" (matches Spring's dispatch convention).
Not covered yet (see #1298):
- HttpServletRequest body scan — Kotlin idiom rarely uses it.
- Meta-annotations (custom annotations composing
@RequestMapping).
Extended Modules
Defined in:
miniparsers/kotlin_parameter_extractor_ts.crConstant Summary
-
HTTP_HEADER_SPECIAL_CASES =
{"Etag" => "ETag", "Te" => "TE", "Www-Authenticate" => "WWW-Authenticate", "X-Frame-Options" => "X-Frame-Options"} -
INJECTED_PARAM_ANNOTATIONS =
Set {"AuthenticationPrincipal", "CurrentUser", "CurrentSecurityContext", "SessionAttribute", "RequestAttribute"} -
Parameter annotations whose value is supplied by a Spring argument resolver, not bound from the HTTP request the client controls. A parameter carrying one of these is NOT an attack-surface input even when its type is a bindable DTO (the classic
@AuthenticationPrincipal user: User, or a custom meta-annotation like@CurrentUser), so it must be excluded from the un-annotated implicit-binding path that would otherwise expand its DTO fields into phantom params. Validation annotations (@Valid, …) are intentionally absent — they leave binding semantics untouched. -
PRIMITIVE_TYPES =
Set {"long", "int", "integer", "short", "byte", "char", "character", "boolean", "string", "float", "double", "number", "bigdecimal", "biginteger", "uuid", "date", "localdate", "localdatetime", "localtime", "instant", "multipartfile"} -
Scalar types Spring binds from a single request value. Type names are first resolved to their leaf identifier by
leaf_type_name(soList<Long>reduces toList); annotated request params emit by name regardless of type. Mirrors the Java extractor'sSIMPLE_PARAM_TYPESso@RequestParam ids: List<Long>surfaces instead of being silently dropped. -
QUERY_VERB_PARAMS =
Set {"GET", "HEAD", "OPTIONS"} -
Verbs whose
params = [...]constraint emits as query parameters. Anything else uses form data.
Instance Method Summary
-
#extract_class_fields(source : String) : Hash(String, Array(FieldInfo))
Extract
{class_name => [FieldInfo]}fromsource. -
#extract_class_fields_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, Array(FieldInfo))
_from(root, source, ...)variants accept a pre-parsed root so the Kotlin Spring analyzer can amortise the tree-sitter parse across multiple extractions on the same file. -
#extract_class_supertypes(source : String) : Hash(String, String)
Map each class to the simple name of its superCLASS (the supertype invoked with
(), e.g. - #extract_class_supertypes_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, String)
-
#extract_consumes(source : String, class_name : String, method_name : String) : String | Nil
Read
consumes = ["..."]/consumes = arrayOf("...")off the method's mapping annotation. - #extract_consumes_from(root : LibTreeSitter::TSNode, source : String, class_name : String, method_name : String) : String | Nil
- #extract_consumes_from_method(method : LibTreeSitter::TSNode, source : String) : String | Nil
- #extract_imports(source : String) : Array(ImportDecl)
- #extract_imports_from(root : LibTreeSitter::TSNode, source : String) : Array(ImportDecl)
-
#extract_method_parameters(source : String, class_name : String, method_name : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo)), string_constants = Hash(String, String).new, local_string_constants = Hash(String, String).new) : Array(Param)
Walk method formal parameters + synthesised
params=/headers=constraints on the method's mapping annotation. - #extract_method_parameters_from(root : LibTreeSitter::TSNode, source : String, class_name : String, method_name : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo)), string_constants = Hash(String, String).new, local_string_constants = Hash(String, String).new) : Array(Param)
- #extract_method_parameters_from_method(method : LibTreeSitter::TSNode, source : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo)), string_constants = Hash(String, String).new, local_string_constants = Hash(String, String).new) : Array(Param)
- #extract_package_name(source : String) : String
- #extract_package_name_from(root : LibTreeSitter::TSNode, source : String) : String
- #extract_server_request_parameters_from_method(method : LibTreeSitter::TSNode, source : String, verb : String, parameter_format : String | Nil, class_fields : Hash(String, Array(FieldInfo))) : Array(Param)
- #index_functions_from(root : LibTreeSitter::TSNode, source : String) : Hash(String, LibTreeSitter::TSNode)
Instance Method Detail
Extract {class_name => [FieldInfo]} from source. Kotlin DTO
fields can come from:
- Primary constructor parameters declared with
val/var(the commondata class Foo(val a: Int, var b: String)idiom). property_declarationnodes inside the class body (var/valproperties on regular classes).
Properties are treated as setter-accessible by default — Kotlin
synthesises setters for var, and val properties usually
serialise just fine for our endpoint-fan-out purposes.
_from(root, source, ...) variants accept a pre-parsed root
so the Kotlin Spring analyzer can amortise the tree-sitter
parse across multiple extractions on the same file. Tree
lifetime is the caller's responsibility.
Map each class to the simple name of its superCLASS (the supertype
invoked with (), e.g. class Owner : Person() → {"Owner" => "Person"}). Interface supertypes (: Foo without parens) carry no
bindable fields and are skipped. Drives the DTO index's cross-file
inheritance merge so a command object that extends a base class
inherits its bindable fields.
Read consumes = ["..."] / consumes = arrayOf("...") off the
method's mapping annotation. Returns "form" / "json" / nil.
Walk method formal parameters + synthesised params=/headers=
constraints on the method's mapping annotation. Returns the
combined parameter list in the order the legacy analyzer
emitted them: formal-parameter sweep first, constraint sweep
appended.