VRaptor

Sharing objects with view

To register objects to be accessed by view, we use the include method:

@Controller
class ClientsController {

    @Inject
    private Result result;

    public void search(int id) {
        result.include("message", "Some message");
        result.include("client", new Client(id));
    }
}

Now the variables message and client are available to use in your template engine. It’s possible to register the object by invoking the include method with only one argument:

@Controller
class ClientsController {

    @Inject
    private Result result;

    public void search(int id) {
        result.include("Some message").include(new Client(id));
    }
}

In this case, the first invocation registers the string key and the second registers the client key. You can change this behavior writing your own TypeNameExtractor.

Custom PathResolver

By default, to render your views, VRaptor uses the convention:

public class ClientsController {
    public void list() { 
        //...
    }
}

The method above will render the view /WEB-INF/jsp/clients/list.jsp. However, if you want to change this behavior for some reason, or if you want to use another template engine like Freemarker or Velocity, you just need to extend the DefaultPathResolver class.

@Specializes
public class FreemarkerPathResolver extends DefaultPathResolver {
    protected String getPrefix() {
        return "/WEB-INF/freemarker/";
    }

    protected String getExtension() {
        return "ftl";
    }
}

Thus the logic will render the view /WEB-INF/freemarker/clients/list.ftl. If you want more customization, you can implement the PathResolver interface. Remember that you need to annotate your implementation with @Specializes annotation.

View

If you want to change the view of some logic, you can use the Result object:

@Controller
public class ClientsController {

    @Inject
    private Result result;

    public void list() {}

    public void save(Client client) {
        //...
        result.use(Results.logic()).redirectTo(ClientsController.class).list();
    }
}

There are these kinds of implemented views:

Results.logic() will redirect to another logic method.
Results.page() will redirect directly to one page, may be a JSP, HTML, or any URI on web application dir, or application context.
Results.http() send informations of HTTP protocol with status code and headers.
Results.status() send status code with more informations.
Results.referer() use the header Referer to do redirects or forwards.
Results.nothing() just returns the success code (HTTP 200 OK).
Results.xml() serializes objects to XML.
Results.json() serializes objects to JSON.
Results.representation() serializes objects on a format determined by request (_format parameter or header Accept).

Shortcuts on Result

Some redirects are often used, so were created shortcuts for them. The available shortcuts are:

result.forwardTo(“/some/uri”) result.use(page()).forward(“/some/uri”);
result.redirectTo(“/some/uri”) result.use(page()).redirect(“/some/uri)
result.permanentlyRedirectTo(“/some/uri”) result.use(status()).movedPermanentlyTo(“/some/uri”);
result.forwardTo(ClientsController.class).list() result.use(logic()).forwardTo(ClientsController.class).list();
result.redirectTo(ClientsController.class).list() result.use(logic()).redirectTo(ClientsController.class).list();
result.of(ClientsController.class).list() result.use(page()).of(ClientsController.class).list();
result.permanentlyRedirectTo(Controller.class) use(status()).movedPermanentlyTo(Controller.class);
result.notFound() use(status()).notFound()
result.nothing() use(nothing());

Furthermore if the redirect is to another method in the same Controller, we can use:

result.forwardTo(this).list() result.use(logic()).forwardTo(this.getClass()).list();
result.redirectTo(this).list() result.use(logic()).redirectTo(this.getClass()).list();
result.of(this).list() result.use(page()).of(this.getClass()).list();
result.permanentlyRedirectTo(this) use(status()).movedPermanentlyTo(this.getClass());

Redirect and forward

With VRaptor we can use both redirect or a forward to another logic or a JSP. Although they are Servlet API concepts, worth remembering the difference: the redirect happens on client side through HTTP codes that will make the browser access a new URL; forward happens on server side, totally transparent for the client/browser.

A good redirect usage example is with ‘redirect-after-post’ pattern. As example: when you add a client and after the submitted form, the client is returned to the client’s listing page. Doing it with redirect, we prevent the user refresh the page (F5) and resubmit all the request, resulting in duplicate data.

In the case of forward, an example of using is when you have a validation and it failed, often you want the user continues on the same screen of form with fulfilled data request, but internally you will make the forward to another business logic (that prepares the necessery data for the form).

Automatic Flash Scope

If you will add object in the Result and do a redirect, these objects will be available in the next request.

public void add(Client client) {
    dao.add(client);
    result.include("message", "Client successfully added");
    result.redirectTo(ClientsController.class).list();
}

list.jsp:

<div id="message">
    <h3>${message}</h3>
</div>

Accepts and the _format parameter

Many times, we need render different formats to the same logic. For example, we want return JSON instead of HTML. To do this, we can define the Header Accepts of request to accept the desired type, or put a _format parameter in the request.

