-
Notifications
You must be signed in to change notification settings - Fork 20
09. Rendering
Resource methods in Utterlyidle can return different types of objects. When you return a Response object, you can explicitly set the headers and the entity. When you return a String or any other object then it will be automatically wrapped in a Response and whatever you return will end up in the entity body. Before you return the response to the client you can modify the response in a ResponseHandlersModule. Why would you want to do that?
Let's take a look at the example.
In your resource you have a method like that:
@GET
@Path("list")
public Model newsInCategory(@QueryParam("category") @DefaultValue("politics") String category) {
List<Article> news = newsRepository.getNews(category, 10);
return Model.model().add("news", news);
}
It returns a Model that contains a list of news in a given category. It doesn't matter what the model is. It can be a wrapper around a map or a more complex data structure. You could also return a map directly. Utterlyidle will wrap this Model in the Response entity.
In the ResponseHandlersModule you can define how this Model should be rendered:
import com.googlecode.utterlyidle.modules.ResponseHandlersModule;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.utterlyidle.ResponseHandler;
import com.googlecode.totallylazy.Pair;
...
public class UIModule implements ResponseHandlersModule, RequestScopedModule {
public ResponseHandlers addResponseHandlers(ResponseHandlers handlers) throws Exception {
Predicate<Pair<Request,Response>> predicate = ...;
ResponseHandler responseHandler = ...
handlers.add(predicate, responseHandler);
return handlers;
}
...
}
As you can see in the code above we need to define a predicate and a response handler. Predicate is an instance of com.googlecode.totallylazy.Predicate and it let's you define what Request, Response pair (com.googlecode.totallylazy.Pair) is eligible for being modified by a response handler.
You can manually create a predicate:
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.utterlyidle.Request;
import com.googlecode.utterlyidle.Response;
...
Predicate<Pair<Request, Response>> predicate = new Predicate<Pair<Request, Response>>() {
public boolean matches(Pair<Request, Response> requestAndResponse) {
...
}
};
Alternatively, you can use one of the built-in predicates:
import com.googlecode.totallylazy.Predicates;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.utterlyidle.handlers.HandlerRule;
...
Predicate<Pair<Request,Response>> predicate = Predicates.where(HandlerRule.entity(), is(instanceOf(Model.class)));
Once you defined a predicate, you can add a matching response handler:
import com.googlecode.utterlyidle.ResponseHandler;
import com.googlecode.utterlyidle.Response;
...
ResponseHandler responseHandler = new ResponseHandler() {
public Response handle(Response response) throws Exception {
...
}
};
Inside the handle method you can create a copy of the original response with a modified entity. E.g. you can take a model/map you returned in a resource and use a template engine to put the model values in a JSON, XML, HTML document or any other format you want.
Utterlyidle also gives you a higher level utility to handle entities:
import com.googlecode.utterlyidle.handlers.RenderingResponseHandler;
...
ResponseHandler renderer = RenderingResponseHandler.renderer(ModelRenderer.class);
public class ModelRenderer implements Renderer<Model> {
public ModelRenderer(TemplateEngine engine) {
....
}
public String render(Model value) throws Exception {
// translate model to String using your template engine of choice
}
}
In the code above, we registered a renderer for our Model. ModelRenderer can have a dependency on a template engine that translates our model/map to a textual representation.