Presently java:S2696
says why it’s an issue.
It would be nice for it to provide another solution especially if the code that is overwriting the field is an overridden method. One approach would be to use AtomicReference
Here’s an example of code that would be flagged
@Configuration
@RequiredArgsConstructor
public class HibernateStorageConfiguration implements InitializingBean {
private static final RedisConnectionFactory configuredRedisConnectionFactory;
private final RedisConnectionFactory redisConnectionFactory;
public static RedisConnectionFactory getConfiguredRedisConnectionFactory() {
return configuredRedisConnectionFactory;
}
@Override
public void afterPropertiesSet() {
configuredRedisConnectionFactory = redisConnectionFactory;
}
}
Here’s the fix
@Configuration
@RequiredArgsConstructor
public class HibernateStorageConfiguration implements InitializingBean {
private static final AtomicReference<RedisConnectionFactory> configuredRedisConnectionFactoryRef =
new AtomicReference<>();
private final RedisConnectionFactory redisConnectionFactory;
public static RedisConnectionFactory getConfiguredRedisConnectionFactory() {
return configuredRedisConnectionFactoryRef.get();
}
@Override
public void afterPropertiesSet() {
configuredRedisConnectionFactoryRef.set(redisConnectionFactory);
}
}
The text could be worded as
Correctly updating a
static
field from a non-static method is tricky to get right and could easily lead to bugs if there are multiple class instances and/or multiple threads in play. Ideally,static
fields are only updated fromsynchronized static
methods.Another approach would be to replace the
static
field to use astatic final
AtomicReference
,AtomicBoolean
,AtomicInteger
,AtomicILong
, orAtomicIDouble
which guarantees the value/reference is updated atomically.
Compiant code examples
public class MyClass {
private static int count = 0;
public syntchronized static void doSomething() { // Compliant
count++;
}
}
public class MyClass {
private static final AtomicInteger countRef = new AtomicInteger(0);
public void doSomething() {
countRef.incrementAndGet(); // Compliant
}
}