If it’s a JSON format, the view rendered by default will be: /WEB-INF/jsp/{controller}/{logic}.json.jsp, in other words, in general will be render the view: /WEB-INF/jsp/{controller}/{logic}.{format}.jsp. If the format is HTML you don’t need put it in the filename. The _format parameter has priority over the header Accepts.

Ajax: building in view

To return a JSON in your view, you just need to provide the object to the view, and inside the view you form the JSON as desired. As example, your /WEB-INF/jsp/clients/load.json.jsp:

{ name: '${client.name}', id: '${client.id}' }

And the logic:

@Controller
public class ClientsController {

    @Inject
    private Result result;

    @Inject
    private ClientDao dao;

    public void load(Client client) {
        result.include("client", dao.load(client));
    }
}

Ajax: programmatic version

If you want the VRaptor automatically serialize your objects to XML or JSON, you can write in your logic:

import static br.com.caelum.vraptor.view.Results.*;
@Controller
public class ClientsController {

    @Inject
    private Result result;

    @Inject
    private ClientDao dao;

    public void loadJson(Client client) {
        result.use(json()).from(client).serialize();
    }
    public void loadXml(Client client) {
        result.use(xml()).from(client).serialize();
    }
}

The results will be simillar to:

{"client": {
    "name": "John"
}}

and xml:

<client>
    <name>John</name>
</client>

By default, just primitive types will be serialized (String, numbers, enums, dates), if you want include a field of non-primitive type you need include it explicitly:

result.use(json()).from(client).include("address").serialize();

Will result something like:

{"client": {
    "name": "John",
    "address" {
        "street": "Vergueiro"
    }
}}

You can also exclude some fields:

result.use(json()).from(user).exclude("password").serialize();

Will result something like:

{"user": {
    "name": "John",
    "login": "john"
}}

You can also exclude or include many fields.

result.use(json()).from(user).recursive().serialize(); // includes all fields recursively
result.use(xml()).from(user).exclude("email").serialize(); // exclude the email field
result.use(xml()).from(user).excludeAll().serialize(); // excludes all fields

The default behavior of JSON serialization is exclude atributes with null values, but it’s possible to change this behavior by calling serializeNulls method: ~~~ #!java result.use(json()).serializeNulls().from(new Person(“John”, null)).serialize(); ~~~

The resulting JSON will be the following: ~~~ #!javascript {“person”:{ “name”: “John”, “age”: null }} ~~~

You can add versioning capability to JSON based results. Through this resource it is possible to add API versioning. As a useful example, suppose that an API which returns a list of our system’s customers was created. The first version returns a list of customers defined by the structure that follows:

public class Customer {
    private String name;    
    private String group;

    // getters and setters omitted
}

Now suppose you’ve created a controller’s method as follows:

@Get{"/customers"}
public void customers() {
    List<Customer> customers = customersRepository.getAll();
    result.use(json()).from(customers).serialize();    
}

So far, so good. But what if we need to add a new attribute as a result. A new attribute that only makes sense to the new API version. How could we solve it? We could write a new class named as CustomerV2 with new attribute and rewrite the cotroller’s method so it could look like the following code:

@Get{"/{versionParameter}/customers"}
public void customers(String versionParameter) {
    double version = Double.parseDouble(versionParameter);
    if (version == 2.0) {
        result.use(json()).from(customersRepository.getAll()).serialize();
    } else {
        result.use(json()).from(customersRepository.getAllFromV2()).serialize();
    }
}

Certainly, that was not a well suited approach. Regarding that VRaptor comes with GSON lib from Google as a dependency, we can use the same Customer class just by inserting @Since annotation through our new versioned attributes. This annotation, tells that an attribute will be available since an specified version as follows at our new Customer class:

public class Customer {
    private String name;
    private String group;

    @Since(2.0)
    private Calendar registerDate;    

    // getters and setters omitted
}

Now, the our method could be rewritten as follows:

@Get{"/{versionParameter}/customers"}
public void customers(String versionParameter) {
    double version = Double.parseDouble(versionParameter);
    List<Customer> customers = customersRepository.getAll();
    result.use(json()).version(version).from(customers).serialize();
}

That’s all. Now our API clients could request for a specified versioned result.

The default XML Serialization implementation is based on XStream, then you can configure serialization by annotations or direct settings to XStream, just create the class:

@Specializes
public class CustomXStreamBuilder extends XStreamBuilderImpl {

    @Override
    protected XStream xmlInstance() {
        XStream xStream = super.xmlInstance();
        //your settings to XStream here
        return xStream;
    }
}

To configure the JSON serialization you can create a class that extends GsonJSONSerialization and overwrite the method getSerializer().

When serialiazing to JSON you can use the annotation SkipSerialization to omit the serialization of a field or class.

The following class was annotated with SkipSerialization, thus it’s fields will never be serialized to JSON:

