Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding stateful singleton beans

Today, we found this pattern in our code:

class Foo {
    private List<String> errors;

    public void addError(String error) { ... }
    public List<String> getErrors();
}

While the code seems to work, this is a singleton Spring bean and it's injected in several independent places and the consumers of the bean assume that they each have their own list of errors. So this introduces subtle bugs.

The obvious solution is to educate developers to avoid this kind of error but I was wondering if there is a static or runtime code analysis tool which can find this kind of bug.

For example, a bean postprocessor could analyze the bean before it's returned and look for private fields that aren't @Autowired.

like image 637
Aaron Digulla Avatar asked Jul 23 '13 08:07

Aaron Digulla


1 Answers

After pouring some more brains (ours and other peoples) on this, we came up with this approach:

  1. Install a BeanPostProcessor which makes sure that all singleton beans (i.e. where the scope in the bean definition is Singleton) have the custom annotation @Stateless on the actual bean type.

    We chose a custom annotation instead of reusing @Singleton since we need this functionality elsewhere, too.

    If the annotation is missing, the factory throws an error.

  2. In a unit test, we use ClassPathScanningCandidateComponentProvider with out custom annotation to locate all classes on the classpath. We can then do the complex and expensive tests to make sure the bean has no state that changes after the initial configuration (i.e. after the autowiring has happened).

The second step could become a little bit easier if we moved the autowired fields into the constructor but we don't like methods that take many, many arguments. It would be nice if Java or an IDE could generate builders from the bean code. Since that's not the case, we stick to autowired fields and/or setters.

like image 89
Aaron Digulla Avatar answered Sep 19 '22 06:09

Aaron Digulla