{"record":{"id":"94a0dbf68d318f1a","repo":"apache/druid","slug":"jsonconfigurator-requires-default-classes-to-have","errorCode":null,"errorMessage":"JsonConfigurator requires default classes to have zero-arg constructors. %s doesn't","messagePattern":"JsonConfigurator requires default classes to have zero-arg constructors\\. (.+?) doesn't","errorType":"validation","errorClass":"ProvisionException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/guice/JsonConfigurator.java","lineNumber":275,"sourceCode":"    hieraricalPutValue(propertyPrefix, originalProperty, property.substring(dotIndex + 1), value, nestedMap);\n  }\n\n  @VisibleForTesting\n  @SuppressWarnings(\"ReturnValueIgnored\")\n  public static <T> void verifyClazzIsConfigurable(\n      ObjectMapper mapper,\n      Class<T> clazz,\n      @Nullable Class<? extends T> defaultClass\n  )\n  {\n    if (defaultClass != null) {\n      try {\n        if (findJsonCreatorFactoryMethod(defaultClass).isEmpty()) {\n          defaultClass.getConstructor();\n        }\n      }\n      catch (NoSuchMethodException e) {\n        throw new ProvisionException(\n            StringUtils.format(\n                \"JsonConfigurator requires default classes to have zero-arg constructors. %s doesn't\",\n                defaultClass\n            )\n        );\n      }\n    }\n\n    final List<BeanPropertyDefinition> beanDefs = mapper.getSerializationConfig()\n                                                        .introspect(mapper.constructType(clazz))\n                                                        .findProperties();\n    for (BeanPropertyDefinition beanDef : beanDefs) {\n      final AnnotatedField field = beanDef.getField();\n      if (field == null || !field.hasAnnotation(JsonProperty.class)) {\n        throw new ProvisionException(\n            StringUtils.format(\n                \"JsonConfigurator requires Jackson-annotated Config objects to have field annotations. %s doesn't\",\n                clazz","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/guice/JsonConfigurator.java#L257-L293","documentation":"When binding a config via JsonConfigurator.configurate, the optional 'default' instance class must be constructible by Druid: it must either have a Jackson @JsonCreator factory method or a public zero-arg constructor. verifyClazzIsConfigurable throws this ProvisionException when the configured default class has neither, so the injector cannot instantiate a default config bean.","triggerScenarios":"configurate() calls verifyClazzIsConfigurable on the default class supplied to the binder; findJsonCreatorFactoryMethod returns empty and getConstructor() throws NoSuchMethodException.","commonSituations":"Binding a custom config class (or third-party class) with only constructor arguments and no default constructor and no @JsonCreator; missing @JsonCreator on a static factory; class written for a different serialization framework.","solutions":["Add a public no-arg constructor to the default class","Or add a @JsonCreator-annotated static factory/constructor method for Jackson deserialization","If the class is third-party and unmodifiable, wrap it in your own class with a zero-arg constructor and bind that"],"exampleFix":"// before\npublic class MyConfig {\n  public MyConfig(int x) { ... }\n}\n// after\npublic class MyConfig {\n  @JsonCreator\n  public MyConfig(@JsonProperty(\"x\") int x) { ... }\n  // or: public MyConfig() { ... }\n}","handlingStrategy":"validation","validationCode":"static void assertConfigurable(Class<?> clazz) throws NoSuchMethodException {\n  if (JsonConfigurator.findJsonCreatorFactoryMethod(clazz).isEmpty()) clazz.getConstructor();\n}","typeGuard":"boolean isConfigurableDefault(Class<?> c) {\n  return !JsonConfigurator.findJsonCreatorFactoryMethod(c).isEmpty()\n      || java.util.Arrays.stream(c.getConstructors()).anyMatch(ctor -> ctor.getParameterCount() == 0);\n}","tryCatchPattern":"try { binder.bind(...); } catch (ProvisionException e) { if (e.getMessage().contains(\"zero-arg constructors\")) log.error(\"Add no-arg ctor or @JsonCreator to {}\", e.getMessage()); throw e; }","preventionTips":["Always give Druid config POJOs a public no-arg constructor or @JsonCreator factory","Smoke-test custom extension modules with a minimal Guice injector before shipping","Follow Druid's own config classes as templates"],"tags":["guice","jackson","configuration","startup"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}