Singleton accessor with a reachable constructor
ID |
apex.maintainability.singleton_private_constructor |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
medium |
Remediation Effort |
low |
Resource |
Api Design |
Language |
Apex |
Description
Reports a class exposing a static getInstance accessor that returns its own type while declaring no private constructor, so callers can still build instances with new.
Rationale
A getInstance accessor is a promise that one instance exists per transaction, and code written against it relies on that: the cached custom settings, the accumulated DML rows, the "already ran" flag that keeps a trigger from recursing. As long as the constructor is reachable, any caller can bypass the accessor with new, get a second instance with its own empty state, and the guarantee quietly stops holding. In a trigger this shows up as the recursion guard failing to guard, and in a cache as a second round of SOQL against the same governor limits.
The following code illustrates the pattern detected by this rule:
// FLAGGED: Singleton accessor with a reachable constructor
public class SettingsCache {
private static SettingsCache instance;
private Map<String, String> values = new Map<String, String>();
public SettingsCache() {
values.put('mode', 'default');
}
public static SettingsCache getInstance() {
if (instance == null) {
instance = new SettingsCache();
}
return instance;
}
public String get(String key) {
return values.get(key);
}
}