You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opennlp.apache.org by ma...@apache.org on 2026/10/06 18:09:02 UTC

(opennlp) branch main updated: GH-1395: Reject null arguments in opennlp-api with IllegalArgumentException (#1410)

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


The following commit(s) were added to refs/heads/main by this push:
     new 66b1719bd GH-1395: Reject null arguments in opennlp-api with IllegalArgumentException (#1410)
66b1719bd is described below

commit 66b1719bdb331acab2e92c3b04d3cfb8f1d0509b
Author: Richard Zowalla <13...@users.noreply.github.com>
AuthorDate: Tue Oct 6 20:08:55 2026 +0200

    GH-1395: Reject null arguments in opennlp-api with IllegalArgumentException (#1410)
---
 .../java/opennlp/tools/doccat/DocumentSample.java  |  7 +++++--
 .../opennlp/tools/document/DocumentAnnotators.java |  6 +++++-
 .../java/opennlp/tools/langdetect/Language.java    |  6 +++++-
 .../opennlp/tools/langdetect/LanguageSample.java   | 15 +++++++++++---
 .../main/java/opennlp/tools/ml/model/Event.java    | 13 +++++++-----
 .../java/opennlp/tools/namefind/NameSample.java    |  6 +++++-
 .../java/opennlp/tools/tokenize/TokenSample.java   | 19 ++++++++++++------
 .../java/opennlp/tools/util/ObjectStreamUtils.java | 12 +++++------
 .../opennlp/tools/util/PlainTextByLineStream.java  |  7 ++++---
 .../opennlp/tools/util/ext/ExtensionLoader.java    | 11 +++++------
 .../opennlp/tools/util/normalizer/AlignedText.java | 19 ++++++++++++++++++
 .../opennlp/tools/util/normalizer/Alignment.java   |  7 +++++--
 .../tools/util/normalizer/CodePointSet.java        | 16 ++++++++++-----
 .../tools/document/DocumentAnnotatorsTest.java     | 12 +++++++++++
 .../tools/util/normalizer/AlignedTextTest.java     | 18 +++++++++++++++++
 .../tools/util/normalizer/AlignmentTest.java       |  8 ++++++++
 .../tools/util/normalizer/CodePointSetTest.java    | 23 ++++++++++++++++++++++
 .../java/opennlp/tools/ml/model/EventTest.java     | 20 +++++++++----------
 .../opennlp/tools/doccat/DocumentSampleTest.java   |  9 +++++++++
 .../tools/langdetect/LanguageSampleTest.java       |  4 ++--
 .../opennlp/tools/langdetect/LanguageTest.java     |  4 ++--
 .../opennlp/tools/namefind/NameSampleTest.java     |  7 +++++++
 .../opennlp/tools/tokenize/TokenSampleTest.java    | 23 ++++++++++++++++++++++
 .../opennlp/tools/util/ObjectStreamUtilsTest.java  | 21 ++++++++++++++++++++
 .../tools/util/PlainTextByLineStreamTest.java      |  9 +++++++++
 .../tools/util/ext/ExtensionLoaderTest.java        |  8 +++++---
 26 files changed, 252 insertions(+), 58 deletions(-)

diff --git a/opennlp-api/src/main/java/opennlp/tools/doccat/DocumentSample.java b/opennlp-api/src/main/java/opennlp/tools/doccat/DocumentSample.java
index 95d7b1202..de749e382 100644
--- a/opennlp-api/src/main/java/opennlp/tools/doccat/DocumentSample.java
+++ b/opennlp-api/src/main/java/opennlp/tools/doccat/DocumentSample.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.Objects;
 
 import opennlp.tools.commons.Sample;
+import opennlp.tools.util.ParamChecks;
 
 /**
  * Class which holds a classified document and its category.
@@ -40,6 +41,7 @@ public class DocumentSample implements Sample {
    *
    * @param category The category to be used. Must not be {@code null}.
    * @param text The plain text in a tokenized form. Must not be {@code null}.
+   * @throws IllegalArgumentException Thrown if {@code category} or {@code text} is {@code null}.
    */
   public DocumentSample(String category, String[] text) {
     this(category, text, null);
@@ -51,11 +53,12 @@ public class DocumentSample implements Sample {
    * @param category The category to be used.Must not be {@code null}.
    * @param text The plain text in a tokenized form. Must not be {@code null}.
    * @param extraInformation Additional information for context.
+   * @throws IllegalArgumentException Thrown if {@code category} or {@code text} is {@code null}.
    */
   public DocumentSample(String category, String[] text, Map<String, Object> extraInformation) {
-    Objects.requireNonNull(text, "text must not be null");
+    ParamChecks.requireNonNullArg(text, "text");
 
-    this.category = Objects.requireNonNull(category, "category must not be null");
+    this.category = ParamChecks.requireNonNullArg(category, "category");
     this.text = List.of(text);
     this.extraInformation = Objects.requireNonNullElse(extraInformation, Collections.emptyMap());
   }
diff --git a/opennlp-api/src/main/java/opennlp/tools/document/DocumentAnnotators.java b/opennlp-api/src/main/java/opennlp/tools/document/DocumentAnnotators.java
index 8dc167297..4ca8b1ae7 100644
--- a/opennlp-api/src/main/java/opennlp/tools/document/DocumentAnnotators.java
+++ b/opennlp-api/src/main/java/opennlp/tools/document/DocumentAnnotators.java
@@ -86,10 +86,14 @@ public final class DocumentAnnotators {
    * @param tokens The token layer, in text order. Must not be {@code null}.
    * @param consumer Receives each token-carrying sentence's run. Must not be
    *                 {@code null}.
-   * @throws IllegalArgumentException Thrown if a token lies outside every sentence.
+   * @throws IllegalArgumentException Thrown if {@code sentences}, {@code tokens} or
+   *         {@code consumer} is {@code null}, or if a token lies outside every sentence.
    */
   public static void forEachSentence(List<Annotation<String>> sentences,
       List<Annotation<String>> tokens, SentenceTokenConsumer consumer) {
+    ParamChecks.requireNonNullArg(sentences, "sentences");
+    ParamChecks.requireNonNullArg(tokens, "tokens");
+    ParamChecks.requireNonNullArg(consumer, "consumer");
     int next = 0;
     for (final Annotation<String> sentence : sentences) {
       final int first = next;
diff --git a/opennlp-api/src/main/java/opennlp/tools/langdetect/Language.java b/opennlp-api/src/main/java/opennlp/tools/langdetect/Language.java
index 0a429805f..55d240a55 100644
--- a/opennlp-api/src/main/java/opennlp/tools/langdetect/Language.java
+++ b/opennlp-api/src/main/java/opennlp/tools/langdetect/Language.java
@@ -20,6 +20,8 @@ package opennlp.tools.langdetect;
 import java.io.Serializable;
 import java.util.Objects;
 
+import opennlp.tools.util.ParamChecks;
+
 /**
  * Class for holding the document language and its confidence
  */
@@ -31,6 +33,7 @@ public class Language implements Serializable {
 
   /**
    * @param lang The language identifier.
+   * @throws IllegalArgumentException Thrown if {@code lang} is {@code null}.
    */
   public Language(String lang) {
     this(lang, 0);
@@ -39,9 +42,10 @@ public class Language implements Serializable {
   /**
    * @param lang The language identifier.
    * @param confidence The confidence computed during language detection.
+   * @throws IllegalArgumentException Thrown if {@code lang} is {@code null}.
    */
   public Language(String lang, double confidence) {
-    Objects.requireNonNull(lang, "lang must not be null");
+    ParamChecks.requireNonNullArg(lang, "lang");
     this.lang = lang;
     this.confidence = confidence;
   }
diff --git a/opennlp-api/src/main/java/opennlp/tools/langdetect/LanguageSample.java b/opennlp-api/src/main/java/opennlp/tools/langdetect/LanguageSample.java
index 3926c95b1..4e4b811be 100644
--- a/opennlp-api/src/main/java/opennlp/tools/langdetect/LanguageSample.java
+++ b/opennlp-api/src/main/java/opennlp/tools/langdetect/LanguageSample.java
@@ -19,7 +19,8 @@ package opennlp.tools.langdetect;
 
 import java.io.Serial;
 import java.io.Serializable;
-import java.util.Objects;
+
+import opennlp.tools.util.ParamChecks;
 
 /**
  * Holds a classified document and its {@link Language}.
@@ -29,9 +30,17 @@ public record LanguageSample(Language language, CharSequence context) implements
   @Serial
   private static final long serialVersionUID = -4791295976215940258L;
 
+  /**
+   * Instantiates a {@link LanguageSample}.
+   *
+   * @param language The {@link Language} of the sample. Must not be {@code null}.
+   * @param context The text of the sample. Must not be {@code null}.
+   * @throws IllegalArgumentException Thrown if {@code language} or {@code context} is
+   *     {@code null}.
+   */
   public LanguageSample(Language language, CharSequence context) {
-    this.language = Objects.requireNonNull(language, "language must not be null");
-    this.context = Objects.requireNonNull(context, "context must not be null");
+    this.language = ParamChecks.requireNonNullArg(language, "language");
+    this.context = ParamChecks.requireNonNullArg(context, "context");
   }
 
   @Override
diff --git a/opennlp-api/src/main/java/opennlp/tools/ml/model/Event.java b/opennlp-api/src/main/java/opennlp/tools/ml/model/Event.java
index 42d786fff..2e68cf92f 100644
--- a/opennlp-api/src/main/java/opennlp/tools/ml/model/Event.java
+++ b/opennlp-api/src/main/java/opennlp/tools/ml/model/Event.java
@@ -17,8 +17,7 @@
 
 package opennlp.tools.ml.model;
 
-
-import java.util.Objects;
+import opennlp.tools.util.ParamChecks;
 
 /**
  * The context of a decision point during training.
@@ -34,6 +33,7 @@ public class Event {
    *
    * @param outcome The outcome to use. Must not be {@code null}.
    * @param context The {@link String array} of context elements. Must not be {@code null}.
+   * @throws IllegalArgumentException Thrown if {@code outcome} or {@code context} is {@code null}.
    */
   public Event(String outcome, CharSequence[] context) {
     this(outcome,context,null);
@@ -45,10 +45,11 @@ public class Event {
    * @param outcome The outcome to use. Must not be {@code null}.
    * @param context The {@link String array} of context elements. Must not be {@code null}.
    * @param values The {@code float} array to use.
+   * @throws IllegalArgumentException Thrown if {@code outcome} or {@code context} is {@code null}.
    */
   public Event(String outcome, String[] context, float[] values) {
-    this.outcome = Objects.requireNonNull(outcome, "outcome must not be null");
-    this.context = Objects.requireNonNull(context, "context must not be null");
+    this.outcome = ParamChecks.requireNonNullArg(outcome, "outcome");
+    this.context = ParamChecks.requireNonNullArg(context, "context");
     this.values = values;
   }
 
@@ -58,9 +59,11 @@ public class Event {
    * @param outcome The outcome to use. Must not be {@code null}.
    * @param context The {@link CharSequence array} of context elements. Must not be {@code null}.
    * @param values The {@code float} array to use.
+   * @throws IllegalArgumentException Thrown if {@code outcome} or {@code context} is {@code null}.
    */
   public Event(String outcome, CharSequence[] context, float[] values) {
-    this.outcome = Objects.requireNonNull(outcome, "outcome must not be null");
+    this.outcome = ParamChecks.requireNonNullArg(outcome, "outcome");
+    ParamChecks.requireNonNullArg(context, "context");
     final String[] ctx = new String[context.length];
     for (int i = 0; i < context.length; i++) {
       ctx[i] = context[i].toString();
diff --git a/opennlp-api/src/main/java/opennlp/tools/namefind/NameSample.java b/opennlp-api/src/main/java/opennlp/tools/namefind/NameSample.java
index 795a25089..4007a4e78 100644
--- a/opennlp-api/src/main/java/opennlp/tools/namefind/NameSample.java
+++ b/opennlp-api/src/main/java/opennlp/tools/namefind/NameSample.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
 
 import opennlp.tools.commons.Sample;
 import opennlp.tools.tokenize.WhitespaceTokenizer;
+import opennlp.tools.util.ParamChecks;
 import opennlp.tools.util.Span;
 
 /**
@@ -62,13 +63,14 @@ public class NameSample implements Sample {
    * @param additionalContext Additional context in a 2-dimensional array.
    * @param clearAdaptiveData If {@code true} the adaptive data of the feature generators is cleared.
    *
+   * @throws IllegalArgumentException Thrown if {@code sentence} is {@code null}.
    * @throws RuntimeException Thrown if name spans are overlapping.
    */
   public NameSample(String id, String[] sentence, Span[] names, String[][] additionalContext,
                     boolean clearAdaptiveData) {
     this.id = id;
 
-    Objects.requireNonNull(sentence, "sentence must not be null");
+    ParamChecks.requireNonNullArg(sentence, "sentence");
 
     if (names == null) {
       names = new Span[0];
@@ -112,6 +114,7 @@ public class NameSample implements Sample {
    * @param additionalContext Additional context in a 2-dimensional array.
    * @param clearAdaptiveData If {@code true} the adaptive data of the feature generators is cleared.
    *
+   * @throws IllegalArgumentException Thrown if {@code sentence} is {@code null}.
    * @throws RuntimeException Thrown if name spans are overlapping.
    */
   public NameSample(String[] sentence, Span[] names,
@@ -126,6 +129,7 @@ public class NameSample implements Sample {
    * @param names The {@link Span names} to use.
    * @param clearAdaptiveData If {@code true} the adaptive data of the feature generators is cleared.
    *
+   * @throws IllegalArgumentException Thrown if {@code sentence} is {@code null}.
    * @throws RuntimeException Thrown if name spans are overlapping.
    */
   public NameSample(String[] sentence, Span[] names, boolean clearAdaptiveData) {
diff --git a/opennlp-api/src/main/java/opennlp/tools/tokenize/TokenSample.java b/opennlp-api/src/main/java/opennlp/tools/tokenize/TokenSample.java
index 591888b9b..d2e02a161 100644
--- a/opennlp-api/src/main/java/opennlp/tools/tokenize/TokenSample.java
+++ b/opennlp-api/src/main/java/opennlp/tools/tokenize/TokenSample.java
@@ -25,6 +25,7 @@ import java.util.Objects;
 
 import opennlp.tools.commons.Sample;
 import opennlp.tools.tokenize.Detokenizer.DetokenizationOperation;
+import opennlp.tools.util.ParamChecks;
 import opennlp.tools.util.Span;
 
 /**
@@ -48,11 +49,13 @@ public class TokenSample implements Sample {
    *             Must not be {@code null}.
    * @param tokenSpans The spans which mark the start and end of the tokens.
    *                   Must not be {@code null}.
+   * @throws IllegalArgumentException Thrown if {@code text} or {@code tokenSpans} is
+   *     {@code null}.
    */
   public TokenSample(String text, Span[] tokenSpans) {
-    Objects.requireNonNull(tokenSpans, "tokenSpans must not be null");
+    ParamChecks.requireNonNullArg(tokenSpans, "tokenSpans");
 
-    this.text = Objects.requireNonNull(text, "text must not be null");
+    this.text = ParamChecks.requireNonNullArg(text, "text");
     this.tokenSpans = List.of(tokenSpans);
 
     for (Span tokenSpan : tokenSpans) {
@@ -69,11 +72,13 @@ public class TokenSample implements Sample {
    *
    * @param detokenizer The text which contains the tokens. Must not be {@code null}.
    * @param tokens The tokens to be processed. Must not be {@code null}.
+   * @throws IllegalArgumentException Thrown if {@code detokenizer} or {@code tokens} is
+   *     {@code null}.
    */
   public TokenSample(Detokenizer detokenizer, String[] tokens) {
 
-    Objects.requireNonNull(detokenizer, "detokenizer must not be null");
-    Objects.requireNonNull(tokens, "tokens must not be null");
+    ParamChecks.requireNonNullArg(detokenizer, "detokenizer");
+    ParamChecks.requireNonNullArg(tokens, "tokens");
     
     DetokenizationOperation[] operations = detokenizer.detokenize(tokens);
 
@@ -174,10 +179,12 @@ public class TokenSample implements Sample {
    * @param separatorChars The characters to be considered separators.
    *                       See {@link #DEFAULT_SEPARATOR_CHARS}. Must not be {@code null}.
    * @return A valid {@link TokenSample} instance.
+   * @throws IllegalArgumentException Thrown if {@code sampleString} or {@code separatorChars}
+   *     is {@code null}.
    */
   public static TokenSample parse(String sampleString, String separatorChars) {
-    Objects.requireNonNull(sampleString, "sampleString must not be null");
-    Objects.requireNonNull(separatorChars, "separatorChars must not be null");
+    ParamChecks.requireNonNullArg(sampleString, "sampleString");
+    ParamChecks.requireNonNullArg(separatorChars, "separatorChars");
 
     Span[] whitespaceTokenSpans = WhitespaceTokenizer.INSTANCE.tokenizePos(sampleString);
 
diff --git a/opennlp-api/src/main/java/opennlp/tools/util/ObjectStreamUtils.java b/opennlp-api/src/main/java/opennlp/tools/util/ObjectStreamUtils.java
index 996bc6838..f57db5e4e 100644
--- a/opennlp-api/src/main/java/opennlp/tools/util/ObjectStreamUtils.java
+++ b/opennlp-api/src/main/java/opennlp/tools/util/ObjectStreamUtils.java
@@ -99,14 +99,14 @@ public class ObjectStreamUtils {
    * @param <T> The generic type of the elements in the {@code collection}.
    *
    * @return The concatenated {@link ObjectStream} aggregating all elements in {@code streams}.
+   * @throws IllegalArgumentException Thrown if {@code streams} or one of its elements is {@code null}.
    */
   public static <T> ObjectStream<T> concatenateObjectStream(final Collection<ObjectStream<T>> streams) {
+    ParamChecks.requireNonNullArg(streams, "streams");
 
     // We may want to skip null streams instead of throwing a 
     for (ObjectStream<T> stream : streams) {
-      if (stream == null) {
-        throw new NullPointerException("stream cannot be null");
-      }
+      ParamChecks.requireNonNullArg(stream, "stream");
     }
 
     return new ObjectStream<>() {
@@ -155,14 +155,14 @@ public class ObjectStreamUtils {
    * @param <T> The generic type of the elements in the {@code streams}.
    *           
    * @return The concatenated {@link ObjectStream} aggregating all elements in {@code streams}.
+   * @throws IllegalArgumentException Thrown if {@code streams} or one of its elements is {@code null}.
    */
   @SafeVarargs
   public static <T> ObjectStream<T> concatenateObjectStream(final ObjectStream<T>... streams) {
+    ParamChecks.requireNonNullArg(streams, "streams");
 
     for (ObjectStream<T> stream : streams) {
-      if (stream == null) {
-        throw new NullPointerException("stream cannot be null");
-      }
+      ParamChecks.requireNonNullArg(stream, "stream");
     }
 
     return new ObjectStream<>() {
diff --git a/opennlp-api/src/main/java/opennlp/tools/util/PlainTextByLineStream.java b/opennlp-api/src/main/java/opennlp/tools/util/PlainTextByLineStream.java
index d524661f1..36d0a1853 100644
--- a/opennlp-api/src/main/java/opennlp/tools/util/PlainTextByLineStream.java
+++ b/opennlp-api/src/main/java/opennlp/tools/util/PlainTextByLineStream.java
@@ -21,7 +21,6 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.nio.charset.Charset;
-import java.util.Objects;
 
 /**
  * Reads a plain text file and returns each line as a {@link String} object.
@@ -41,6 +40,7 @@ public class PlainTextByLineStream implements ObjectStream<String> {
    * @param charsetName The name of the {@link Charset} that is used for interpreting characters.
    *
    * @throws IOException Thrown if IO errors occurred.
+   * @throws IllegalArgumentException Thrown if {@code inputStreamFactory} is {@code null}.
    */
   public PlainTextByLineStream(InputStreamFactory inputStreamFactory, String charsetName)
           throws IOException {
@@ -54,11 +54,12 @@ public class PlainTextByLineStream implements ObjectStream<String> {
    * @param charset The {@link Charset} that is used for interpreting characters.
    *
    * @throws IOException Thrown if IO errors occurred.
+   * @throws IllegalArgumentException Thrown if {@code inputStreamFactory} is {@code null}.
    */
   public PlainTextByLineStream(InputStreamFactory inputStreamFactory, Charset charset)
           throws IOException {
-    this.inputStreamFactory = Objects.requireNonNull(
-            inputStreamFactory, "inputStreamFactory must not be null!");
+    this.inputStreamFactory = ParamChecks.requireNonNullArg(
+            inputStreamFactory, "inputStreamFactory");
     this.encoding = charset;
 
     reset();
diff --git a/opennlp-api/src/main/java/opennlp/tools/util/ext/ExtensionLoader.java b/opennlp-api/src/main/java/opennlp/tools/util/ext/ExtensionLoader.java
index ad878bd79..f48058ad3 100644
--- a/opennlp-api/src/main/java/opennlp/tools/util/ext/ExtensionLoader.java
+++ b/opennlp-api/src/main/java/opennlp/tools/util/ext/ExtensionLoader.java
@@ -21,11 +21,11 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 import opennlp.tools.commons.Internal;
+import opennlp.tools.util.ParamChecks;
 import opennlp.tools.util.StringUtil;
 
 /**
@@ -93,11 +93,10 @@ public class ExtensionLoader {
    *
    * @param packagePrefix The package prefix to allow, e.g. {@code "com.example.nlp"}.
    *                      Must not be {@code null} or blank.
-   * @throws NullPointerException if {@code packagePrefix} is {@code null}.
-   * @throws IllegalArgumentException if {@code packagePrefix} is blank.
+   * @throws IllegalArgumentException if {@code packagePrefix} is {@code null} or blank.
    */
   public static void registerAllowedPackage(String packagePrefix) {
-    Objects.requireNonNull(packagePrefix, "packagePrefix must not be null");
+    ParamChecks.requireNonNullArg(packagePrefix, "packagePrefix");
     if (packagePrefix.isBlank()) {
       throw new IllegalArgumentException("packagePrefix must not be blank");
     }
@@ -115,10 +114,10 @@ public class ExtensionLoader {
    *
    * @param packagePrefix The package prefix to remove, e.g. {@code "com.example.nlp"}.
    *                      Must not be {@code null}.
-   * @throws NullPointerException if {@code packagePrefix} is {@code null}.
+   * @throws IllegalArgumentException if {@code packagePrefix} is {@code null}.
    */
   public static void unregisterAllowedPackage(String packagePrefix) {
-    Objects.requireNonNull(packagePrefix, "packagePrefix must not be null");
+    ParamChecks.requireNonNullArg(packagePrefix, "packagePrefix");
     String normalized = packagePrefix.endsWith(".") ? packagePrefix : packagePrefix + ".";
     ALLOWED_PREFIXES.remove(normalized);
   }
diff --git a/opennlp-api/src/main/java/opennlp/tools/util/normalizer/AlignedText.java b/opennlp-api/src/main/java/opennlp/tools/util/normalizer/AlignedText.java
index 911a6d757..42f2d946b 100644
--- a/opennlp-api/src/main/java/opennlp/tools/util/normalizer/AlignedText.java
+++ b/opennlp-api/src/main/java/opennlp/tools/util/normalizer/AlignedText.java
@@ -35,6 +35,25 @@ import opennlp.tools.util.Span;
  */
 public record AlignedText(CharSequence original, CharSequence normalized, Alignment alignment) {
 
+  /**
+   * Validates the components.
+   *
+   * @throws IllegalArgumentException Thrown if a component is {@code null}, or if the lengths of
+   *     {@code original} and {@code normalized} do not match the lengths of {@code alignment}.
+   */
+  public AlignedText {
+    ParamChecks.requireNonNullArg(original, "original");
+    ParamChecks.requireNonNullArg(normalized, "normalized");
+    ParamChecks.requireNonNullArg(alignment, "alignment");
+    if (alignment.originalLength() != original.length()
+        || alignment.normalizedLength() != normalized.length()) {
+      throw new IllegalArgumentException("alignment lengths (original="
+          + alignment.originalLength() + ", normalized=" + alignment.normalizedLength()
+          + ") do not match the texts (original=" + original.length() + ", normalized="
+          + normalized.length() + ")");
+    }
+  }
+
   /**
    * Returns the normalized text as a {@code String}.
    *
diff --git a/opennlp-api/src/main/java/opennlp/tools/util/normalizer/Alignment.java b/opennlp-api/src/main/java/opennlp/tools/util/normalizer/Alignment.java
index 278becd86..ff893c012 100644
--- a/opennlp-api/src/main/java/opennlp/tools/util/normalizer/Alignment.java
+++ b/opennlp-api/src/main/java/opennlp/tools/util/normalizer/Alignment.java
@@ -19,6 +19,7 @@ package opennlp.tools.util.normalizer;
 import java.util.Arrays;
 
 import opennlp.tools.commons.ThreadSafe;
+import opennlp.tools.util.ParamChecks;
 import opennlp.tools.util.Span;
 
 /**
@@ -130,10 +131,12 @@ public final class Alignment {
    *
    * @param next The next stage, whose original side is this stage's normalized text.
    * @return The composed alignment.
-   * @throws IllegalArgumentException Thrown if {@code next.originalLength()} does not equal this
-   *     {@code normalizedLength()} (the stages do not line up).
+   * @throws IllegalArgumentException Thrown if {@code next} is {@code null}, or if
+   *     {@code next.originalLength()} does not equal this {@code normalizedLength()} (the stages do
+   *     not line up).
    */
   public Alignment andThen(Alignment next) {
+    ParamChecks.requireNonNullArg(next, "next");
     if (next.originalLength != normalizedLength()) {
       throw new IllegalArgumentException("stages do not line up: this normalizedLength="
           + normalizedLength() + " but next originalLength=" + next.originalLength);
diff --git a/opennlp-api/src/main/java/opennlp/tools/util/normalizer/CodePointSet.java b/opennlp-api/src/main/java/opennlp/tools/util/normalizer/CodePointSet.java
index b17b98390..519f29285 100644
--- a/opennlp-api/src/main/java/opennlp/tools/util/normalizer/CodePointSet.java
+++ b/opennlp-api/src/main/java/opennlp/tools/util/normalizer/CodePointSet.java
@@ -25,6 +25,8 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 
+import opennlp.tools.util.ParamChecks;
+
 /**
  * An immutable set of Unicode code points with O(1) membership.
  *
@@ -52,10 +54,11 @@ public final class CodePointSet {
    *
    * @param codePoints The code points to include.
    * @return The set.
-   * @throws IllegalArgumentException Thrown if any value is not a valid Unicode code point
-   *     (outside {@code [0, U+10FFFF]}).
+   * @throws IllegalArgumentException Thrown if {@code codePoints} is {@code null}, or if any value
+   *     is not a valid Unicode code point (outside {@code [0, U+10FFFF]}).
    */
   public static CodePointSet of(int... codePoints) {
+    ParamChecks.requireNonNullArg(codePoints, "codePoints");
     final BitSet members = new BitSet();
     for (final int codePoint : codePoints) {
       requireValid(codePoint);
@@ -100,10 +103,12 @@ public final class CodePointSet {
    * @return The code points declared under {@code section}, or an empty set if the section is
    *     absent.
    * @throws IOException Thrown if the file cannot be read.
-   * @throws IllegalArgumentException Thrown if a line is malformed, naming the offending line.
+   * @throws IllegalArgumentException Thrown if {@code definitions} or {@code section} is
+   *     {@code null}, or if a line is malformed, naming the offending line.
    */
   public static CodePointSet fromFile(Path definitions, String section) throws IOException {
-    Objects.requireNonNull(definitions, "definitions");
+    ParamChecks.requireNonNullArg(definitions, "definitions");
+    ParamChecks.requireNonNullArg(section, "section");
     return parse(Files.readAllLines(definitions, StandardCharsets.UTF_8), section);
   }
 
@@ -219,9 +224,10 @@ public final class CodePointSet {
    *
    * @param other The set to union with.
    * @return The union, a new set; neither input is modified.
+   * @throws IllegalArgumentException Thrown if {@code other} is {@code null}.
    */
   public CodePointSet union(CodePointSet other) {
-    Objects.requireNonNull(other, "other");
+    ParamChecks.requireNonNullArg(other, "other");
     final BitSet merged = (BitSet) members.clone();
     merged.or(other.members);
     return new CodePointSet(merged);
diff --git a/opennlp-api/src/test/java/opennlp/tools/document/DocumentAnnotatorsTest.java b/opennlp-api/src/test/java/opennlp/tools/document/DocumentAnnotatorsTest.java
index a7c1792ce..f42e64e2b 100644
--- a/opennlp-api/src/test/java/opennlp/tools/document/DocumentAnnotatorsTest.java
+++ b/opennlp-api/src/test/java/opennlp/tools/document/DocumentAnnotatorsTest.java
@@ -123,6 +123,18 @@ public class DocumentAnnotatorsTest {
     assertTrue(runs.isEmpty());
   }
 
+  @Test
+  void testForEachSentenceRejectsNullArguments() {
+    final DocumentAnnotators.SentenceTokenConsumer consumer = (first, words) -> {
+    };
+    assertEquals("sentences must not be null", assertThrows(IllegalArgumentException.class,
+        () -> DocumentAnnotators.forEachSentence(null, List.of(), consumer)).getMessage());
+    assertEquals("tokens must not be null", assertThrows(IllegalArgumentException.class,
+        () -> DocumentAnnotators.forEachSentence(List.of(), null, consumer)).getMessage());
+    assertEquals("consumer must not be null", assertThrows(IllegalArgumentException.class,
+        () -> DocumentAnnotators.forEachSentence(List.of(), List.of(), null)).getMessage());
+  }
+
   @Test
   void testRequireAlignedAcceptsEqualSizes() {
     final Document document = Document.of("Ana runs")
diff --git a/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignedTextTest.java b/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignedTextTest.java
index 2293e462e..0d05bc600 100644
--- a/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignedTextTest.java
+++ b/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignedTextTest.java
@@ -167,4 +167,22 @@ public class AlignedTextTest {
     assertThrows(IllegalArgumentException.class, () -> collapsed.andThen(unrelated));
   }
 
+  @Test
+  void constructorRejectsNullComponents() {
+    final Alignment alignment = new Alignment.Builder().equal(1).replace(2, 1).equal(1).build(4);
+    assertEquals("original must not be null", assertThrows(IllegalArgumentException.class,
+        () -> new AlignedText(null, "a b", alignment)).getMessage());
+    assertEquals("normalized must not be null", assertThrows(IllegalArgumentException.class,
+        () -> new AlignedText("a  b", null, alignment)).getMessage());
+    assertEquals("alignment must not be null", assertThrows(IllegalArgumentException.class,
+        () -> new AlignedText("a  b", "a b", null)).getMessage());
+  }
+
+  @Test
+  void constructorRejectsLengthMismatch() {
+    final Alignment alignment = new Alignment.Builder().equal(1).replace(2, 1).equal(1).build(4);
+    assertThrows(IllegalArgumentException.class, () -> new AlignedText("a b", "a b", alignment));
+    assertThrows(IllegalArgumentException.class, () -> new AlignedText("a  b", "a  b", alignment));
+  }
+
 }
diff --git a/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignmentTest.java b/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignmentTest.java
index 27416f07f..4939ed124 100644
--- a/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignmentTest.java
+++ b/opennlp-api/src/test/java/opennlp/tools/util/normalizer/AlignmentTest.java
@@ -111,6 +111,14 @@ public class AlignmentTest {
     assertThrows(IllegalArgumentException.class, () -> first.andThen(second));
   }
 
+  @Test
+  void testAndThenRejectsNull() {
+    final Alignment first = new Alignment.Builder().equal(2).build(2);
+    final IllegalArgumentException e =
+        assertThrows(IllegalArgumentException.class, () -> first.andThen(null));
+    assertEquals("next must not be null", e.getMessage());
+  }
+
   @Test
   void testAllDeletedProducesEmptyNormalized() {
     final Alignment a = new Alignment.Builder().replace(2, 0).build(2); // "  " -> ""
diff --git a/opennlp-api/src/test/java/opennlp/tools/util/normalizer/CodePointSetTest.java b/opennlp-api/src/test/java/opennlp/tools/util/normalizer/CodePointSetTest.java
index 6e262154e..33b3dd590 100644
--- a/opennlp-api/src/test/java/opennlp/tools/util/normalizer/CodePointSetTest.java
+++ b/opennlp-api/src/test/java/opennlp/tools/util/normalizer/CodePointSetTest.java
@@ -107,6 +107,29 @@ public class CodePointSetTest {
     assertFalse(set.equals("not a code point set"));
   }
 
+  @Test
+  void testOfRejectsNullArray() {
+    final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+        () -> CodePointSet.of((int[]) null));
+    assertEquals("codePoints must not be null", e.getMessage());
+  }
+
+  @Test
+  void testUnionRejectsNull() {
+    final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+        () -> CodePointSet.of(0x20).union(null));
+    assertEquals("other must not be null", e.getMessage());
+  }
+
+  @Test
+  void testFromFileRejectsNullArguments(@TempDir Path dir) {
+    final Path file = dir.resolve("definitions.txt");
+    assertEquals("definitions must not be null", assertThrows(IllegalArgumentException.class,
+        () -> CodePointSet.fromFile(null, "whitespace")).getMessage());
+    assertEquals("section must not be null", assertThrows(IllegalArgumentException.class,
+        () -> CodePointSet.fromFile(file, null)).getMessage());
+  }
+
   @Test
   void testParseAcceptsSingleHexDigit() {
     assertTrue(CodePointSet.parse(List.of("[s]", "9"), "s").contains(0x9));
diff --git a/opennlp-core/opennlp-ml/opennlp-ml-commons/src/test/java/opennlp/tools/ml/model/EventTest.java b/opennlp-core/opennlp-ml/opennlp-ml-commons/src/test/java/opennlp/tools/ml/model/EventTest.java
index 9492f6e8d..28f84fc0d 100644
--- a/opennlp-core/opennlp-ml/opennlp-ml-commons/src/test/java/opennlp/tools/ml/model/EventTest.java
+++ b/opennlp-core/opennlp-ml/opennlp-ml-commons/src/test/java/opennlp/tools/ml/model/EventTest.java
@@ -24,20 +24,20 @@ public class EventTest {
 
   @Test
   void testNullOutcome() {
-    try {
-      new Event(null, new String[] {"aa", "bb", "cc"});
-      Assertions.fail("NPE must be thrown");
-    } catch (NullPointerException expected) {
-    }
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new Event(null, new String[] {"aa", "bb", "cc"}));
+    Assertions.assertEquals("outcome must not be null", e.getMessage());
+    Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new Event(null, new String[] {"aa"}, null));
   }
 
   @Test
   void testNullContext() {
-    try {
-      new Event("o1", null);
-      Assertions.fail("NPE must be thrown");
-    } catch (NullPointerException expected) {
-    }
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new Event("o1", null));
+    Assertions.assertEquals("context must not be null", e.getMessage());
+    Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new Event("o1", (String[]) null, null));
   }
 
   @Test
diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/doccat/DocumentSampleTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/doccat/DocumentSampleTest.java
index 8bc3bb0a2..74c77f75e 100644
--- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/doccat/DocumentSampleTest.java
+++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/doccat/DocumentSampleTest.java
@@ -70,4 +70,13 @@ public class DocumentSampleTest {
     return new DocumentSample("anotherCategory", new String[] {"a", "small", "text"});
   }
 
+  @Test
+  void testRejectsNullArguments() {
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new DocumentSample(null, new String[] {"a"}));
+    Assertions.assertEquals("category must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new DocumentSample("c", null));
+    Assertions.assertEquals("text must not be null", e.getMessage());
+  }
 }
diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageSampleTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageSampleTest.java
index 4ebcdac7b..c11bd8a87 100644
--- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageSampleTest.java
+++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageSampleTest.java
@@ -72,7 +72,7 @@ public class LanguageSampleTest {
 
   @Test
   void testNullLang() {
-    Assertions.assertThrows(NullPointerException.class, () -> {
+    Assertions.assertThrows(IllegalArgumentException.class, () -> {
       CharSequence context = "aContext";
 
       new LanguageSample(null, context);
@@ -82,7 +82,7 @@ public class LanguageSampleTest {
 
   @Test
   void testNullContext() {
-    Assertions.assertThrows(NullPointerException.class, () -> {
+    Assertions.assertThrows(IllegalArgumentException.class, () -> {
       Language lang = new Language("aLang");
 
       new LanguageSample(lang, null);
diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageTest.java
index 4d55012f1..261393584 100644
--- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageTest.java
+++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/langdetect/LanguageTest.java
@@ -44,12 +44,12 @@ public class LanguageTest {
 
   @Test
   void emptyLanguage() {
-    Assertions.assertThrows(NullPointerException.class, () -> new Language(null));
+    Assertions.assertThrows(IllegalArgumentException.class, () -> new Language(null));
   }
 
   @Test
   void emptyLanguageConfidence() {
-    Assertions.assertThrows(NullPointerException.class, () -> new Language(null, 0.05));
+    Assertions.assertThrows(IllegalArgumentException.class, () -> new Language(null, 0.05));
   }
 
   @Test
diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/namefind/NameSampleTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/namefind/NameSampleTest.java
index 42879f3b3..8ea8b879e 100644
--- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/namefind/NameSampleTest.java
+++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/namefind/NameSampleTest.java
@@ -301,4 +301,11 @@ public class NameSampleTest {
   public static NameSample createPredSample() {
     return createSimpleNameSample(false);
   }
+
+  @Test
+  void testRejectsNullSentence() {
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new NameSample(null, new Span[0], false));
+    Assertions.assertEquals("sentence must not be null", e.getMessage());
+  }
 }
diff --git a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenSampleTest.java b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenSampleTest.java
index f3883a823..4987a1b40 100644
--- a/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenSampleTest.java
+++ b/opennlp-core/opennlp-runtime/src/test/java/opennlp/tools/tokenize/TokenSampleTest.java
@@ -131,4 +131,27 @@ public class TokenSampleTest {
     Assertions.assertNotEquals(createPredSample(), createGoldSample());
     Assertions.assertNotEquals(new Object(), createPredSample());
   }
+
+  @Test
+  void testRejectsNullArguments() throws IOException {
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new TokenSample(null, new Span[0]));
+    Assertions.assertEquals("text must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new TokenSample("text", null));
+    Assertions.assertEquals("tokenSpans must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new TokenSample(null, new String[] {"a"}));
+    Assertions.assertEquals("detokenizer must not be null", e.getMessage());
+    Detokenizer detokenizer = DictionaryDetokenizerTest.createLatinDetokenizer();
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new TokenSample(detokenizer, null));
+    Assertions.assertEquals("tokens must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> TokenSample.parse(null, TokenSample.DEFAULT_SEPARATOR_CHARS));
+    Assertions.assertEquals("sampleString must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> TokenSample.parse("a b", null));
+    Assertions.assertEquals("separatorChars must not be null", e.getMessage());
+  }
 }
diff --git a/opennlp-tools/src/test/java/opennlp/tools/util/ObjectStreamUtilsTest.java b/opennlp-tools/src/test/java/opennlp/tools/util/ObjectStreamUtilsTest.java
index 31065ce15..358624cdc 100644
--- a/opennlp-tools/src/test/java/opennlp/tools/util/ObjectStreamUtilsTest.java
+++ b/opennlp-tools/src/test/java/opennlp/tools/util/ObjectStreamUtilsTest.java
@@ -97,6 +97,27 @@ public class ObjectStreamUtilsTest {
     }
   }
 
+  @Test
+  @SuppressWarnings("unchecked")
+  void testConcatenateRejectsNullArguments() {
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> ObjectStreamUtils.concatenateObjectStream((List<ObjectStream<String>>) null));
+    Assertions.assertEquals("streams must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> ObjectStreamUtils.concatenateObjectStream((ObjectStream<String>[]) null));
+    Assertions.assertEquals("streams must not be null", e.getMessage());
+
+    List<ObjectStream<String>> withNull = new ArrayList<>();
+    withNull.add(ObjectStreamUtils.createObjectStream("a"));
+    withNull.add(null);
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> ObjectStreamUtils.concatenateObjectStream(withNull));
+    Assertions.assertEquals("stream must not be null", e.getMessage());
+    e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> ObjectStreamUtils.concatenateObjectStream(ObjectStreamUtils.createObjectStream("a"), null));
+    Assertions.assertEquals("stream must not be null", e.getMessage());
+  }
+
   private void compareUpToLastCharacter(ObjectStream<String> stream,
                                         String[] expectedValues) throws IOException {
 
diff --git a/opennlp-tools/src/test/java/opennlp/tools/util/PlainTextByLineStreamTest.java b/opennlp-tools/src/test/java/opennlp/tools/util/PlainTextByLineStreamTest.java
index 6ff81a2ad..8071fa6cf 100644
--- a/opennlp-tools/src/test/java/opennlp/tools/util/PlainTextByLineStreamTest.java
+++ b/opennlp-tools/src/test/java/opennlp/tools/util/PlainTextByLineStreamTest.java
@@ -41,6 +41,15 @@ public class PlainTextByLineStreamTest {
       "line4" +
       '\n';
 
+  @Test
+  void testRejectsNullInputStreamFactory() {
+    IllegalArgumentException e = Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new PlainTextByLineStream(null, StandardCharsets.UTF_8));
+    Assertions.assertEquals("inputStreamFactory must not be null", e.getMessage());
+    Assertions.assertThrows(IllegalArgumentException.class,
+        () -> new PlainTextByLineStream(null, "UTF-8"));
+  }
+
   @Test
   void testLineSegmentation() throws IOException {
     ObjectStream<String> stream =
diff --git a/opennlp-tools/src/test/java/opennlp/tools/util/ext/ExtensionLoaderTest.java b/opennlp-tools/src/test/java/opennlp/tools/util/ext/ExtensionLoaderTest.java
index 41d2c3e82..4eb8e2807 100644
--- a/opennlp-tools/src/test/java/opennlp/tools/util/ext/ExtensionLoaderTest.java
+++ b/opennlp-tools/src/test/java/opennlp/tools/util/ext/ExtensionLoaderTest.java
@@ -149,13 +149,15 @@ public class ExtensionLoaderTest {
   }
 
   /**
-   * registerAllowedPackage() throws NullPointerException for null and
-   * IllegalArgumentException for blank inputs.
+   * registerAllowedPackage() throws IllegalArgumentException for null and
+   * blank inputs.
    */
   @Test
   void testRegisterAllowedPackageRejectsNullAndBlank() {
-    Assertions.assertThrows(NullPointerException.class,
+    Assertions.assertThrows(IllegalArgumentException.class,
         () -> ExtensionLoader.registerAllowedPackage(null));
+    Assertions.assertThrows(IllegalArgumentException.class,
+        () -> ExtensionLoader.unregisterAllowedPackage(null));
 
     Assertions.assertThrows(IllegalArgumentException.class,
         () -> ExtensionLoader.registerAllowedPackage(""));