Prefer constructor injection over @Autowired fields
ID |
java.spring_prefer_constructor_injection |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Best Practice |
Language |
Java |
Tags |
best-practice, reliability, spring |
Description
Reports fields annotated with @Autowired. Field injection hides dependencies, prevents immutability, and makes unit testing harder. Constructor injection should be preferred.
Test code is excluded, since @Autowired field injection is the standard pattern there. A test is recognised first by its path, which is what catches the shapes an annotation check on the declaring class misses: the annotation sitting on a superclass, and a @Nested inner class whose own declaration says nothing about being a test. The annotation check is kept as a second line of defence for a test living outside a recognised test root, and walks outer classes.
Rationale
Field injection via @Autowired has several drawbacks:
-
Dependencies are hidden — the class’s API does not reveal what it needs.
-
Fields cannot be declared
final, so the object is mutable after construction. -
Unit testing requires reflection to set the private field, making tests fragile.
-
The class cannot be instantiated outside of a Spring container.
Since Spring 4.3, a single-constructor bean is auto-wired implicitly, so @Autowired is not even needed on the constructor.
// Bad - field injection
@Service
public class UserService {
@Autowired
private UserRepository repo;
}
Remediation
Replace field injection with constructor injection.
// Good - constructor injection, immutable
@Service
public class UserService {
private final UserRepository repo;
public UserService(UserRepository repo) {
this.repo = repo;
}
}