I love how simple it is, but my company is at the point where squeezing every ounce out of our API servers is necessary. I've been fiddling around with Vert.x a little; but another option is just to use raw Servlets.
Read this to get some idea of what can be achieved with annotation processing: http://scg.unibe.ch/archive/projects/Erni08b.pdf
They do use so compiler API which are not stable interfaces, but even without that, you can go surprisingly far.
...So any sufficiently advanced magic is indistinguishable from science :)
With plain functions if I need to wrap requests or responses I just wrap the functions. With JAX-RS I need to find or write an appropriate annotation or start adding filters.
With plain functions I can share behaviour between resources by sharing functions.
Honestly, when JUnit was still "just Java" by that definition, it was a much worse framework.
Annotations in Java have always bothered me! Why are they needed? I don't need them in Clojure, Go, Haskell, C - similar behaviour is supplied by alternative means.