> But if you take a look at how Sinatra (or Rails) serialize the returned object, you notice the duplicated code. Especially if you want to return both JSON or XML based on the request header. To add to this, both frameworks do this serialization as part of the code logic that you have to write, instead of slapping annotation once...
I can't speak for Sinatra, but in Spray I'd just write a directive for this - maybe it exists already, but if not, it's a couple of lines - and then I can use it just like any of the built-in directives. And this is a perfect example of why "just code" is so powerful. Jersey is a very well-designed framework and I'm sure you can find examples where the built-in Jersey thing is better than the built-in Spray thing. But no framework is perfect, at some point you find yourself having to extend these things - and in Jersey's case, IIRC once you want to write your own annotation you need a magic .service file containing a class name to use to interpret that annotation. And then the only way to pass dependencies to that processor is by static global variables. Good luck refactoring that, and don't expect to be able to use hot code replace when debugging it. And good luck remembering how the mechanism works in six months' time. "Plain old code" has a lot to recommend it here.
> Let's take this further: exception mapping to http response code. In JAX RS, you can map application exception to certain WebApplicationException with specific http response code, I believe you have to handle them manually in Sinatra.
Again, trivial in Spray - I do my error-handling with Either and then I have a meta-marshaller that knows what to do with the error case. Better still, error handling isn't a special case - I do exactly the same thing if I have async code in my methods (can JAX-RS handle Futures? Can it handle a different kind of Future from a non-standard third-party library?). I can do exactly the same thing with a database-transaction monad, and then I can have session-in-view but in a principled, safe, zero-magic way. I can do the same thing to e.g. show debug traces if a special header is present - like Jersey's dynamic choice of serialization format that you were so impressed by, but it doesn't have to be built into the framework, it's just code that I can write myself.