languagetool-org/languagetool · error · RuntimeException

Constructor of filter class '${className}' must not have arg

Error message

Constructor of filter class '${className}' must not have arguments: ${constructor}

What it means

RuleFilterCreator.getFilter() reflectively instantiates the filter class and requires a public no-argument constructor. When the single public constructor takes parameters, it throws RuntimeException with the offending Constructor's toString, because the framework has no arguments to pass.

Source

Thrown at languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterCreator.java:55

  private RuleFilterCreator() {
  }

  /**
   * @param className fully qualified class Name of a class implementing {@link RuleFilter}
   */
  public RuleFilter getFilter(String className) {
    try {
      Class<?> aClass = JLanguageTool.getClassBroker().forName(className);
      return myFilterCache.computeIfAbsent(aClass, clazz -> {
        Constructor<?>[] constructors = clazz.getConstructors();
        if (constructors.length != 1) {
          throw new RuntimeException("Constructor of filter class '"
            + className + "' must have exactly one constructor, but it has " + constructors.length);
        }
        Constructor<?> constructor = constructors[0];
        try {
          if (constructor.getParameterTypes().length != 0) {
            throw new RuntimeException("Constructor of filter class '" + className + "' must not have arguments: " + constructor);
          }
          Object filter = constructor.newInstance();
          if (filter instanceof RuleFilter) {
            return (RuleFilter) filter;
          } else {
            throw new RuntimeException("Filter class '" + className + "' must implement interface " + RuleFilter.class.getSimpleName());
          }
        } catch (Exception e) {
          throw new RuntimeException("Could not create filter class using constructor " + constructor, e);
        }
      });
    } catch (ClassNotFoundException e) {
      throw new RuntimeException("Could not find filter class: '"
              + className + "' - make sure to use a fully qualified class name like 'org.languagetool.rules.MyFilter'");
    }
  }

  public static @NotNull RuleFilterCreator getInstance() {

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Change the filter to a public no-argument constructor and move configuration into the args map (the key/value attributes passed to the filter at runtime)
  2. If state is needed, use mutable setters or static configuration initialized before rule loading
  3. Verify the class in <filter class='...'> is the intended filter, not a differently-constructed wrapper

Example fix

// before
public MyFilter(Language lang) { this.lang = lang; }
// after
public MyFilter() {}
@Override
public RuleMatch acceptRuleMatch(RuleMatch match, Map<String,String> args, int patternTokenPos, AnalyzedTokenReadings[] patternTokens) {
  // read config from args instead of constructor
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(className);
for (java.lang.reflect.Constructor<?> ctor : c.getConstructors()) {
  if (ctor.getParameterCount() != 0) throw new IllegalStateException(className + " must have a public no-arg constructor");
}

Type guard

boolean hasNoArgPublicCtor(Class<?> c) { try { c.getConstructor(); return true; } catch (NoSuchMethodException e) { return false; } }

Try / catch

try {
  RuleFilter f = new RuleFilterCreator().getFilter(className);
} catch (RuntimeException e) {
  if (e.getMessage().contains("must not have arguments")) {
    throw new ConfigurationException("Filter " + className + " needs a no-arg constructor", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: A filter class referenced by <filter class='...'> declares its only public constructor with one or more parameters (e.g. taking a Language or configuration object).

Common situations: Injecting dependencies via constructor in a filter and forgetting LanguageTool creates filters via a no-arg reflection call; migrating a filter class from another framework where constructor injection was allowed.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/5966d60a0a4c2a68. Report an issue: GitHub.