Skip to content

OPENNLP-1932: Match model finder wildcards without regular expressions - #1278

Draft
krickert wants to merge 28 commits into
apache:mainfrom
ai-pipestream:OPENNLP-1932-model-resolver-glob
Draft

krickert wants to merge 28 commits into
apache:mainfrom
ai-pipestream:OPENNLP-1932-model-resolver-glob

Conversation

@krickert

@krickert krickert commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Based on #1275, and independent of the other parts of the epic. It can be reviewed and merged in any order relative to them. This diff carries the #1275 commits until that one merges; the commits of this change alone: ai-pipestream/opennlp@OPENNLP-1928-regex-removal-trivial...OPENNLP-1932-model-resolver-glob

AbstractClassPathModelFinder, DirectoryModelFinder, and SimpleClassPathModelFinder converted wildcard strings to regular expressions and split the class path with compiled patterns. A package-private GlobMatcher now matches * (any run) and ? (one code point) directly, anchored on the whole name and, as before, not crossing line terminators; the class path split is a character scan with String.split semantics.

One intended behavior change: characters the old conversion never quoted (( ) [ ] { } + | ^ $ \) had regex meaning or threw PatternSyntaxException; they now stand for themselves.

API: the protected asRegex and matchesPattern(URL, Pattern) on the public abstract AbstractClassPathModelFinder are replaced by protected matchesWildcard(URL, String). No code in the repository used them.

Verification: 39 globs by 46 inputs plus a 300,000-pair fuzz compared with the old regex path; all differences come from the unquoted characters above. GlobMatcherTest adds 64 cases and the module gains its first DirectoryModelFinderTest. opennlp-model-resolver: 119 tests in each of its three surefire executions, with checkstyle, offline, -Dopennlp.forkCount=1.

OPENNLP-1932

@rzo1 rzo1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Little time, so here is a GPT 5.6-sol review instead for now

Request changes. The protected API removal breaks downstream subclasses.

Validation across the combined stack: 1,856 targeted tests, zero failures, one skipped.

@krickert
krickert force-pushed the OPENNLP-1932-model-resolver-glob branch from 8913d04 to e7e5f06 Compare September 15, 2026 16:00
@rzo1

rzo1 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Here are some additional comments. The new matcher is correct and a real improvement: it agrees with a reference DP on 1M random and 87M exhaustive pairs, it is linear where the old regex could hang, and typical *.bin matching is about 4x faster. The issues are the deprecated shims, the description and the docs.

