Let's say that you have developed the persistence layer of your application using Roo. Now, you want to expose the CRUD operations and dynamic finder methods defined in the Roo-generated JPA entities to the outside world via a RESTful interface.
Roo supports exposing CRUD operations and dynamic finders of JPA entities via RESTful interfaces that use JSON documents for exchanging data. As JSON is used by Roo-generated RESTful interfaces, you can modify JSPX pages of the Roo-generated Spring Web MVC application to use Ajax to interact with these RESTful interfaces.
Roo provides two commands for adding JSON support to existing classes in the Roo project:
The json
add
and json
all
commands add the @RooJson
annotation to Java classes. the @RooJson
annotation results in the creation of a *_Roo_Json.aj
AspectJ ITD corresponding to the class annotated with the @RooJson
annotation. In this recipe, we'll look at the *_Roo_Json.aj
AspectJ ITD and at the @RooJson
annotation.
It is important to note that @RooJson
annotation allows you to control auto-generation of JSON related methods in the corresponding *_Roo_Json.aj
ITD file.
Delete the contents of the ch04-recipe
sub-directory inside the C:
oo-cookbook
directory.
Copy the ch04_web-app.roo
script into the ch04-recipe
directory.
Execute the ch04_web-app.roo
script that creates the flight-app
Roo project, sets up Hibernate as the persistence provider, configures MySQL as the database for the application, creates the Flight
and FlightDescription
JPA entities, and defines a many-to-one relationship between the Flight
and FlightDescription
entities. If you are using a different database than MySQL or your connection settings are different than what is specified in the script, then modify the script accordingly.
Start the Roo shell from the C:
oo-cookbookch04-recipe
directory.
Execute the controller
all
command to create controllers and JSPX views corresponding to JPA entities in the flight-app
project, as shown here:
.. roo> controller all --package ~.web
Execute the perform
eclipse
command to update the project's classpath settings, as shown here:
.. roo> perform eclipse
Now, import the flight-app
project into your Eclipse IDE.
To add the json
support execute the json
add
command against the Flight
JPA entity:
~.domain.Flight roo> json add --class ~.domain.Flight Updated SRC_MAIN_JAVA...domainFlight.java Created SRC_MAIN_JAVA...domainFlight_Roo_Json.aj Created SRC_MAIN_JAVA...webFlightController_Roo_Controller_Json.aj
Alternatively, add the @RooJson
annotation to the Flight.java
class. Adding the @RooJson
annotation to the Flight
entity has the same effect as executing the json
add
command against the Flight
entity. Adding the @RooJson
annotation will result in auto-generation of Flight_Roo_Json.aj
and FlightController_Roo_Controller_Json.aj
AspectJ ITDs.
Executing the json
add
command annotates the class (specified via class
argument)
with the @RooJson
annotation. If a class is annotated with the @RooJson
annotation, Roo creates a *_Roo_Json.aj
AspectJ ITD, which defines methods for converting objects of the class to JSON documents and vice versa.
We saw that when the json
addon
command was executed against the Flight
entity, it also resulted in the creation of a FlightController_Roo_Controller_Json.aj
AspectJ ITD. This ITD is created if the value of the @RooWebScaffold
's exposeJson
attribute in the FlightController.java
class is true
. If the @RooWebScaffold
's exposeJson
attribute is not specified, the default value is true
.
If the value of the exposeJson
attribute is true
and the JPA entity used as the form-backing object by the web controller is annotated with the @RooJson
annotation, Roo creates a *_Roo_Controller_Json.aj
ITD corresponding to the web controller class. This ITD defines JSON-based methods to perform CRUD operations and execute dynamic finder methods of the JPA entity. For instance, the FlightController_Roo_Controller_Json.aj
ITD introduces JSON-related methods into the FlightController.java
class for performing CRUD operations on the Flight
entity.
The following listing shows the methods defined in the Flight_Roo_Json.aj
ITD file that was created corresponding to the @RooJson
annotated Flight
entity:
import flexjson.JSONDeserializer; import flexjson.JSONSerializer; privileged aspect Flight_Roo_Json { public String Flight.toJson() { return new JSONSerializer().exclude("*.class"). serialize(this); } public static Flight Flight.fromJsonToFlight(String json) { return new JSONDeserializer<Flight>().use(null, Flight.class).deserialize(json); } public static String Flight. toJsonArray( Collection<Flight> collection) { ... } public static Collection<Flight> Flight.fromJsonArrayToFlights(String json) { ... } }
In the given code listing, Roo makes use of the Flexj son
library to incorporate support for serializing and deserializing JSON documents. The auto-generated JSON methods that are defined in Flight_Roo_Json.aj
are:
toJson
: Converts the current Flight
object into a JSON documentfromJsonToFlight
: Converts the JSON document passed as an argument into the Flight
objecttoJsonArray
: Converts a collection of Flight
objects into a JSON document containing an arrayfromJsonArrayToFlights
: Converts a JSON array document into a collection of Flight
objects@RooJson
, you can use the following attributes of @RooJson
annotation:The <class_name> refers to the name of the JPA entity class to which the JSON method applies. If the value of an element is ""
, then the corresponding method is not generated by Roo in the *_Roo_Json.aj
file.
It is important to note that you can use the json
add
command to add JSON support to any class. For instance, if you create a MyKlass
class and annotate it with @RooJson
, then Roo will auto-generate the given methods where the <class-name> is MyKlass
.
Excluding fields from serializing
To exclude a field from serializing to JSON format, all you need to do is to annotate the field or the corresponding getter method with the @JSON(include=false)
annotation.
In some JavaScript libraries, such as EXT JS, it is expected that the JSON document contains a root node. You can instruct Roo to set the root node of the generated JSON document either by using the rootName
argument of the json
add
command or by setting the rootName
attribute of the @RooJson
annotation. When the rootName
argument of the json
add
command is used, the generated @RooJson
annotation's rootName
attribute is set to the value of the rootName
command argument.
The following code snippet shows the Flight_Roo_Json.aj
ITD when the rootName
attribute of the @RooJson
annotation on the Flight.java
file is set to myRoot
:
import flexjson.JSONDeserializer; import flexjson.JSONSerializer; privileged aspect Flight_Roo_Json { public String Flight.toJson() { return new JSONSerializer(). rootName("myRoot").exclude("*.class").serialize(this); } ... public static String Flight.toJsonArray( Collection<Flight> collection) { return new JSONSerializer(). rootName("myRoot").exclude("*.class"). serialize(collection); } ... }
The given code shows that if the rootName
attribute of the @RooJson
annotation is specified, the toJson
and toJsonArray
methods of the *_Roo_Json.aj
ITD set the root node of the JSON document to myRoot
using the rootName
method of the JSONSerializer
object of Flexjson. The argument passed to the rootName
method is the value set for the rootName
attribute of the @RooJson
annotation.
The following code shows the FlightController_Roo_Controller_Json.aj
ITD, which was generated because the value of the @RooWebScaffold
's exposeJson
attribute is true
in the FlightController.java
file:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ResponseBody; privileged aspect FlightController_Roo_Controller_Json { @RequestMapping(value = "/{flightId}", method = RequestMethod.GET, headers = "Accept=application/json") @ResponseBody public Object FlightController. showJson(@PathVariable("flightId") Long flightId) { Flight flight = Flight.findFlight(flightId); if (flight == null) { HttpHeaders headers= new HttpHeaders(); headers.add("Content-Type", "application/text"); return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND); } return flight.toJson(); } ... }
The given code shows the showJson
method that the ITD adds to the FlightController.java
class. The showJson
method represents one of many JSON related methods defined in the ITD. The showJson
method returns a Flight
object as a JSON document. The showJson
method returns the JSON representation of the Flight
entity whose identifier is specified via request URI. If the request URI is /flights/10
, then the showJson
method returns the JSON representation of the Flight
entity instance whose identifier value is 10
. the @ResponseBody
annotation instructs the Spring Web MVC framework to write the response to the HTTP response body. The headers
attribute of the @RequestMapping
annotation specifies the request headers that must be present in the web request.
To test the JSON related methods defined in FlightController_Roo_Controller_Json.aj
, you can use the Poster add-on of Firefox or you can use the curl
command of Linux.
3.145.186.83