module

Analyzer::Java::JavaEngine

Constants

DECLARATION_NODE_TYPES = Set {"class_declaration", "interface_declaration", "enum_declaration", "record_declaration", "annotation_type_declaration"}
FRAMEWORK_PROVIDED_TAG = Tag.new("framework-provided", "Served by Spring Boot / Spring Security itself, not by an application controller", "spring_analyzer")
JAVA_STRING_CONSTANT_RE = /\bstatic\s+final\s+(?:java\.lang\.)?String\b|\bfinal\s+static\s+(?:java\.lang\.)?String\b|\binterface\s/

A file that declares no static final String and no interface (whose fields are implicitly static final) has no constant another file could reference.

JAVA_STRING_RE = /"(?:[^"\\\n]|\\.)*"/
RESOLVER_SUPPORTS_RE = /\b(?:has|get)ParameterAnnotation\s*\(\s*(?:[\w.]+\.)?(\w+)\s*(?:\.\s*class|::\s*class(?:\s*\.\s*java)?)\b/
SECURITY_FILTER_TAG = Tag.new("framework-provided", "Served by a Spring Security filter, which answers it before any authorization rule applies", "spring_analyzer")

The login / logout / OAuth2 routes: a filter of the chain answers them, and every one of those filters runs before the AuthorizationFilter, so no authorizeHttpRequests rule (anyRequest().authenticated()) ever sees the request.

SPRING_ACTUATOR_CORE = ["health", "info", "beans", "caches", "conditions", "configprops", "env", "loggers", "heapdump", "threaddump", "metrics", "scheduledtasks", "mappings"] of ::String

Actuator endpoints every Boot app has once they are exposed; the rest (prometheus, flyway, ...) need their own dependency, so they are emitted only when exposure.include names them.

SPRING_ACTUATOR_DEP_RE = /spring[-.]boot[-.]starter[-.]actuator\b/
SPRING_BINDING_ANNOTATIONS = Set {"Valid", "Validated", "ModelAttribute", "RequestBody", "RequestParam", "RequestHeader", "RequestPart", "PathVariable", "CookieValue", "MatrixVariable"}

Annotations Spring itself binds or validates from the request; a resolver that checks them does not make them server-filled.

SPRING_BUILD_NOISE_RE = /<!--.*?-->|<dependencyManagement>.*?<\/dependencyManagement>|\/\*.*?\*\/|\/\/[^\n]*/m

Comments and Maven <dependencyManagement> (which only pins versions) are not dependencies; masked to spaces so offsets keep their lines.

SPRING_CHAIN_SCOPE_RE = /\bsecurityMatchers?\s*\(|(?<!AntPathRequestMatcher)\.\s*(?:antMatcher|requestMatcher)\s*\(/

securityMatcher(s)(...) / Spring 5 http.antMatcher(...) / http.requestMatcher(...): the requests a chain (and so its filters) sees.

SPRING_CHAIN_START_RE = /\bSecurity(?:Web)?FilterChain\b|configure\s*\(\s*(?:final\s+)?(?:Server)?HttpSecurity/

Where one security chain's source starts (its bean method).

SPRING_DEFAULT_STATIC_LOCATIONS = ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"]

Spring Boot's four classpath defaults for spring.web.resources.static-locations.

SPRING_LOGOUT_MATCHER_RE = /\A\s*new\s+AntPathRequestMatcher\s*\(\s*"([^"\\]*)"\s*(?:,\s*(?:"([A-Z]+)"|HttpMethod\.([A-Z]+)\.name\(\s*\)))?\s*\)\s*\)/

logoutRequestMatcher(new AntPathRequestMatcher("/x"[, "GET"])).

SPRING_LOGOUT_SUCCESS_RE = /\blogoutSuccessHandler\s*(?:\(\s*|=\s*)(?:new\s+([A-Z][\w$.]*)\s*\(|([a-z_$][\w$]*)\s*(?:\)|$))/m

.logoutSuccessHandler(handler) / (new Impl()), Kotlin logoutSuccessHandler = handler.

SPRING_SECURITY_DSL_RE = /(?:\.\s*(formLogin|logout|oauth2Login)\s*\(|\b(formLogin|logout|oauth2Login)\s*\{)/

.formLogin( / .logout( (Java, Kotlin http. calls) or the Kotlin DSL's formLogin { — a bare logout( is any app's own method, and a dotted one counts only on an HttpSecurity chain (spring_security_receiver?).

SPRING_SECURITY_FILE_RE = Regex.union("HttpSecurity", "SecurityFilterChain", "SecurityWebFilterChain", "WebSecurityConfigurerAdapter")

Files that configure an HttpSecurity / ServerHttpSecurity chain.

SPRING_SECURITY_SETTER_RE = /\b(loginPage|loginProcessingUrl|usernameParameter|passwordParameter|logoutUrl|baseUri)\s*(?:\(\s*|=\s*)/
SPRING_SECURITY_VAR_RE = /\b(?:Server)?HttpSecurity\s+([a-z_$][\w$]*)|\b([a-z_$][\w$]*)\s*:\s*(?:Server)?HttpSecurity\b/
SPRING_SPRINGDOC_DEP_RE = /springdoc[-.]openapi/
SPRING_SWAGGER_UI_DEP_RE = /springdoc[-.]openapi[\w.-]*?[-.]ui\b/
TEST_CLASS_FILE_RE = /.(?:Test|Tests)\.(?:java|kt)\z/

Takes the scan-base-relative path (Analyzer#base_relative_path), never the absolute one. The layout is a contract between the build tool and the project, so matching the absolute path let a directory above the scan base decide the answer — a CI job that checks out under a src/test/ step directory silently lost 375 of the fixture tree's 396 endpoints.

FooTest.java / FooTests.java (and .kt, which Javalin, Micronaut, Quarkus and JAX-RS read through the same predicate) are JUnit classes even when they sit in src/main/java of a published test kit (the Micronaut TCK declares its @Requires(property = "spec.name") controllers there). The suffix check is case-sensitive, so Latest.java is not a hit, and it needs a name before the suffix: a class literally called Test or Tests is a tutorial's servlet, not a test.

TEST_SOURCE_SET_RE = Regex.union("/src/test/", "/src/it/", "/src/testFixtures/", "/src/jmh/", "/src/integrationTest/", /\/src\/integration\/(?!(?:.*\/)?src\/main\/)/, "/src/functionalTest/")

Maven/Gradle pin test sources to src/test/<lang>/ — java, kotlin, scala, groovy all share the layout. Real route handlers never live there, but Quarkus, Micronaut, Spring, Javalin, JAX-RS and friends routinely declare inline controllers under src/test/java/... to exercise the framework. The path layout is part of the build tool's contract so the prefix check is unambiguous.

Also covers Maven's archetype source-roots (src/it/, integration-test convention used by some Quarkus extensions and Apache projects) which sit alongside src/test/, and Gradle's extra test source sets (testFixtures, jmh, integrationTest, functionalTest, and integration from the com.coditory.integration-test plugin).

Class methods

ant_matches?(url : String, pattern : String) : Bool

Spring's ant match of a request path (/** also matches the bare prefix).

Source
each_char_after(code : String, index : Int32, &)

Yields each char after char index index with its char index.

Source
find_matching_delimiter(code : String, open_idx : Int32, open_char : Char, close_char : Char) : Int32 | Nil

Index of the delimiter closing the open_char at open_idx, or nil when the source runs out first. String and char literals are skipped, so a )/} inside "…" or '…' cannot close the block early.

Scan by CHARACTER (not byte): open_idx is a char index from String#index and callers char-slice with — or range-compare — the returned index. A byte scan corrupts both on multi-byte UTF-8. ASCII-identical to the previous byte loop. The walk starts at open_idx rather than skipping up to it from the file head, which made one call per route quadratic over a large file.

Source
java_type_file(type : String, source : String) : String | Nil

The project file declaring the JVM type type as source names it: by its single-type import, else in source's own package.

Source
name_scope(source : String) : NameScope
Source
project_root_for(path : String, base : String) : String

Module root of a Maven/Gradle source file: everything before /src/main/java/ (or /src/main/kotlin/) below base, or the file's own directory outside that layout.

Source
spring_chain_range(masked : String, offset : Int32) : Tuple(Int32, Int32)

The char range of the security chain (bean method) holding offset.

Source
spring_security_routes(code : String) : Array(SpringSecurityRoute)

The login / logout / OAuth2 endpoints Spring Security's filters serve for each formLogin / logout / oauth2Login of an HttpSecurity chain, with the configured URLs and parameter names or Spring's defaults. code is comment-stripped source. Values are string literals or static final String / const val constants of the file; a URL set any other way (a constant of another class, a request matcher) is unknown, so that configurer yields no route rather than the default one.

Source
strip_comments(text : String) : String

Replaces // line comments and /* */ block comments with spaces (newlines preserved) so a commented-out annotation or call is never mistaken for a live one, while keeping every real line number stable for PathInfo reporting. String and char literals are tracked so // or /* inside a literal (e.g. a URL default value "http://x//y") is never treated as a comment opener.

Source
test_path?(relative_path : String) : Bool
Source
type_resolves_to?(written : String, fqn : String, file : String, scope : NameScope, unresolved : Bool = false) : Bool

True when the type name written in file (simple or qualified, generic arguments ignored) is fqn, resolved the way javac does: a qualified name stands for itself; a simple one goes to a single-type import, then a type the file declares, then its own package, then an on-demand import. unresolved answers when none of those names it (a type from an implicit or unscanned package).

Source

Nested types