Blocking

  1. AbstractClassPathModelFinder.java:178-209. The deprecated asRegex shim does not "restore the regex contract" (commit e7e5f06). It returns (?s) plus quoted runs instead of 2.x's .*opennlp-models-.*\.jar. A third-party subclass that fed regex syntax through it (*.(bin|onnx)) or relied on . stopping at line terminators gets different results (300k pairs old vs new asRegex: 20,106 differences with metacharacters, 61,187 with line terminators), and null now throws IAE instead of NPE. testLegacySubclassStillFilters runs against the new asRegex, so it doesn't prove compatibility, and the shim adds about 45 lines, 3 constants and a static helper to code marked for removal. Either remove both methods in 3.0.0 and note it, or keep the old bodies verbatim with only @Deprecated(since = "3.0.0", forRemoval = true) and @deprecated Use {@link #matchesWildcard(URL, String)}. The OPENNLP-1935: Add a checkstyle guard for java.util.regex in production code #1282 suppression comment ("subclasses written for them see no change") is false for the same reason.

  2. PR description. It is out of date on four points:

    • asRegex/matchesPattern "are replaced": they are still there, deprecated (:177, :223), and matchesWildcard is new protected API (:155).
    • "as before, not crossing line terminators": GlobMatcher.java:57-71 lets * and ? match \n \r U+0085 U+2028 U+2029, and GlobMatcherTest.java:78-88 pins it. That is a second intended divergence; say that the built-in finders can't hit it (Path.toUri() encodes \n, and a raw \n in a jar entry name throws URISyntaxException and is dropped at :262), while subclasses calling matchesWildcard with lenient URLs can.
    • "all differences come from the unquoted characters" was only true for an earlier commit.
    • "class path split … with String.split semantics": splitClassPath (SimpleClassPathModelFinder.java:177) drops leading and inner empty entries (":::abb" gives [abb], old [, , , abb]). No practical effect, since a cwd URL never matches *…jar, but the text is wrong.

    Rewrite it. Suggested title: "OPENNLP-1932: Model finders treat regex metacharacters in jar and resource masks literally".

  3. model-loading.xml:165-171. "the finders put an asterisk in front of it themselves" and "every other character … stands for itself" hold only for SimpleClassPathModelFinder/DirectoryModelFinder. The example right above (:150) uses ClassgraphModelFinder, which passes the mask to ClassGraph with its own glob rules. Checked against ClassGraph 4.8.194: models-pos-en-*.jar finds 0 jars there (Simple would match), and opennlp-models-pos-en-?.?.?.jar finds 0 (Simple matches). Scope the paragraph to the two finders and say ClassgraphModelFinder follows ClassGraph. Also say the mask is compared with the percent-encoded URL file part, so a space or non-ASCII character in a directory becomes %20/%C3%A9 and a mask containing the raw character never matches; drop or qualify the "outside the BMP counts as one character" sentence.

Minor

  • AbstractClassPathModelFinder.java:71 vs :155/:178/:224. The constructor still uses Objects.requireNonNull (NPE) while the new and deprecated methods throw IAE, and GlobMatcher.java:46/49 uses inline message literals while this class declares constants. Either drop it or align all.
  • GlobMatcher.java:25, :44. A new class and static helper for one caller, and "Glob" suggests java.nio.file.PathMatcher syntax ({a,b}, [..], escapes, * not crossing /), while the API and docs say "wildcard". Fold it into a private instance method of AbstractClassPathModelFinder, or rename it WildcardMatcher. (Using getPathMatcher("glob:…") would be wrong: glob:*.bin doesn't match file:/x.jar!/models/en.bin, and it would bring back metacharacters.)
  • GlobMatcher.java:45-50. The null checks repeat those in matchesWildcard. Validate at the protected boundary only.
  • GlobMatcher.java:51-52. codePoints().toArray() allocates two int[] per call, twice per jar entry per findModels, and the constant jarWildcard is decoded again for every classpath URL. Walk the String with codePointAt/Character.charCount.
  • AbstractClassPathModelFinder.java:43, :150. The class Javadoc still says only "Wildcard search is supported by using asterisk symbol", and matchesWildcard says ? matches "exactly one character" (it's one code point). Document *, ?, and that there is no escape character.
  • AbstractClassPathModelFinder.java:174-175, :220-221. "Matching no longer needs a regular expression" is migration narrative. Use @deprecated Use {@link #matchesWildcard(URL, String)} instead.
  • AbstractClassPathModelFinder.java:204, SimpleClassPathModelFinder.java:177. No need to be static.
  • GlobMatcherTest.java:141-300. newProbeFinder, LegacyFinder, and the asRegex/matchesPattern/matchesWildcard tests exercise AbstractClassPathModelFinder. Move them to an AbstractClassPathModelFinderTest. Also:
    • :226 and :231 use fully qualified java.util.ArrayList and java.net.URISyntaxException; import them.
    • @SuppressWarnings("removal") is only on :223, but :178, :192 and :278 also call the deprecated methods.
    • :184-185 repeat the asserts just above them.
    • The "previous API" wording at :206 and :241 won't make sense in five years.
  • GlobMatcherTest.java. Pin the linear worst case, the one real improvement here, e.g. assertTimeoutPreemptively with *a*a*a*b against 100k as. The old regex .*a.*a.*a.*b on 400 as took 2.7 s, and *?*?*?*?*?*?*?*?b on 100 chars did not finish in 110 s.
  • DirectoryModelFinderTest.java:107. The hard-coded 4 duplicates the number of opennlp-models-* test dependencies. Assert against the number of jars copied in @BeforeAll.
  • Recurs from OPENNLP-1928: Stop EmojiCharSequenceNormalizer from blanking hyphens and BMP characters; reject malformed CoNLL-U multiword ids #1275. Commit 2c8d32b briefly made this PR a caller of StringUtil.isLineTerminator and e7e5f06 removed it again, so that method is still public API with no outside caller (OPENNLP-1928: Stop EmojiCharSequenceNormalizer from blanking hyphens and BMP characters; reject malformed CoNLL-U multiword ids #1275 blocking 7).

Verified:

  • No other public or protected member changed. The only in-repo subclasses are DirectoryModelFinder, SimpleClassPathModelFinder and ClassgraphModelFinder, and none use the deprecated methods.
  • DirectoryModelFinder file walking is unchanged; dropping the non-thread-safe pattern cache is a plus.
  • ? handling of surrogate pairs matches the old ..
  • The pom only adds test-scoped junit-jupiter-params, with its version managed in the root pom.

1 similar comment
@rzo1

rzo1 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Here are some additional comments. The new matcher is correct and a real improvement: it agrees with a reference DP on 1M random and 87M exhaustive pairs, it is linear where the old regex could hang, and typical *.bin matching is about 4x faster. The issues are the deprecated shims, the description and the docs.

Blocking

  1. AbstractClassPathModelFinder.java:178-209. The deprecated asRegex shim does not "restore the regex contract" (commit e7e5f06). It returns (?s) plus quoted runs instead of 2.x's .*opennlp-models-.*\.jar. A third-party subclass that fed regex syntax through it (*.(bin|onnx)) or relied on . stopping at line terminators gets different results (300k pairs old vs new asRegex: 20,106 differences with metacharacters, 61,187 with line terminators), and null now throws IAE instead of NPE. testLegacySubclassStillFilters runs against the new asRegex, so it doesn't prove compatibility, and the shim adds about 45 lines, 3 constants and a static helper to code marked for removal. Either remove both methods in 3.0.0 and note it, or keep the old bodies verbatim with only @Deprecated(since = "3.0.0", forRemoval = true) and @deprecated Use {@link #matchesWildcard(URL, String)}. The OPENNLP-1935: Add a checkstyle guard for java.util.regex in production code #1282 suppression comment ("subclasses written for them see no change") is false for the same reason.

  2. PR description. It is out of date on four points:

    • asRegex/matchesPattern "are replaced": they are still there, deprecated (:177, :223), and matchesWildcard is new protected API (:155).
    • "as before, not crossing line terminators": GlobMatcher.java:57-71 lets * and ? match \n \r U+0085 U+2028 U+2029, and GlobMatcherTest.java:78-88 pins it. That is a second intended divergence; say that the built-in finders can't hit it (Path.toUri() encodes \n, and a raw \n in a jar entry name throws URISyntaxException and is dropped at :262), while subclasses calling matchesWildcard with lenient URLs can.
    • "all differences come from the unquoted characters" was only true for an earlier commit.
    • "class path split … with String.split semantics": splitClassPath (SimpleClassPathModelFinder.java:177) drops leading and inner empty entries (":::abb" gives [abb], old [, , , abb]). No practical effect, since a cwd URL never matches *…jar, but the text is wrong.

    Rewrite it. Suggested title: "OPENNLP-1932: Model finders treat regex metacharacters in jar and resource masks literally".

  3. model-loading.xml:165-171. "the finders put an asterisk in front of it themselves" and "every other character … stands for itself" hold only for SimpleClassPathModelFinder/DirectoryModelFinder. The example right above (:150) uses ClassgraphModelFinder, which passes the mask to ClassGraph with its own glob rules. Checked against ClassGraph 4.8.194: models-pos-en-*.jar finds 0 jars there (Simple would match), and opennlp-models-pos-en-?.?.?.jar finds 0 (Simple matches). Scope the paragraph to the two finders and say ClassgraphModelFinder follows ClassGraph. Also say the mask is compared with the percent-encoded URL file part, so a space or non-ASCII character in a directory becomes %20/%C3%A9 and a mask containing the raw character never matches; drop or qualify the "outside the BMP counts as one character" sentence.

Minor

  • AbstractClassPathModelFinder.java:71 vs :155/:178/:224. The constructor still uses Objects.requireNonNull (NPE) while the new and deprecated methods throw IAE, and GlobMatcher.java:46/49 uses inline message literals while this class declares constants. Either drop it or align all.
  • GlobMatcher.java:25, :44. A new class and static helper for one caller, and "Glob" suggests java.nio.file.PathMatcher syntax ({a,b}, [..], escapes, * not crossing /), while the API and docs say "wildcard". Fold it into a private instance method of AbstractClassPathModelFinder, or rename it WildcardMatcher. (Using getPathMatcher("glob:…") would be wrong: glob:*.bin doesn't match file:/x.jar!/models/en.bin, and it would bring back metacharacters.)
  • GlobMatcher.java:45-50. The null checks repeat those in matchesWildcard. Validate at the protected boundary only.
  • GlobMatcher.java:51-52. codePoints().toArray() allocates two int[] per call, twice per jar entry per findModels, and the constant jarWildcard is decoded again for every classpath URL. Walk the String with codePointAt/Character.charCount.
  • AbstractClassPathModelFinder.java:43, :150. The class Javadoc still says only "Wildcard search is supported by using asterisk symbol", and matchesWildcard says ? matches "exactly one character" (it's one code point). Document *, ?, and that there is no escape character.
  • AbstractClassPathModelFinder.java:174-175, :220-221. "Matching no longer needs a regular expression" is migration narrative. Use @deprecated Use {@link #matchesWildcard(URL, String)} instead.
  • AbstractClassPathModelFinder.java:204, SimpleClassPathModelFinder.java:177. No need to be static.
  • GlobMatcherTest.java:141-300. newProbeFinder, LegacyFinder, and the asRegex/matchesPattern/matchesWildcard tests exercise AbstractClassPathModelFinder. Move them to an AbstractClassPathModelFinderTest. Also:
    • :226 and :231 use fully qualified java.util.ArrayList and java.net.URISyntaxException; import them.
    • @SuppressWarnings("removal") is only on :223, but :178, :192 and :278 also call the deprecated methods.
    • :184-185 repeat the asserts just above them.
    • The "previous API" wording at :206 and :241 won't make sense in five years.
  • GlobMatcherTest.java. Pin the linear worst case, the one real improvement here, e.g. assertTimeoutPreemptively with *a*a*a*b against 100k as. The old regex .*a.*a.*a.*b on 400 as took 2.7 s, and *?*?*?*?*?*?*?*?b on 100 chars did not finish in 110 s.
  • DirectoryModelFinderTest.java:107. The hard-coded 4 duplicates the number of opennlp-models-* test dependencies. Assert against the number of jars copied in @BeforeAll.
  • Recurs from OPENNLP-1928: Stop EmojiCharSequenceNormalizer from blanking hyphens and BMP characters; reject malformed CoNLL-U multiword ids #1275. Commit 2c8d32b briefly made this PR a caller of StringUtil.isLineTerminator and e7e5f06 removed it again, so that method is still public API with no outside caller (OPENNLP-1928: Stop EmojiCharSequenceNormalizer from blanking hyphens and BMP characters; reject malformed CoNLL-U multiword ids #1275 blocking 7).

Verified:

  • No other public or protected member changed. The only in-repo subclasses are DirectoryModelFinder, SimpleClassPathModelFinder and ClassgraphModelFinder, and none use the deprecated methods.
  • DirectoryModelFinder file walking is unchanged; dropping the non-thread-safe pattern cache is a plus.
  • ? handling of surrogate pairs matches the old ..
  • The pom only adds test-scoped junit-jupiter-params, with its version managed in the root pom.

@krickert
krickert force-pushed the OPENNLP-1932-model-resolver-glob branch from edb46b6 to a363b77 Compare September 16, 2026 06:01
…in DefaultPOSContextGenerator

Add pinning tests for the accept and reject sides of both predicates.
… checks in FeatureGeneratorUtil

Add pinning tests for the capPeriod accept and reject sides.
…enPatternFeatureGenerator

Add a pinning test that non-letter sub-tokens do not produce st= features.
… char scan

Matches (.+)-\w+ semantics: group(1) is everything before the last hyphen,
the hyphen must not be at index 0, and the suffix must be non-empty word
chars. Add pinning tests for outcomes without hyphen, hyphen at index 0,
empty suffix, non-word suffix, and the normal accept case.
…n BrownCluster

Replicates String.split(\t) semantics, including dropped trailing empty fields.
…explicit char scans in TokenSampleStream

splitOnWhitespace replicates String.split(\\s+): a leading whitespace run
yields one empty leading field, runs collapse, and trailing empty fields are
dropped.
…mojiCharSequenceNormalizer

The replaced pattern contains a high surrogate range, so the regex engine
matches whole code points in the flattened range [U+D83C, U+10FC00]. The
replacement scans code points, collapses each maximal matching run into a
single space, and copies non-matching code points verbatim. Add pinning
tests for unpaired surrogates, BMP chars above U+D83C, and supplementary
code points beyond U+10FC00.
…xplicit scans in ConlluStream

splitOnHyphen replicates String.split("-"): every hyphen is a boundary,
empty fields between consecutive hyphens are kept, and trailing empty
fields are dropped.

extractTextLang replicates find() of text_([a-z]{2,3}): the first
occurrence of "text_" followed by two to three ASCII lowercase letters,
preferring three.
…ss scans in ParserTool

The two replaceAll passes are replicated by two cursor passes with the
same leftmost-first resume-after-match semantics, which matters for
overlapping pairs such as "x((" or "((a)(b))": a pair starting at the
second char of a match is only reconsidered by the second pass.
…cans in DownloadUtil

parseChecksum now scans to the first ASCII whitespace character,
replicating split(\s)[0] on the trimmed content.

extractLinks replicates find() of the <a href="(.*?)">(.*?)</a> pattern
with CASE_INSENSITIVE and DOTALL flags: the href value ends at the first
"> and the first case-insensitive </a> closes the match, so nested link
markup is swallowed by the outer match.
…meric patterns with explicit scans in ADNameSampleStream

splitOnWhitespace and splitOnUnderscores replicate run-based splitting: a
leading separator run yields one empty leading field, trailing empty
fields are dropped, and an all-separator input yields no fields.

matchHyphenatedToken replicates the three-branch hyphen pattern at code
point granularity, isAlphaNumeric replicates ^[\p{L}\p{Nd}]+$ via
Character.isLetter and Character.isDigit, and tagContent replicates
matches() of <(NER:)?(.*?)> including its optional NER: prefix.
…OSSampleStream

replaceWhitespaceWithEquals replicates replaceAll("=") of the \s+
pattern: every run of ASCII whitespace, including leading and trailing
runs, is replaced by a single equals sign.
…tenceSampleStream

parseTextAndParagraph replicates matches() of the
^(?:[a-zA-Z\-]*(\d+)).*?p=(\d+).* pattern: after the optional ASCII
letters and hyphens, the text id is the first ASCII digit run and the
paragraph id is the digit run after the first "p=" that is followed by
at least one digit.
…entenceStream

replaceGuillemetPunctuation replicates replaceAll of the »\s+ punct
patterns: every run of ASCII whitespace between » and the punctuation
character is removed.

parsePunctuationLine replicates matches() of the ^(=*)(\W+)$ pattern:
the line consists of leading equals signs followed by one or more
non-word characters, where a word character is an ASCII letter, digit,
or underscore. A line of only equals signs matches, with the last
equals sign as lexeme.
Adds StringUtil.isAsciiWhitespace, splitOnAsciiWhitespace,
containsAsciiUpperCase, and containsAsciiDigit and removes the copies
from the AD streams, the English TokenSampleStream, DownloadUtil, and
the POS and lemmatizer context generators. NameFinderME.extractNameType
delegates to BioCodec.

Cases the new tests found first: the TokenSampleStream split returned
one empty token for a whitespace-only line where the original split
returned none, and matchHyphenatedToken accepted a single hyphen.
BrownCluster.splitTabs now removes all trailing empty fields, as
String.split does.

Each helper has a test, parameterized where the inputs are a table,
with the reject side and the edge cases: empty input, leading and
trailing separators, non-ASCII spaces and digits, and
supplementary-plane characters. Helpers only called from instance
methods are no longer static; the block comments on the helpers are
now Javadoc that states the behavior.
… quirks

Scans now do what the code meant instead of what the regular expression
would accept:

- EmojiCharSequenceNormalizer replaces only supplementary-plane code
  points. BMP characters, hyphens and unpaired surrogates are kept.
- ParserTool separates brackets on Unicode whitespace in one pass, so
  brackets that follow each other are all spaced and no space is doubled.
- The FeatureGeneratorUtil capital-period feature needs one capital and
  one period; a trailing line break no longer qualifies.
- BioCodec rejects a line terminator at any position of an outcome type.
- DownloadUtil accepts a checksum file with leading Unicode whitespace
  and treats a blank file as missing.
- The AD streams split on the toolkit whitespace definition, drop empty
  underscore parts and judge punctuation lines by code point.
- ConlluStream fails a malformed multiword token id with an
  InvalidFormatException instead of skipping it.

StringUtil adds isAsciiLetter, isAsciiDigit, endOfAsciiDigits,
isLineTerminator and indexOfLineTerminator, shared by BioCodec,
ADSentenceSampleStream and ConlluStream here and needed by the related
OPENNLP-1929 to OPENNLP-1935 branches. isAsciiWhitespace and
splitOnAsciiWhitespace are removed; callers use the Unicode-aware
StringUtil.isWhitespace and WhitespaceTokenizer.

The manual documents the bracket handling of the parser tool, the
CoNLL-U multiword id and language code rules, the AD reader rules and
the emoji normalizer in the language detector chapter. Tests cover the
accept and reject side of each scan, the Unicode plane boundaries and
Unicode whitespace separators.
…ssPathModelFinder

The fallback that reads java.class.path split the value with two compiled
Patterns, ";" on Windows and ":" elsewhere. A package-private splitClassPath
now walks the string once and cuts at the separator character, keeping the
String.split result for that separator: a leading separator gives one empty
first element, empty elements between consecutive separators stay, trailing
empty elements are dropped, separator-only input gives an empty array, and
empty input gives a single empty element. The test table covers those cases
for both separators and checks each row against String.split. The module
gains the managed junit-jupiter-params test dependency for the table.
AbstractClassPathModelFinder turned a wildcard such as "*opennlp-models-*"
into a regular expression by escaping "." and rewriting "*" to ".*" and "?"
to ".", then compiled it and called matches() on the file part of each URL.
The package-private GlobMatcher now walks the wildcard and the input by code
point: "*" absorbs any run of characters including none, "?" takes exactly
one, and every other character stands for itself. As with the old ".", neither
wildcard crosses a line feed, carriage return, next line, line separator, or
paragraph separator, and the whole input must be covered. The protected
asRegex and matchesPattern(URL, Pattern) are replaced by matchesWildcard(URL,
String); DirectoryModelFinder and SimpleClassPathModelFinder keep the plain
wildcard strings instead of compiled patterns, and the pattern cache in
DirectoryModelFinder goes away because there is nothing left to compile.

Characters the old code never escaped, such as parentheses, brackets, braces,
"+", "|", "^", "$", and backslash, had regular expression meaning before or
made Pattern.compile fail; they are now literal. GlobMatcherTest covers the
accept and reject sides, dots, those characters, each line terminator, and
supplementary-plane characters.
DirectoryModelFinder had no test. The new test copies the opennlp-models
jars from the test class path into a temporary directory one level below the
scanned root, runs the shared finder assertions against it, and checks the
non-recursive mode, a narrowing jar prefix, an unknown prefix, and the null
directory rejection.
GlobMatcherTest now calls asRegex and matchesPattern. Test compile fails
with cannot find symbol, the same break a downstream subclass would hit.
Restores protected asRegex and matchesPattern as deprecated shims over
GlobMatcher and guards null inputs. Old regex strings no longer apply.
Adds parameterized null glob and input cases plus finder null checks.
All fail fast with NullPointerException carrying a must not be null note.
The private copy was byte-identical to the rewritten 1928 helper
(same five terminators), so calls now go to StringUtil and the
duplicate is gone. GlobMatcherTest still pins the ?-never-matches-a-
terminator contract; model-resolver suite green.
…behavior (red)

A wildcard covers a line terminator like any other character, empty
class path entries are skipped wherever they appear, null arguments
fail with an IllegalArgumentException, and the deprecated asRegex and
matchesPattern pair keeps its regular expression contract so a subclass
compiled against the previous API filters as before. The tests fail on
the current implementation.
… contract of the deprecated matchers

GlobMatcher treats a line terminator like any other character, since a
wildcard for a file name has no reason to stop at one, and it reports
a null argument with an IllegalArgumentException as the rest of the
module does. splitClassPath skips empty entries wherever they appear
because none of them names a jar file.

asRegex again returns a regular expression, with the literal characters
quoted and with DOTALL so that it accepts what matchesWildcard accepts;
matchesPattern evaluates the Pattern as a regular expression over the
complete file part. Both are deprecated for removal in favor of
matchesWildcard, so a subclass compiled with the previous API links and
filters as before. The manual describes the wildcard syntax and the
class path split.
…oded names

The glob matcher is checked with consecutive stars, a glob longer than
the name, regex syntax as plain characters, path separators in the glob,
jar entry paths, drive letters in the file part of a file URL, and
percent-encoded file names, on the accept and the reject side.

The deprecated asRegex translation is compared with the matcher on each
of those rows, and matchesWildcard is checked on jar, file and http URLs
together with the deprecated asRegex and matchesPattern pair. The file
part of a jar URL is the inner URL with its scheme, and a query string is
part of the file part while a fragment is not.

Class path splitting is checked with drive letters, UNC paths, spaces,
percent signs, jar entry suffixes and line breaks in entries.
@krickert
krickert force-pushed the OPENNLP-1932-model-resolver-glob branch from a363b77 to 4bebe3c Compare September 16, 2026 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants