Beginner Mistake 1: Forgetting that Spring uses Proxies

24.01.2019 by Jens in Spring Boot | Learning

Beginners and even long-time users of Spring can forget that the magic is all about proxies. Yep, when Spring works its magic, your classes are proxied.

By default, those are generated during runtime/startup when necessary. Let’s take a look at the following example and what’s wrong with it:

@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SecuritySchulungApplication.class, args);
    }

}

And one simple @Controller:

@RestController
public class TaskController {

    @Autowired
    private TaskRepository taskRepo;

    @PostAuthorize("hasRole('USER') and returnObject.user.username == principal.username")
    @GetMapping("/task/{id}")
    private Task getTask(@PathVariable("id") Long id) {
        return taskRepo.findById(id).orElse(null);
    }
}

TaskRepository is a Spring Data repository and irrelevant for the problem at hand.

Sympton

We’ll get a nice NullPointerException because taskRepo is null. Yet, Spring could start the app and did not complain it can’t fulfill the @Autowired dependency.

Strange, huh?

Problem

Can you spot it?

EnableGlobalMethodSecurity(prePostEnabled=true) enables proxies of the TaskController because it uses one of the supported annotations @PostAuthorize. So, during runtime, Spring generates a CGLib proxy for our Controller. So, every method call from the outside of the class is going through the proxy. The proxy does its magic and finally calls our class.

In this case, it does not, because the problem is that our Controller method getTask is set to private. In this case, the proxy magic does not work, and the call ends up in the proxy itself, but the dependencies are always null there; by design.

Solution

Setting getTask to public fixed it.

When you run in those errors, remember to check your method visibility.


Want content like this in your inbox each workday? No BS, spam or tricks... just useful content:

I understand and agree to the privacy policy