Java - S6832 false positive for proxied non singleton classes

  • What language is this for?
    Java

  • Which rule?
    S6832

  • Why do you believe it’s a false-positive/false-negative?
    The given sample for non-compliant code is actually the suggested and correct way to inject beans with non-singleton scopes (e.g. request or session) into a singleton bean.

  • Are you using

    • SonarQube Server
      Yes, Enterprise Edition (v2025.3.1)
  • How can we reproduce the problem?

This is a NonSingleton-Bean as explained as non compliant code (in ScopedProxyMode.TARGET_CLASS)

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class NonSingletonSample {

  private static final Logger log = LoggerFactory.getLogger(NonSingletonSample.class);

  private int number = 0;

  public NonSingletonSample() {
    log.info("new NonSingletonSample()");
  }

  public int getNumber() {
    return number;
  }

  public void setNumber(int number) {
    this.number = number;
  }

}

We use this NonSingletonBean inside a RestController-Implementation (which is a singleton)

@RestController
public class SpringBootSonarAppController {

  private static final Logger log = LoggerFactory.getLogger(SpringBootSonarAppController.class);

  @Autowired
  private NonSingletonSample nonSingletonSample;

  @GetMapping(path = "/number")
  public String getNumber() {
    log.info("nonSingletonSample.getNumber() returns: %d".formatted(nonSingletonSample.getNumber()));
    return String.valueOf(nonSingletonSample.getNumber());
  }

  @GetMapping(path = "/number/{mynumber}")
  public String getMyNumber(@PathVariable final Integer mynumber) {
    log.info("Set current number to new value %d".formatted(mynumber));
    nonSingletonSample.setNumber(mynumber);
    log.info("nonSingletonSample.getNumber() returns: %d".formatted(this.nonSingletonSample.getNumber()));
    return String.valueOf(this.nonSingletonSample.getNumber());
  }

}

This Unit-Test proves, that with every call of the nonSingletonSample, a new instance is created

@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class SpringBootSonarAppControllerTests_NonSingletonSample
{

	private static final Logger log = LoggerFactory
		.getLogger(SpringBootSonarAppControllerTests_NonSingletonSample.class);

	@Autowired
	WebApplicationContext wac;

	MockMvc mockMvc;

	@BeforeEach
	void setup()
	{
		this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
		log.info("SpringBootSonarAppControllerTests_NonSingletonSample.setup()");
	}

	@Test
	void testGetNumberMultiple() throws Exception
	{
		log.info("First call of NonSingletonSample should return 0");
		this.mockMvc.perform(get("/number")).andExpect(content().string("0"));
		log.info("Second call sets the value to 12 and returns it");
		this.mockMvc.perform(get("/number/12")).andExpect(content().string("12"));
		log.info("Third call returns 0 again, since a new instance of NonSingletonBean is created");
		this.mockMvc.perform(get("/number")).andExpect(content().string("0"));
	}

}

The log output shows, that a new instance of nonSingletonSample is created with every call

 narAppControllerTests_NonSingletonSample : Started SpringBootSonarAppControllerTests_NonSingletonSample in 1.136 seconds (process running for 1.945)
 o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
 o.s.t.web.servlet.TestDispatcherServlet  : Initializing Servlet ''
 o.s.t.web.servlet.TestDispatcherServlet  : Completed initialization in 0 ms
 narAppControllerTests_NonSingletonSample : SpringBootSonarAppControllerTests_NonSingletonSample.setup()
 narAppControllerTests_NonSingletonSample : First call of NonSingletonSample should return 0
 d.s.d.s.beans.NonSingletonSample         : new NonSingletonSample()
 d.s.d.s.SpringBootSonarAppController     : nonSingletonSample.getNumber() returns: 0
 narAppControllerTests_NonSingletonSample : Second call sets the value to 12 and returns it
 d.s.d.s.SpringBootSonarAppController     : Set current number to new value 12
 d.s.d.s.beans.NonSingletonSample         : new NonSingletonSample()
 d.s.d.s.SpringBootSonarAppController     : nonSingletonSample.getNumber() returns: 12
 narAppControllerTests_NonSingletonSample : Third call returns 0 again, since a new instance of NonSingletonBean is created
 d.s.d.s.beans.NonSingletonSample         : new NonSingletonSample()
 d.s.d.s.SpringBootSonarAppController     : nonSingletonSample.getNumber() returns: 0

Additional informations:

  • Setting the Proxy-Mode of NonSingletonSample to ScopedProxyMode.DEFAULT instead of ScopedProxyMode.TARGET_CLASS, the following error message occures
Error creating bean with name 'nonSingletonSample': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton

This message advices to use ScopedProxyMode.TARGET_CLASS for the given scenario of using NonSingleton-Beans inside Singleton-Beans.

  • Autowired-Annotations are not needed if there is only one constructor. Injection will work automatically in this case. The rule S6832 does not consider this and only checks for annotated beans