{"record":{"id":"5966d60a0a4c2a68","repo":"languagetool-org/languagetool","slug":"constructor-of-filter-class-classname-must-no-5966d6","errorCode":null,"errorMessage":"Constructor of filter class '${className}' must not have arguments: ${constructor}","messagePattern":"Constructor of filter class '(.+?)' must not have arguments: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterCreator.java","lineNumber":55,"sourceCode":"  private RuleFilterCreator() {\n  }\n\n  /**\n   * @param className fully qualified class Name of a class implementing {@link RuleFilter}\n   */\n  public RuleFilter getFilter(String className) {\n    try {\n      Class<?> aClass = JLanguageTool.getClassBroker().forName(className);\n      return myFilterCache.computeIfAbsent(aClass, clazz -> {\n        Constructor<?>[] constructors = clazz.getConstructors();\n        if (constructors.length != 1) {\n          throw new RuntimeException(\"Constructor of filter class '\"\n            + className + \"' must have exactly one constructor, but it has \" + constructors.length);\n        }\n        Constructor<?> constructor = constructors[0];\n        try {\n          if (constructor.getParameterTypes().length != 0) {\n            throw new RuntimeException(\"Constructor of filter class '\" + className + \"' must not have arguments: \" + constructor);\n          }\n          Object filter = constructor.newInstance();\n          if (filter instanceof RuleFilter) {\n            return (RuleFilter) filter;\n          } else {\n            throw new RuntimeException(\"Filter class '\" + className + \"' must implement interface \" + RuleFilter.class.getSimpleName());\n          }\n        } catch (Exception e) {\n          throw new RuntimeException(\"Could not create filter class using constructor \" + constructor, e);\n        }\n      });\n    } catch (ClassNotFoundException e) {\n      throw new RuntimeException(\"Could not find filter class: '\"\n              + className + \"' - make sure to use a fully qualified class name like 'org.languagetool.rules.MyFilter'\");\n    }\n  }\n\n  public static @NotNull RuleFilterCreator getInstance() {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-core/src/main/java/org/languagetool/rules/patterns/RuleFilterCreator.java#L37-L73","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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)","If state is needed, use mutable setters or static configuration initialized before rule loading","Verify the class in <filter class='...'> is the intended filter, not a differently-constructed wrapper"],"exampleFix":"// before\npublic MyFilter(Language lang) { this.lang = lang; }\n// after\npublic MyFilter() {}\n@Override\npublic RuleMatch acceptRuleMatch(RuleMatch match, Map<String,String> args, int patternTokenPos, AnalyzedTokenReadings[] patternTokens) {\n  // read config from args instead of constructor\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(className);\nfor (java.lang.reflect.Constructor<?> ctor : c.getConstructors()) {\n  if (ctor.getParameterCount() != 0) throw new IllegalStateException(className + \" must have a public no-arg constructor\");\n}","typeGuard":"boolean hasNoArgPublicCtor(Class<?> c) { try { c.getConstructor(); return true; } catch (NoSuchMethodException e) { return false; } }","tryCatchPattern":"try {\n  RuleFilter f = new RuleFilterCreator().getFilter(className);\n} catch (RuntimeException e) {\n  if (e.getMessage().contains(\"must not have arguments\")) {\n    throw new ConfigurationException(\"Filter \" + className + \" needs a no-arg constructor\", e);\n  }\n  throw e;\n}","preventionTips":["Never require constructor parameters in RuleFilter implementations; use the args map instead","Verify with hasNoArgPublicCtor before registering a custom filter class","Document filter configuration through the rule XML attributes, not the constructor","Run rule-XML loading tests in CI to catch constructor issues before release"],"tags":["java","languagetool","reflection","constructor"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}