JAX-RS

One of the exciting new features in Liferay Digital Experience Platform (DXP) 7 is its built-in support for creating and deploying JAX-RS based REST services. Among other things this can enable the rapid development of modern web applications in Liferay DXP using Ajax-based frameworks such as AngularJS and React.

JAX-RS is the JEE standards based approach for developing REST web services. In terms of developing the actual services it primarily uses an annotation-based approach, where one decorates methods in Java classes with annotations such as @GET, @POST, @Path etc. to describe the URL/HTTP routing used to reach the method (service).

We at XTIVIA have created a basic example (click here to access the code on GitHub) of how to create JAX-RS based REST services in Liferay DXP. Our example implements two REST resources:

  • A simple GET service that returns a transformed/abbreviated representation of the currently logged in user in JSON
  • A full in-memory CRUD implementation (GET, PUT, POST, DELETE) for a hypothetical set of Person objects. This is the same sample class that is included as a part of the XTIVIA Services Framework (XSF) which has been ported to use JAX-RS

This project builds off of the excellent original example created by Ray Augé of Liferay and adds the following:

  • The sample project is self-contained in a single Gradle project/build (no parent project dependencies)
  • Demonstrates how to write a function that runs when the bundle is deployed/activated in the OSGi container
  • Shows how to include multiple REST resources (e.g. /users, /people) in a single application (OSGi bundle)
  • Leverages the Jackson JAX-RS content handler for simplified conversion of Java POJOs to/from JSON
  • Includes a simple technique in the Gradle build file for automatically including dependent JARs in both the OSGi classpath and in the packaged OSGi bundle (JAR), i.e., manual editing of a bnd.bnd file is not required as new dependencies are added to the build script
  • Demonstrates how to use the new OSGi Config API (and Liferay’s support for it in DXP in terms of autogenerated UI) to provide configuration parameters for your services

We won’t have space to cover all of these features in this original post, so we will come back to them in subsequent articles. However all of the features described above are fully functional in the source project on GitHub so feel free to review that as a working example in the meantime.

Getting Started

To get started clone the repository from the XTIVIA GitHub repository. Then execute the gradle build by running “gradlew” inside the project directory. The build will produce an OSGi bundle (JAR) that you can then drop into the “deploy” directory of a Liferay DXP (or Liferay 7 CE) deployment and you will have access to the REST services implemented by the example. (See the README on GitHub for a full list of the available REST endpoints).

Reviewing the Code

We do not have space here to do an exhaustive review of the code included in our sample application, but we will highlight some basic aspects of the code and encourage you to review the source on GitHub. We will also review more aspects of this particular sample application in future posts.

The application “starts” with the code snippet below (from SampleRESTApplication.java).

@Component(immediate=true, 
   service=Application.class,
   configurationPid = "com.xtivia.rest.SampleRESTConfiguration",
   configurationPolicy = ConfigurationPolicy.OPTIONAL,
   property={"jaxrs.application=true"} 
)
@ApplicationPath("/samples")
public class SampleRESTApplication extends Application {
	
  @Override
  public Set getSingletons() {	
    Set singletons = new HashSet();	
    //add the automated Jackson marshaller for JSON
    singletons.add(new JacksonJsonProvider());
    // add our REST endpoints (resources)
    singletons.add(new LiferayUserResource(this));
    singletons.add(new PeopleResource());
    return singletons;
  }

The values in the @Component annotation indicate to Liferay DXP that this module will be providing JAX-RS services and that the application will be configurable using the OSGi Configuration API. The @ApplicationPath annotation indicates what the top level URL segment will be for all services exposed by this application. The overridden getSingletons method then enumerates to the JAX-RS runtime what providers and resources this application will be providing.

JAX-RS has the concept of “providers” which are classes that plug into the JAX-RS framework and provide useful features such as filters/interceptors, content marshalling, etc. In this case we are using the Jackson library’s builtin facility (JacksonJsonProvider) for automatically converting Java objects to/from JSON. Finally we add two “resource” classes that will define our respective REST services.

Now let’s examine the code from one of our “resources”, in this case LiferayUserResource.java. This service demonstrates how one can obtain the currently logged in user, access the Liferay User object for that user, and then return a simplified JSON representation of that User object.

@GET
@Path("/current")
@Produces("application/json")
public LiferayUser getCurrentUser(@Context HttpServletRequest request) {
  UserLocalService userLocalService = _app.getUserLocalService();
  String userid = request.getRemoteUser();
  LiferayUser liferayUser = null;
  try {
    if (userid != null && userLocalService != null) {
      User user = userLocalService.getUser(new Long(userid));
      if (user != null) { liferayUser = new LiferayUser(user);  }
    }
  } catch (Exception e) {
    e.printStackTrace();
  }
		
  if (liferayUser != null) {
    return liferayUser;
  } else {
    throw new WebApplicationException(Response.Status.NOT_FOUND);
  }
}

Again in the interest of space we will not go into exhaustive detail on this implementation and encourage you to review the code, but you can see how easy it is to obtain the user ID of the logged in user, use that value to obtain the full User object from Liferay, and then return an abbreviated representation of that to the client (LiferayUser). Also note that we did not have to do anything to handle the conversion from Java to JSON–that was completed handled for us by the JacksonJSONProvider that we previously registered in our application.

This REST service is now available at http://localhost:8080/o/rest/samples/users/current (see GitHub for a more thorough description of this URL structure). Our example application also provides a full in-memory CRUD implementation for another service that manages a list of “people” (PeopleResource.java) so that you can see other ways of using JAX-RS facilities to implement a complete REST backend.

So that’s it for a quick introduction to writing REST services in Liferay DXP. Please refer to the source project on GitHub for more information and be sure to watch this space for further articles about our example, including how we use Gradle to build a self-contained project that includes other libraries like Jackson, as well as the use of the new Configuration API for automatic configuration objects.

If you need assistance with your Liferay DXP Implementation or just need some advice, do reach out to us.

 

Additional Reading

You can also continue to explore Liferay DXP by checking out The Top 10 New Features in Liferay DXP 7 and Liferay DXP Audience Targeting 2.0 Overview from a functional perspective or Top 5 New Features in Liferay DXP UI Development or Top 5 DevOps Features in Liferay DXP from a DevOps perspective.

If you liked what you read, please share this helpful post with your friends and co-workers on your favorite social media here:

Share This