ninjaframework / ninja

Ninja is a full stack web framework for Java. Rock solid, fast and super productive.
http://www.ninjaframework.org
Apache License 2.0
1.91k stars 518 forks source link

Ninja Jaxy Resolution not working as expected. #379

Open BjoernAkAManf opened 9 years ago

BjoernAkAManf commented 9 years ago

Hello, im working on a plain and simple json api and thus i was not pleased to map each method in the controller by hand and i found jaxy quite handy. Thank you.

My articles controller will map the following (CRUD) operations: GET /api/articles -> List all articles GET /api/articles/:id -> List specific article POST /api/articles -> Creates new Article. PUT /api/articles/:id -> Updates specific article DELETE /api/articles/:id -> Deletes specific article

Based on #299 it should be possible to create Paths without @Path. This is crucial, as @Path("") looks nasty. [I would not mind having to add a trailing slash, as the jaxy tests show].

package controllers;

import com.google.inject.Singleton;
import link.mcseu.controllers.APIController;
import ninja.Result;
import ninja.jaxy.GET;
import ninja.jaxy.Path;

@Singleton
@Path("/articles")
public class ArticlesController extends APIController {
    @GET
    public Result get() { 
        return wrap("articles", new Article[] {
            new Article(1, "Generic Article I", 10.99),
            new Article(2, "Generic Article II", 3.99),
            new Article(3, "Generic Article III", 1.99),
            new Article(4, "Generic Article IV", 2),
            new Article(5, "Generic Article V", 400),
        });
    }

    private static class Article {
        public final int id;
        public final String name;
        public final double price;

        Article(int id, String name, double price) {
            this.id = id;
            this.name = name;
            this.price = price;
        }
    }
}
package controllers;
import com.google.common.collect.ImmutableMap;
import ninja.Result;
import ninja.Results;
import ninja.jaxy.Path;

@Path("/api")
// TODO: Javadoc
// TODO: Testing
public abstract class APIController {
    protected Result wrap(String key, Object data) {
        return Results.json().render(ImmutableMap.builder()
                .put(key, data)
                .build()
        );
    }
}

Using above Code the route will not be loaded.

I have played around with the jaxy module, but i didnt came up with something productive. For development purposes, i added a default value ("") to @Path so i can work until this issue is resolved.

raphaelbauer commented 9 years ago

Not sure about this one. @gitblit may know more about this...

gitblit commented 9 years ago

For now you could move the @Path("/articles") declaration to the method.

Jaxy does support @Path-less method registration BUT it registers the method with a trailing forward-slash. If you accessed the above example at /articles/ it should work. Why does it do that? I can't remember - but it was deliberate. I'm inclined to think it was the wrong choice.

To change this behavior we would need to replace "/" with "" at this line: https://github.com/ninjaframework/ninja/blob/develop/ninja-jaxy-routes/src/main/java/ninja/jaxy/JaxyRoutes.java#L116

And adjust the unit-test here: https://github.com/ninjaframework/ninja/blob/develop/ninja-jaxy-routes/src/test/java/controllers/ApplicationControllerTest.java#L298

raphaelbauer commented 9 years ago

Thanks for the explanation :)

BjoernAkAManf commented 9 years ago

No, it does not register any Route. Thats the whole issue. I did a test with and without / and both did not work. The output of the registered routes did reflect the same results @gitblit . I'm certain the class was not found and i think jaxy should consider the configured application package (but thats out of the scope for this issue anyway).

I'll have to review my project again and will provide further information as soon as my cloud is synced.

wdimac commented 8 years ago

Just ran into something related to this. Looking at JaxyRoutes.registerMethods(), if no @Path is declared on the controller, controllerPaths comes back as an empty list. Therefore, no paths will be registered at all, even if they are declared at the method level.