Spring chose NullAway because it’s lightweight and integrates easily into large builds. It only checks for nullness, so it runs much faster than the Checker Framework and doesn’t add much overhead during compilation. That’s a big deal for a project the size of Spring where build times matter.
The Checker Framework is more powerful and can enforce stricter guarantees, but it requires more annotations, has a steeper learning curve, and is noticeably slower. On top of that, the current JSpecify annotations fit naturally with NullAway, while support in Checker Framework is less complete (for example, locals).
So it’s mainly a trade-off: Spring doesn’t need the full power of Checker Framework, but it does need something consistent, fast, and aligned with JSpecify.