This is an automated email from the ASF dual-hosted git repository. mawiesne pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/opennlp.git
commit 436f44183b7e730b1a4053b96d3c29e250432fe2 Author: Martin Wiesner <[email protected]> AuthorDate: Sat Mar 14 21:50:22 2026 +0100 OPENNLP-1735: Upgrade minimum JDK level to 21 LTS - adjusts pom.xml - adjusts GH actions - replace new Locale(..) with Locale.of(..) - replaces new URL(..) with new URI(..).toURL() --- .github/workflows/license.yml | 4 +- .github/workflows/maven.yml | 8 +-- .github/workflows/publish-snapshots.yml | 4 +- .github/workflows/shell-tests.yml | 18 +++---- README.md | 10 ++-- .../opennlp/tools/AbstractModelLoaderTest.java | 14 ++++- .../opennlp/tools/EnabledWhenCDNAvailable.java | 7 ++- .../formats/NameFinderCensus90NameStream.java | 4 +- .../opennlp/tools/formats/conllu/ConlluStream.java | 2 +- .../tools/formats/conllu/ConlluStreamTest.java | 6 +-- .../models/simple/SimpleClassPathModelFinder.java | 20 ++++--- .../main/java/opennlp/tools/util/DownloadUtil.java | 63 +++++++++++++--------- .../opennlp/tools/AbstractModelLoaderTest.java | 14 ++++- .../opennlp/tools/EnabledWhenCDNAvailable.java | 7 ++- .../sentdetect/AbstractSentenceDetectorTest.java | 8 +-- .../tools/tokenize/TokenizerFactoryTest.java | 8 +-- .../java/opennlp/uima/normalizer/NumberUtil.java | 4 +- .../src/test/java/opennlp/uima/AbstractIT.java | 12 ++++- .../opennlp/tools/EnabledWhenCDNAvailable.java | 7 ++- .../tools/namefind/AbstractNameFinderTest.java | 12 ++++- .../opennlp/tools/util/DownloadParserTest.java | 44 +++++++++------ pom.xml | 8 +-- 22 files changed, 186 insertions(+), 98 deletions(-) diff --git a/.github/workflows/license.yml b/.github/workflows/license.yml index 9ebde146..b3f0c245 100644 --- a/.github/workflows/license.yml +++ b/.github/workflows/license.yml @@ -27,10 +27,10 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - name: Cache Maven packages diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index bf7aa0d4..a0ad6a78 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -27,14 +27,14 @@ on: jobs: build: runs-on: ${{ matrix.os }} - continue-on-error: ${{ matrix.experimental }} strategy: + fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] - java: [ 17, 21, 25 ] + java: [ 21, 25 ] experimental: [false] # include: -# - java: 25-ea +# - java: 26-ea # os: ubuntu-latest # experimental: true @@ -54,6 +54,6 @@ jobs: distribution: temurin java-version: ${{ matrix.java }} - name: Build with Maven - run: mvn -V clean test install --show-version --batch-mode --no-transfer-progress -Pjacoco -Pci + run: mvn -V clean test verify --show-version --batch-mode --no-transfer-progress -Pjacoco -Pci - name: Jacoco run: mvn jacoco:report diff --git a/.github/workflows/publish-snapshots.yml b/.github/workflows/publish-snapshots.yml index b03082a2..c01b974b 100644 --- a/.github/workflows/publish-snapshots.yml +++ b/.github/workflows/publish-snapshots.yml @@ -43,8 +43,8 @@ jobs: - name: Setup Java uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: - distribution: adopt - java-version: 17 + distribution: temurin + java-version: 21 - id: extract_version name: Extract version shell: bash diff --git a/.github/workflows/shell-tests.yml b/.github/workflows/shell-tests.yml index 5cacc0a9..888cc197 100644 --- a/.github/workflows/shell-tests.yml +++ b/.github/workflows/shell-tests.yml @@ -36,14 +36,14 @@ jobs: sudo apt-get update sudo apt-get install -y bats - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin - java-version: 17 + java-version: 21 - name: Build with Maven - run: mvn -V clean install --no-transfer-progress -Pci -DskipTests=true + run: mvn -V clean verify --no-transfer-progress -Pci -DskipTests=true - name: Find and Extract OpenNLP Distribution run: | @@ -91,14 +91,14 @@ jobs: brew update brew install bats-core - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin - java-version: 17 + java-version: 21 - name: Build with Maven - run: mvn -V clean install --no-transfer-progress -Pci -DskipTests=true + run: mvn -V clean verify --no-transfer-progress -Pci -DskipTests=true - name: Find and Extract OpenNLP Distribution run: | @@ -138,14 +138,14 @@ jobs: Import-Module Pester shell: pwsh - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin - java-version: 17 + java-version: 21 - name: Build with Maven - run: mvn -V clean install --no-transfer-progress -Pci -DskipTests=true + run: mvn -V clean verify --no-transfer-progress -Pci -DskipTests=true - name: Run Pester Tests # (one step to avoid environment issues on Windows) run: | diff --git a/README.md b/README.md index e263f2b6..060792a4 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ For users of the traditional CLI toolkit, nothing changes with the 3.x release l The Apache OpenNLP team is planning to change the package namespace from `opennlp` to `org.apache.opennlp` in a future release (potentially 4.x). This change will be made to align with standard Java package naming conventions and to avoid potential conflicts with other libraries. -In addition, the Apache OpenNLP team is considering the raise of the minimal Java version to JDK 21+ in a future release (potentially 4.x) +In addition, the Apache OpenNLP team raised the minimal Java version to JDK 21+ for the 3.0.0 release to take advantage of the latest language features and improvements. ## Branches and Merging Strategy @@ -141,8 +141,10 @@ To support ongoing development and stable maintenance of Apache OpenNLP, the pro ### Branch overview -- **`main`**: Development branch for version **3.0** and beyond. All feature development and 3.x releases occur here. -- **`opennlp-2.x`**: Maintains the stable **2.x** release line. This branch will receive selective updates and patch releases. +- **`main`**: Development branch for version **3.0** and beyond. + All feature development and 3.x releases occur here. Minimum Java level: 21. +- **`opennlp-2.x`**: Maintains the stable **2.x** release line. + This branch will receive selective updates and patch releases. Minimum Java level: 17. ### Workflow summary @@ -159,7 +161,7 @@ To support ongoing development and stable maintenance of Apache OpenNLP, the pro ## Building OpenNLP -At least JDK 17 and Maven 3.3.9 are required to build the library. +For the main branch, at least JDK 21 and Maven 3.9.x are required to build the library. After cloning the repository go into the destination directory and run: diff --git a/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/AbstractModelLoaderTest.java b/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/AbstractModelLoaderTest.java index 059a07d3..8da15743 100644 --- a/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/AbstractModelLoaderTest.java +++ b/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/AbstractModelLoaderTest.java @@ -20,6 +20,8 @@ package opennlp.tools; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -47,11 +49,19 @@ public abstract class AbstractModelLoaderTest { "sv", "tr", "uk"); protected static void downloadVersion15Model(String modelName) throws IOException { - downloadModel(new URL(BASE_URL_MODELS_V15 + modelName)); + downloadModel(toModelURL(BASE_URL_MODELS_V15 + modelName)); } protected static void downloadVersion183Model(String modelName) throws IOException { - downloadModel(new URL(BASE_URL_MODELS_V183 + modelName)); + downloadModel(toModelURL(BASE_URL_MODELS_V183 + modelName)); + } + + private static URL toModelURL(String location) throws IOException { + try { + return new URI(location).toURL(); + } catch (URISyntaxException e) { + throw new IOException(e); + } } private static void downloadModel(URL url) throws IOException { diff --git a/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java b/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java index fccc5526..d15f2707 100644 --- a/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java +++ b/opennlp-core/opennlp-cli/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java @@ -22,6 +22,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; @@ -57,7 +59,7 @@ public @interface EnabledWhenCDNAvailable { socket.connect(new InetSocketAddress(host, 443), TIMEOUT_MS); // Then, try to check the HTTP status by making an HTTPS request - final URL url = new URL("https://" + host); + final URL url = new URI("https://" + host).toURL(); final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setConnectTimeout(TIMEOUT_MS); connection.setReadTimeout(TIMEOUT_MS); @@ -72,6 +74,9 @@ public @interface EnabledWhenCDNAvailable { "Resource (CDN) reachable, but HTTP status code: " + statusCode); } + } catch (URISyntaxException e) { + return ConditionEvaluationResult.disabled( + "Resource (CDN) identifier has an invalid form."); } catch (IOException e) { return ConditionEvaluationResult.disabled( "Resource (CDN) unreachable."); diff --git a/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/NameFinderCensus90NameStream.java b/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/NameFinderCensus90NameStream.java index 43fe6f38..e8acc2c4 100644 --- a/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/NameFinderCensus90NameStream.java +++ b/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/NameFinderCensus90NameStream.java @@ -58,7 +58,7 @@ public class NameFinderCensus90NameStream implements ObjectStream<StringList> { * input file to be attached to this class. */ public NameFinderCensus90NameStream(ObjectStream<String> lineStream) { - this.locale = new Locale("en"); // locale is English + this.locale = Locale.of("en"); // locale is English this.encoding = Charset.defaultCharset(); // todo how do we find the encoding for an already open ObjectStream() ? this.lineStream = lineStream; @@ -76,7 +76,7 @@ public class NameFinderCensus90NameStream implements ObjectStream<StringList> { */ public NameFinderCensus90NameStream(InputStreamFactory in, Charset encoding) throws IOException { - this.locale = new Locale("en"); // locale is English + this.locale = Locale.of("en"); // locale is English this.encoding = encoding; this.lineStream = new PlainTextByLineStream(in, this.encoding); } diff --git a/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/conllu/ConlluStream.java b/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/conllu/ConlluStream.java index e4a9d8fa..17c991e6 100644 --- a/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/conllu/ConlluStream.java +++ b/opennlp-core/opennlp-formats/src/main/java/opennlp/tools/formats/conllu/ConlluStream.java @@ -240,7 +240,7 @@ public class ConlluStream implements ObjectStream<ConlluSentence> { throw new InvalidFormatException(e); } if (!lang.isEmpty()) { - textLang.put(new Locale(lang), secondPart); + textLang.put(Locale.of(lang), secondPart); } else { throw new InvalidFormatException(String.format("Locale language code is invalid: %s", lang)); diff --git a/opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluStreamTest.java b/opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluStreamTest.java index 5545f321..5716a84a 100644 --- a/opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluStreamTest.java +++ b/opennlp-core/opennlp-formats/src/test/java/opennlp/tools/formats/conllu/ConlluStreamTest.java @@ -83,8 +83,8 @@ public class ConlluStreamTest extends AbstractConlluSampleStreamTest<SentenceSam Assertions.assertEquals(3, sent3.getWordLines().size()); Assertions.assertTrue(sent3.isNewParagraph()); Map<Object, Object> textLang3 = new HashMap<>(); - textLang3.put(new Locale("fr"), "VoilĂ ce qui nous est parvenu par la tradition orale."); - textLang3.put(new Locale("en"), "This is what is heard."); + textLang3.put(Locale.of("fr"), "VoilĂ ce qui nous est parvenu par la tradition orale."); + textLang3.put(Locale.of("en"), "This is what is heard."); Assertions.assertEquals(Optional.of(textLang3) , sent3.getTextLang()); @@ -99,7 +99,7 @@ public class ConlluStreamTest extends AbstractConlluSampleStreamTest<SentenceSam Assertions.assertTrue(sent4.isNewParagraph()); Assertions.assertEquals(Optional.of("mf920901-001"), sent4.getDocumentId()); Assertions.assertEquals(Optional.of("mf920901-001-p1"), sent4.getParagraphId()); - Assertions.assertEquals(Optional.of(Collections.singletonMap(new Locale("en"), + Assertions.assertEquals(Optional.of(Collections.singletonMap(Locale.of("en"), "Slovak constitution: pros and cons")) , sent4.getTextLang()); diff --git a/opennlp-core/opennlp-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java b/opennlp-core/opennlp-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java index ebc7da9f..0a85fb98 100644 --- a/opennlp-core/opennlp-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java +++ b/opennlp-core/opennlp-models/src/main/java/opennlp/tools/models/simple/SimpleClassPathModelFinder.java @@ -148,20 +148,28 @@ public class SimpleClassPathModelFinder extends AbstractClassPathModelFinder imp return pattern.matcher(url.getFile()).matches(); } + private static URL toURL(String location) throws IOException { + try { + return new URI(location).toURL(); + } catch (URISyntaxException e) { + throw new IOException(e); + } + } + private List<URI> getURIsFromJar(URL fileUrl, boolean isWindows) throws IOException { final List<URI> uris = new ArrayList<>(); - final URL jarUrl = new URL(JAR + ":" + + final String location = JAR + ":" + (isWindows ? fileUrl.toString().replace("\\", "/") - : fileUrl.toString()) + "!/"); + : fileUrl.toString()) + "!/"; + final URL jarUrl = toURL(location); final JarURLConnection jarConnection = (JarURLConnection) jarUrl.openConnection(); try (JarFile jarFile = jarConnection.getJarFile()) { final Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { final JarEntry entry = entries.nextElement(); if (!entry.isDirectory()) { - final URL entryUrl = new URL(jarUrl + entry.getName()); try { - uris.add(entryUrl.toURI()); + uris.add(new URI(jarUrl + entry.getName())); } catch (URISyntaxException ignored) { //if we cannot convert to URI here, we ignore that entry. } @@ -211,8 +219,8 @@ public class SimpleClassPathModelFinder extends AbstractClassPathModelFinder imp final List<URL> jarUrls = new ArrayList<>(); for (String classPath: matches) { try { - jarUrls.add(new URL(FILE_PREFIX, "", classPath)); - } catch (MalformedURLException ignored) { + jarUrls.add(new URI(FILE_PREFIX, "", classPath, null).toURL()); + } catch (MalformedURLException | URISyntaxException ignored) { //if we cannot parse a URL from the system property, just ignore it... //we couldn't load it anyway } diff --git a/opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/util/DownloadUtil.java b/opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/util/DownloadUtil.java index 03f6f064..7554c064 100644 --- a/opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/util/DownloadUtil.java +++ b/opennlp-core/opennlp-runtime/src/main/java/opennlp/tools/util/DownloadUtil.java @@ -22,6 +22,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -61,7 +63,7 @@ public class DownloadUtil { System.getProperty("OPENNLP_DOWNLOAD_MODEL_PATH", "models/ud-models-1.3/"); private static final String OPENNLP_DOWNLOAD_HOME = "OPENNLP_DOWNLOAD_HOME"; - private static Map<String, Map<ModelType, String>> availableModels; + private static Map<String, Map<ModelType, URL>> availableModels; /** * Checks if a model of the specified {@code modelType} has been downloaded already @@ -71,22 +73,23 @@ public class DownloadUtil { * @param modelType The {@link ModelType type} of model. * @return {@code true} if a model exists locally, {@code false} otherwise. * @throws IOException Thrown if IO errors occurred or the computed hash sum - * of an associated, local model file was incorrect. + * of an associated, local model file was incorrect. */ static boolean existsModel(String language, ModelType modelType) throws IOException { - Map<ModelType, String> modelsByLanguage = getAvailableModels().get(language); + Map<ModelType, URL> modelsByLanguage = getAvailableModels().get(language); if (modelsByLanguage == null) { return false; } else { - final String url = modelsByLanguage.get(modelType); + final URL url = modelsByLanguage.get(modelType); if (url != null) { final Path homeDirectory = getDownloadHome(); - final String filename = url.substring(url.lastIndexOf("/") + 1); + final String extUrl = url.toExternalForm(); + final String filename = extUrl.substring(extUrl.lastIndexOf("/") + 1); final Path localFile = homeDirectory.resolve(filename); boolean exists; if (Files.exists(localFile)) { // if this does not throw the requested model is valid! - validateModel(new URL(url + ".sha512"), localFile); + validateModel(url + ".sha512", localFile); exists = true; } else { exists = false; @@ -112,9 +115,9 @@ public class DownloadUtil { Class<T> type) throws IOException { if (getAvailableModels().containsKey(language)) { - final String url = getAvailableModels().get(language).get(modelType); + final URL url = getAvailableModels().get(language).get(modelType); if (url != null) { - return downloadModel(new URL(url), type); + return downloadModel(url, type); } } @@ -156,7 +159,7 @@ public class DownloadUtil { try (final InputStream in = url.openStream()) { Files.copy(in, localFile, StandardCopyOption.REPLACE_EXISTING); } - validateModel(new URL(url + ".sha512"), localFile); + validateModel(url + ".sha512", localFile); logger.debug("Download complete."); } else { logger.debug("Model file '{}' already exists. Skipping download.", filename); @@ -169,11 +172,12 @@ public class DownloadUtil { } } - public static Map<String, Map<ModelType, String>> getAvailableModels() { + public static Map<String, Map<ModelType, URL>> getAvailableModels() { if (availableModels == null) { try { - availableModels = new DownloadParser(new URL(BASE_URL + MODEL_URI_PATH)).getAvailableModels(); - } catch (MalformedURLException e) { + DownloadParser p = new DownloadParser(new URI(BASE_URL + MODEL_URI_PATH).toURL()); + availableModels = p.getAvailableModels(); + } catch (MalformedURLException | URISyntaxException e) { throw new RuntimeException(e); } } @@ -187,15 +191,21 @@ public class DownloadUtil { * @param downloadedModel the model file to check * @throws IOException thrown if the checksum could not be computed */ - private static void validateModel(URL sha512, Path downloadedModel) throws IOException { - // Download SHA512 checksum file + private static void validateModel(String sha512, Path downloadedModel) throws IOException { String expectedChecksum; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(sha512.openStream()))) { - expectedChecksum = reader.readLine(); + try { + // Download SHA512 checksum file + final URL hashSum = new URI(sha512).toURL(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(hashSum.openStream()))) { + expectedChecksum = reader.readLine(); - if (expectedChecksum != null) { - expectedChecksum = expectedChecksum.split("\\s")[0].trim(); + if (expectedChecksum != null) { + expectedChecksum = expectedChecksum.split("\\s")[0].trim(); + } } + } catch (URISyntaxException use) { + throw new IOException("Expected SHA512 checksum could not be retrieved for " + + downloadedModel.getFileName(), use); } // Validate SHA512 checksum @@ -248,7 +258,8 @@ public class DownloadUtil { this.indexUrl = indexUrl; } - Map<String, Map<ModelType, String>> getAvailableModels() { + Map<String, Map<ModelType, URL>> getAvailableModels() + throws MalformedURLException, URISyntaxException { final Matcher matcher = LINK_PATTERN.matcher(fetchPageIndex()); final List<String> links = new ArrayList<>(); @@ -259,8 +270,9 @@ public class DownloadUtil { return toMap(links); } - private Map<String, Map<ModelType, String>> toMap(List<String> links) { - final Map<String, Map<ModelType, String>> result = new HashMap<>(); + private Map<String, Map<ModelType, URL>> toMap(List<String> links) + throws MalformedURLException, URISyntaxException { + final Map<String, Map<ModelType, URL>> result = new HashMap<>(); for (String link : links) { if (link.endsWith(".bin")) { if (link.contains("de-ud")) { // German @@ -341,10 +353,11 @@ public class DownloadUtil { return result; } - private void addModel(String locale, String link, Map<String, Map<ModelType, String>> result) { - final Map<ModelType, String> models = result.getOrDefault(locale, new HashMap<>()); - final String url = (indexUrl.toString().endsWith("/") ? indexUrl : indexUrl + "/") + link; - + private void addModel(String locale, String link, Map<String, Map<ModelType, URL>> result) + throws URISyntaxException, MalformedURLException { + final Map<ModelType, URL> models = result.getOrDefault(locale, new HashMap<>()); + final String combined = (indexUrl.toString().endsWith("/") ? indexUrl : indexUrl + "/") + link; + final URL url = new URI(combined).toURL(); if (link.contains("sentence")) { models.put(ModelType.SENTENCE_DETECTOR, url); } else if (link.contains("tokens")) { diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/AbstractModelLoaderTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/AbstractModelLoaderTest.java index 059a07d3..8da15743 100644 --- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/AbstractModelLoaderTest.java +++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/AbstractModelLoaderTest.java @@ -20,6 +20,8 @@ package opennlp.tools; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -47,11 +49,19 @@ public abstract class AbstractModelLoaderTest { "sv", "tr", "uk"); protected static void downloadVersion15Model(String modelName) throws IOException { - downloadModel(new URL(BASE_URL_MODELS_V15 + modelName)); + downloadModel(toModelURL(BASE_URL_MODELS_V15 + modelName)); } protected static void downloadVersion183Model(String modelName) throws IOException { - downloadModel(new URL(BASE_URL_MODELS_V183 + modelName)); + downloadModel(toModelURL(BASE_URL_MODELS_V183 + modelName)); + } + + private static URL toModelURL(String location) throws IOException { + try { + return new URI(location).toURL(); + } catch (URISyntaxException e) { + throw new IOException(e); + } } private static void downloadModel(URL url) throws IOException { diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java index fccc5526..d15f2707 100644 --- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java +++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java @@ -22,6 +22,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; @@ -57,7 +59,7 @@ public @interface EnabledWhenCDNAvailable { socket.connect(new InetSocketAddress(host, 443), TIMEOUT_MS); // Then, try to check the HTTP status by making an HTTPS request - final URL url = new URL("https://" + host); + final URL url = new URI("https://" + host).toURL(); final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setConnectTimeout(TIMEOUT_MS); connection.setReadTimeout(TIMEOUT_MS); @@ -72,6 +74,9 @@ public @interface EnabledWhenCDNAvailable { "Resource (CDN) reachable, but HTTP status code: " + statusCode); } + } catch (URISyntaxException e) { + return ConditionEvaluationResult.disabled( + "Resource (CDN) identifier has an invalid form."); } catch (IOException e) { return ConditionEvaluationResult.disabled( "Resource (CDN) unreachable."); diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/sentdetect/AbstractSentenceDetectorTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/sentdetect/AbstractSentenceDetectorTest.java index 64f2a000..d258ea4e 100644 --- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/sentdetect/AbstractSentenceDetectorTest.java +++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/sentdetect/AbstractSentenceDetectorTest.java @@ -30,10 +30,10 @@ import opennlp.tools.util.TrainingParameters; public abstract class AbstractSentenceDetectorTest { - protected static final Locale LOCALE_DUTCH = new Locale("nl"); - protected static final Locale LOCALE_POLISH = new Locale("pl"); - protected static final Locale LOCALE_PORTUGUESE = new Locale("pt"); - protected static final Locale LOCALE_SPANISH = new Locale("es"); + protected static final Locale LOCALE_DUTCH = Locale.of("nl"); + protected static final Locale LOCALE_POLISH = Locale.of("pl"); + protected static final Locale LOCALE_PORTUGUESE = Locale.of("pt"); + protected static final Locale LOCALE_SPANISH = Locale.of("es"); static ObjectStream<SentenceSample> createSampleStream(Locale loc) throws IOException { final String trainingResource; diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenizerFactoryTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenizerFactoryTest.java index 23d2ba7a..41ff5d44 100644 --- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenizerFactoryTest.java +++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenizerFactoryTest.java @@ -42,10 +42,10 @@ import opennlp.tools.util.TrainingParameters; */ public class TokenizerFactoryTest { - private static final Locale LOCALE_DUTCH = new Locale("nl"); - private static final Locale LOCALE_POLISH = new Locale("pl"); - private static final Locale LOCALE_PORTUGUESE = new Locale("pt"); - private static final Locale LOCALE_SPANISH = new Locale("es"); + private static final Locale LOCALE_DUTCH = Locale.of("nl"); + private static final Locale LOCALE_POLISH = Locale.of("pl"); + private static final Locale LOCALE_PORTUGUESE = Locale.of("pt"); + private static final Locale LOCALE_SPANISH = Locale.of("es"); private static ObjectStream<TokenSample> createSampleStream() throws IOException { InputStreamFactory in = new ResourceAsStreamFactory( diff --git a/opennlp-extensions/opennlp-uima/src/main/java/opennlp/uima/normalizer/NumberUtil.java b/opennlp-extensions/opennlp-uima/src/main/java/opennlp/uima/normalizer/NumberUtil.java index 6adf9030..f14df8ec 100644 --- a/opennlp-extensions/opennlp-uima/src/main/java/opennlp/uima/normalizer/NumberUtil.java +++ b/opennlp-extensions/opennlp-uima/src/main/java/opennlp/uima/normalizer/NumberUtil.java @@ -36,7 +36,7 @@ public final class NumberUtil { * @return true if the language is supported */ public static boolean isLanguageSupported(String languageCode) { - Locale locale = new Locale(languageCode); + Locale locale = Locale.of(languageCode); Locale[] possibleLocales = NumberFormat.getAvailableLocales(); @@ -70,7 +70,7 @@ public final class NumberUtil { throw new IllegalArgumentException("Language " + languageCode + " is not supported!"); } - Locale locale = new Locale(languageCode); + Locale locale = Locale.of(languageCode); NumberFormat numberFormat = NumberFormat.getInstance(locale); number = WHITESPACE_PATTERN.matcher(number).replaceAll(""); return numberFormat.parse(number); diff --git a/opennlp-extensions/opennlp-uima/src/test/java/opennlp/uima/AbstractIT.java b/opennlp-extensions/opennlp-uima/src/test/java/opennlp/uima/AbstractIT.java index 4e0c45ef..9d5633dd 100644 --- a/opennlp-extensions/opennlp-uima/src/test/java/opennlp/uima/AbstractIT.java +++ b/opennlp-extensions/opennlp-uima/src/test/java/opennlp/uima/AbstractIT.java @@ -21,6 +21,8 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -71,7 +73,15 @@ abstract class AbstractIT extends AbstractUimaTest { } private static void downloadVersion15Model(String modelName) throws IOException { - downloadModel(new URL(BASE_URL_MODELS_V15 + modelName)); + downloadModel(toModelURL(BASE_URL_MODELS_V15 + modelName)); + } + + private static URL toModelURL(String location) throws IOException { + try { + return new URI(location).toURL(); + } catch (URISyntaxException e) { + throw new IOException(e); + } } private static void downloadModel(URL url) throws IOException { diff --git a/opennlp-tools/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java b/opennlp-tools/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java index fccc5526..d15f2707 100644 --- a/opennlp-tools/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java +++ b/opennlp-tools/src/test/java/opennlp/tools/EnabledWhenCDNAvailable.java @@ -22,6 +22,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; @@ -57,7 +59,7 @@ public @interface EnabledWhenCDNAvailable { socket.connect(new InetSocketAddress(host, 443), TIMEOUT_MS); // Then, try to check the HTTP status by making an HTTPS request - final URL url = new URL("https://" + host); + final URL url = new URI("https://" + host).toURL(); final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); connection.setConnectTimeout(TIMEOUT_MS); connection.setReadTimeout(TIMEOUT_MS); @@ -72,6 +74,9 @@ public @interface EnabledWhenCDNAvailable { "Resource (CDN) reachable, but HTTP status code: " + statusCode); } + } catch (URISyntaxException e) { + return ConditionEvaluationResult.disabled( + "Resource (CDN) identifier has an invalid form."); } catch (IOException e) { return ConditionEvaluationResult.disabled( "Resource (CDN) unreachable."); diff --git a/opennlp-tools/src/test/java/opennlp/tools/namefind/AbstractNameFinderTest.java b/opennlp-tools/src/test/java/opennlp/tools/namefind/AbstractNameFinderTest.java index 47fa4d72..3a0cca4a 100644 --- a/opennlp-tools/src/test/java/opennlp/tools/namefind/AbstractNameFinderTest.java +++ b/opennlp-tools/src/test/java/opennlp/tools/namefind/AbstractNameFinderTest.java @@ -21,6 +21,8 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -112,7 +114,15 @@ abstract class AbstractNameFinderTest { } protected static void downloadVersion15Model(String modelName) throws IOException { - downloadModel(new URL(BASE_URL_MODELS_V15 + modelName)); + downloadModel(toModelURL(BASE_URL_MODELS_V15 + modelName)); + } + + private static URL toModelURL(String location) throws IOException { + try { + return new URI(location).toURL(); + } catch (URISyntaxException e) { + throw new IOException(e); + } } private static void downloadModel(URL url) throws IOException { diff --git a/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java b/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java index b2d360bd..ac04d7d4 100644 --- a/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java +++ b/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java @@ -18,6 +18,8 @@ package opennlp.tools.util; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.Map; import java.util.stream.Stream; @@ -32,6 +34,7 @@ import opennlp.tools.models.ModelType; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; public class DownloadParserTest { @@ -44,20 +47,23 @@ public class DownloadParserTest { final DownloadUtil.DownloadParser downloadParser = new DownloadUtil.DownloadParser(baseUrl); - Map<String, Map<ModelType, String>> result = downloadParser.getAvailableModels(); + try { + Map<String, Map<ModelType, URL>> result = downloadParser.getAvailableModels(); + assertNotNull(result); + assertEquals(36, result.size()); - assertNotNull(result); - assertEquals(36, result.size()); + final Map<ModelType, URL> availableModels = result.get(language); + assertNotNull(availableModels); - final Map<ModelType, String> availableModels = result.get(language); - assertNotNull(availableModels); + for (Map.Entry<ModelType, String> e : expectedModels.entrySet()) { + final URL url = availableModels.get(e.getKey()); + final String expectedUrl = baseUrl + "/" + e.getValue(); - for (Map.Entry<ModelType, String> e : expectedModels.entrySet()) { - final String url = availableModels.get(e.getKey()); - final String expectedUrl = baseUrl + "/" + e.getValue(); - - assertNotNull(url, "A model for the given model type is expected"); - assertEquals(expectedUrl, url); + assertNotNull(url, "A model for the given model type is expected"); + assertEquals(expectedUrl, url.toExternalForm()); + } + } catch (URISyntaxException | MalformedURLException e) { + fail(e); } } @@ -68,12 +74,16 @@ public class DownloadParserTest { } @Test - void testInvalidUrl() throws MalformedURLException { - final DownloadUtil.DownloadParser downloadParser = - new DownloadUtil.DownloadParser(new URL("file:/this/does/not/exist")); - Map<String, Map<ModelType, String>> result = downloadParser.getAvailableModels(); - assertNotNull(result); - assertEquals(0, result.size()); + void testInvalidUrl() { + try { + final DownloadUtil.DownloadParser downloadParser = + new DownloadUtil.DownloadParser(new URI("file:/this/does/not/exist").toURL()); + Map<String, Map<ModelType, URL>> result = downloadParser.getAvailableModels(); + assertNotNull(result); + assertEquals(0, result.size()); + } catch (URISyntaxException | MalformedURLException e) { + fail(e); + } } private URL fromClasspath(String file) { diff --git a/pom.xml b/pom.xml index b85d3a32..98a3df1c 100644 --- a/pom.xml +++ b/pom.xml @@ -221,8 +221,8 @@ <properties> <!-- Build properties --> - <java.version>17</java.version> - <maven.version>3.3.9</maven.version> + <java.version>21</java.version> + <maven.version>3.9.0</maven.version> <maven.compiler.release>${java.version}</maven.compiler.release> <maven.compiler.target>${java.version}</maven.compiler.target> @@ -485,11 +485,11 @@ <configuration> <rules> <requireJavaVersion> - <message>Java 17 or higher is required to compile this module</message> + <message>Java 21 or higher is required to compile this module</message> <version>[${java.version},)</version> </requireJavaVersion> <requireMavenVersion> - <message>Maven 3.3.9 or higher is required to compile this module</message> + <message>Maven 3.9.0 or higher is required to compile this module</message> <version>[${maven.version},)</version> </requireMavenVersion> </rules>
