{"record":{"id":"9b39d56843a53e90","repo":"SonarSource/sonarqube","slug":"constructor-annotations-missing-in","errorCode":null,"errorMessage":"Constructor annotations missing in: ","messagePattern":"Constructor annotations missing in: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sonar-core/src/main/java/org/sonar/core/platform/PriorityBeanFactory.java","lineNumber":109,"sourceCode":"    while (factory != null) {\n      if (factory.containsBeanDefinition(beanName)) {\n        return i;\n      }\n      factory = (DefaultListableBeanFactory) factory.getParentBeanFactory();\n      i++;\n    }\n    return null;\n  }\n\n  /**\n   * A common mistake when migrating from Pico Container to Spring is to forget to add @Inject or @Autowire annotations to classes that have multiple constructors.\n   * Spring will fail if there is no default no-arg constructor, but it will silently use the no-arg constructor if there is one, never calling the other constructors.\n   * We override this method to fail fast if a class has multiple constructors.\n   */\n  @Override\n  protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {\n    if (mbd.hasBeanClass() && mbd.getBeanClass().getConstructors().length > 1) {\n      throw new IllegalStateException(\"Constructor annotations missing in: \" + mbd.getBeanClass());\n    }\n    return super.instantiateBean(beanName, mbd);\n  }\n\n  private static class Bean {\n    private final String name;\n    private final Object instance;\n\n    public Bean(String name, Object instance) {\n      this.name = name;\n      this.instance = instance;\n    }\n\n    public String getName() {\n      return name;\n    }\n\n    public Object getInstance() {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/sonar-core/src/main/java/org/sonar/core/platform/PriorityBeanFactory.java#L91-L127","documentation":"PriorityBeanFactory overrides Spring's instantiateBean to fail fast when a bean class has more than one constructor but no explicit constructor annotation (@Autowired/@Inject) or XML-specified constructor resolution. With multiple constructors and no annotations, Spring would silently pick the no-arg constructor, so SonarQube refuses to guess and throws IllegalStateException naming the offending class.","triggerScenarios":"Registering a class with 2+ constructors (and no @Autowired on any constructor, no no-arg-only case handled as intended) into a SonarQube Spring container; the bean is instantiated without an explicit constructor definition.","commonSituations":"Adding a second constructor (e.g. for tests) to a component without adding @Autowired to the intended one; refactoring a component's constructor while keeping the old one for compatibility.","solutions":["Annotate the intended constructor with @org.springframework.beans.factory.annotation.Autowired (or @Inject).","Delete the extra constructor so the class has exactly one constructor.","Register the bean with an explicit constructor-arg definition so instantiateBean's multi-constructor check is not hit."],"exampleFix":"// before\nclass MyService {\n  MyService(Database db) { ... }\n  MyService() { ... } // second ctor -> IllegalStateException\n}\n// after\nclass MyService {\n  @Autowired\n  MyService(Database db) { ... }\n}","handlingStrategy":"type-guard","validationCode":"static boolean isContainerSafe(Class<?> beanClass) {\n  return beanClass.getConstructors().length <= 1\n    || Arrays.stream(beanClass.getConstructors())\n        .anyMatch(c -> c.isAnnotationPresent(Autowired.class) || c.isAnnotationPresent(Inject.class));\n}","typeGuard":"boolean hasSingleOrAnnotatedConstructor(Class<?> c) {\n  java.lang.reflect.Constructor<?>[] ctors = c.getConstructors();\n  return ctors.length == 1 || Arrays.stream(ctors).anyMatch(k -> k.isAnnotationPresent(Autowired.class));\n}","tryCatchPattern":"try {\n  container.add(MyService.class);\n} catch (IllegalStateException e) {\n  // e.getMessage() names the offending class: add @Autowired or remove extra constructor\n}","preventionTips":["Give Spring components exactly one constructor (use final fields + constructor injection).","Never keep old constructors around 'for tests' — instantiate test fixtures directly.","Lint for multi-constructor components registered in SonarQube containers."],"tags":["spring","dependency-injection","constructor-injection"],"backgroundTag":"invalid-state-transition","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}