-
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)
- SonarQube Server
-
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