jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] Re: feedback from vraptor's and restfulie server side usage

From: Roberto Chinnici <roberto.chinnici_at_oracle.com>
Date: Wed, 16 Mar 2011 09:02:17 -0700

  I think these features cover a vast area, so if it's OK with you I'll
file a new issue for each item 2-7 (i.e. skipping the example in 1). We
can use JAX_RS_SPEC-59 as an umbrella issue.

On 3/12/11 10:29 AM, Guilherme Silveira wrote:
> Hi guys, sorry for the long email...
>
>
> This is the feedback that I have got and features we would love to see
> in JAX-RS 2.
> All those changes are backward compatible as I see them working
> currently with VRaptor. The code samples are from VRaptor real
> interfaces (and thus, implementations)...
>
>
> 1. (not a request, just showing an example) This is the final code I
> would like to see supported while *maintaining compatibility* (unless
> its decided not to). To do that, one can simply implement the
> following structures (2~):
>
> @Resource
> public class SoftwareController {
>
> public Software show(long id) {
> Software retrieved = dao.search(id);
> return retrieved;
> }
>
> }
>
>
> 2. Allows custom resource lookup:
> Extract the process of resource lookup and expose it. This allows
> anyone to provide its own UrlToResourceTranslator. The default is
> JAX-RS1 compatible.
> Other simple implementations are the ones where the verb GET is
> assumed by default, where getX means the get verb and so on. Every
> convention (as with the annotation approach)
> is a different implementation. Implementations can be combined through
> composition allowing backward *and* forward compatibility:
>
> public interface UrlToResourceTranslator {
>
> ResourceMethod translate(RequestInfo info)
> throws ResourceNotFoundException, MethodNotAllowedException;
>
> }
>
> 3. Support to a non-default parameter access convention using Java's
> debug information. This can be non-default so its up to the user to
> decide to use it. I surely prefer to be default:
>
> @Resource
> public class SoftwareController {
>
> @Get @Path("/software/{id}")
> public Software show(long id) {
> Software retrieved = dao.search(id);
> return retrieved;
> }
>
> }
>
> It can be achieved with backward compatibility by providing the interfaces:
> public interface ParameterNameProvider {
>
> String[] parameterNamesFor(AccessibleObject methodOrConstructor);
>
> }
> public interface ParametersProvider {
>
> Object[] getParametersFor(ResourceMethod method, List<Message>
> errors, ResourceBundle bundle); // the last two parameters are error
> related
>
> }
>
> This also allows someone to do this, *if he thinks that will boost his
> productivity*:
>
> @Resource
> public class SoftwareController {
>
> @Get @Path("/software/{id}")
> public Software show(Software software) {
> return retrieved; // yep, it was already loaded from the database!
> }
>
> }
>
> It also allows one to support file upload easily:
>
> @Resource
> public class SoftwareController {
>
> @Get @Path("/softwares")
> public void upMyBoy(File orAnyOtherRelatedInterfaceOrClass) {
> }
>
> }
>
>
> 4. Also support breaking the view layer from the control layer
>
> If a method does not serialize or return anything, assume a default
> behavior so you don't have to repeat yourself all over the place. For
> example, if the show method did not
> return anything it would go to "/software/show.jsp" or
> /software/show.json.jsp or /software/show.xml.jsp etc according to
> conneg. To implement it, the semantic model needs to be exposed again:
>
> public interface PathResolver {
> String pathFor(ResourceMethod method);
> }
>
> 5. URI Building
>
> This is one that bothers me a lot. We should be writing OO code, not
> xml-oriented, not annotation-oriented, not string-oriented. So why so
> many annotations, strings and just one object? This is the
> refactor-friendly version of URI builder that we use in VRaptor so
> people can refactor code and things are still working:
>
> @Resource
> public class UserController {
>
> // inject dao
> public User show(long id) {
> return dao.load(id);
> }
>
> }
>
> @Resource
> public class AdminController {
>
> private final Result result;
> private final UserDao dao;
>
> // easy to mock, inject => easy to test
> public AdminController(Result result, UserDao dao) {
> this.result = result;
> this.dao = dao;
> }
>
> public void create(User created) {
> User created = dao.save(prototype);
>
> // refactor friendly + no URI hell
> result.redirectTo(UserController.class).show(created);
>
> }
>
> }
>
> Of course, if there is a @Path annotation on top of the method, the
> framework knows how to understand that. To do so we provide, again,
> everything configurable (and default versions):
>
> public interface PathResolver {
> String pathFor(ResourceMethod method);
> }
> public interface Proxifier {
> <T> T proxify(Class<T> type, MethodInvocation<? super T> handler);
> }
>
> This is the one that allows hypermedia resource generation in a
> refactor-friendly, non-annotation based way, i.e.:
>
> public class Basket implements HypermediaResource {
>
> public void configureRelations(RelationBuilder builder) {
> builder.relation("self").uses(BasketsController.class).show(id);
> builder.relation("payment").uses(PaymentsController.class).create(id, null);
> }
>
> }
>
>
>
> 6. Allow custom resource creation, so injection can be done in any way
> the client wants. Not only Java EE support in all JAX-RS
> implementations (done by the user, of course, unless we want to
> implement them also):
>
> public interface Container {
> <T> T instanceFor(Class<T> type);
> <T> boolean canProvide(Class<T> type);
> }
>
>
> 7. The heart of a new request. The semantic model for the HTTP<->Resource layer:
>
> public interface Router {
> void add(Route route);
> ResourceMethod parse(String uri, HttpMethod method, MutableRequest request)
> throws ResourceNotFoundException, MethodNotAllowedException,
> IllegalStateException;
> <T> String urlFor(Class<T> type, Method method, Object... params);
> List<Route> allRoutes();
> }
>
> And a route:
>
> public interface Route {
>
> boolean canHandle(String uri);
> EnumSet<HttpMethod> allowedMethods();
> String urlFor(Class<?> type, Method m, Object... params);
> boolean canHandle(Class<?> type, Method method);
> int getPriority();
> String getOriginalUri();
> }
>
>
> 8. Allow ordered interceptors. Most of the time behavior can be
> composed by using interceptors (as in servlet filters), without the
> need for global variables (threadlocals). Interceptor order
> might also be important:
>
> @Documented
> @Retention(RetentionPolicy.RUNTIME)
> @Target(ElementType.TYPE)
> @Stereotype
> public @interface Intercepts {
> Class<? extends Interceptor>[] before() default ExecuteMethodInterceptor.class;
> Class<? extends Interceptor>[] after() default ResourceLookupInterceptor.class;
> }
>
> If a request lifecycle is handled by interfaced interceptors, *any*
> behavior can be changed without breaking compatibility.
> Validation, for instance, can be supported through an interceptor in
> one of several ways: based on the JSR, hibernate validations, hamcrest
> and so on
> Other examples of interceptors is the typical file download support:
>
> public InputStream download(Music m) {
> return manager.load(m).getStream();
> }
>
> Regards
>
>
>
> Guilherme Silveira
> Caelum | Ensino e Inovação
> http://www.caelum.com.br/