@SkipSerialization
public class UserPrivateInfo {

    private String document;
    private String phone;
    private String address;
    
    // getters and setters
}

In this another class, the field password will not be serialized. The info field will not be serialized either due to the UserPrivateInfo class was annotated with SkipSerialization :

public class User {

    private String name;
    private String login;
    
    @SkipSerialization
    private String password;
    
    private UserPrivateInfo info;
    
    // getters and setters
}

Making the following call:

User user = ...;
result.use(json()).withoutRoot().from(user).recursive().serialize();

The obtained result is similar to:

{
    "name": "John Smith",
    "login": "john"
}

Note that the password field and the entire UserPrivateInfo wasn’t serialized.

Serializing Collections

When serializing collections, by default is put the tag list around elements:

List<Client> clients = ...;
result.use(json()).from(clients).serialize();
//or
result.use(xml()).from(clients).serialize();

Will result something like:

{"list": [
    { "name": "John" },
    { "name": "Mary" }
]}

or

<list>
    <client>
        <name>John</name>
    </client>
    <client>
        <name>Mary</name>
    </client>
</list>

You can customize the outside element, using the method:

List<Client> clients = ...;
result.use(json()).from(clients, "clients").serialize();
//ou
result.use(xml()).from(clients, "clients").serialize();

Will result something like:

{"clients": [
    {"name": "John"},
    {"name": "Mary"}
]}

or

<clients>
    <client>
        <name>John</name>
    </client>
    <client>
        <name>Mary</name>
    </client>
</clients>

The includes and excludes work as if you were applied in the element within the list. For example if you want include the address on the client:

List<Client> clients = ...;
result.use(json()).from(clients).include("address").serialize();

With result:

{"list": [
    {
        "name": "John",
        "address": { "street": "Vergueiro, 3185" }
    },
    {
        "name": "Mary",
        "address": { "street": "Vergueiro, 3185" }
    }
]}

JSON serialization without root element

If you want serialize an object in JSON format without naming it, you can do this with the method withoutRoot:

result.use(json()).from(car).serialize();

Will result something like:

{
  'car':
  {
    'color': 'blue'
  }
}

and

result.use(json()).withoutRoot().from(car).serialize();

Will result something like:

{
  'color': 'blue'
}

JSON and XML result indentation

By default, the serialization result is without indentation, that is useful to improve browser downloading time.

result.use(json()).indented().from(car).serialize();

Will result something like:

{
  'car':
  {
    'color': 'blue'
  }
}

Or you can also use the Environment to define the default indentation according with enviroment. In this case you can define that in DEVELOPMENT enviroment the indentation will be enabled, and in PRODUCTION enviroment will be disabled.

development.properties:

br.com.caelum.vraptor.serialization.xml.indented=true
br.com.caelum.vraptor.serialization.json.indented=true

production.properties:

br.com.caelum.vraptor.serialization.xml.indented=false
br.com.caelum.vraptor.serialization.json.indented=false

Note: The Enviroment settings has lower priority than code. In other words, if you define br.com.caelum.vraptor.serialization.xml.indented=false on Enviroment and call the indented method in your code, the result will be an indented JSON or XML.

LinkTo is a functionality that allows you create links on JSP pages without writing link, but just indicating the class of controller, and the method.

To the following controller:

public class ClientController {
    @Path("/client/list")
    public void list() {
        // some logic here
    }

    @Path("/client/{id}")
    public void show(Long id) {
        // some logic here
    }
}

To call the list and show methods respectively, we would have to write the JSP:

<a href="/client/list">list clients</a>
<a href="/client/1">show client 1</a>

Using the linkTo functionality, we can simplify the call to the list method:

<a href="${linkTo[ClientController].list()}">list clients</a>

Because the method have no parameters, you also can omit the parentheses.

<a href="${linkTo[ClientController].list}">list clients</a>

To call the show method, we can do a call like this:

<a href="${linkTo[ClientController].show(1)}">show client 1</a>

Instead of the fixed parameter, you can pass JSTL variables, for example:

<a href="${linkTo[ClientController].show(client.id)}">show client ${client.name}</a>

Automatic parameters inclusion

If you annotate your method with @IncludeParameters, all method parameters will be automatically included in the view.

So, instead of doing something like:

public void filters(Interval interval, Representative representative,
        Unit unit, BigDecimal maxValue, BigDecimal minValue) {

    // filter logic

    result.include("interval", interval);
    result.include("representative", representative);
    result.include("maxValue", maxValue);
    result.include("minValue", minValue);
}

Now you can do:

@IncludeParameters
public void filters(Interval interval, Representative representative,
        Unit unit, BigDecimal maxValue, BigDecimal minValue) {

    // filter logic
}

All the parameters will be available by JSP with EL: ${interval.begin}