WCMUsePojo To Sling Models in AEM - Component

How To Switch From WCMUsePojo To Sling Models in AEM Part One – Component

Looking back at Adobe Experience Manager’s (AEM) component development path (especially if you started from 6.0 or earlier), you likely have used a variety of ways to provide back-end logic to components. Beginning with JSP (or even scriptlets), to abstract component Java class with page context or binding objects, to Adobe’s WCMUse or your custom implementation of Use class, and most recently, WCMUsePojo class if you are working on AEM 6.1 or 6.2. With the release of AEM 6.3 and AEM Core WCM Components, we see that using Sling Models have been advocated by Adobe as the best practice. Now let’s take a look how you can switch from WCMUsePojo to Sling Models.

Note: this was tested on AEM 6.2, 6.3.

You probably created your project from Adobe Maven Archetype 10 or later. Great, because the archetype should’ve automatically generated some of the settings for you (i.e. Sling Models API, Sling-Model-Packages in maven-bundle-plugin) in order to use Sling Models, and also created a sample Sling Model class (core.models.HelloWorldModel) in your project. While that is great, you likely still need to do a bit more to use the latest Sling Models API and features.

For AEM 6.2

Because AEM 6.2 is built with Sling Models API and Implementation version 1.2, you will need to:

  1. Download the latest Sling Models API and Implementation bundles from Sling and then manually upload them to AEM bundles console (http://localhost:4502/system/console/bundles)
  2. Download AEM 6.2 Communities/Livefyre – FP2 and install the package
  3. Check your project’s POM files and make sure the version numbers for Sling Models API and Implementation are updated based on the ones installed in your AEM server. (Notice that a too high or too low version number in your POM file may cause the ‘imported package cannot be resolved issue’ for your project’s core bundle)
  4. In your core module POM file, check for maven-bundle-plugin, and make sure you have all packages that contain the model classes or interfaces in header Sling-Model-Packages, so that your models can be picked up

For AEM 6.3

Because AEM 6.3 is built on top of Sling Models API and Implementation version 1.3, and the latest version for those are also 1.3, you don’t need to manually import the updated bundles to AEM in order to use the 1.3 features (for example, Exporter Framework and Associating a Model Class with a Resource Type).

You will just need to check #3 and 4 from above to make sure your project is set up properly for Sling Models.

If Sling has a new major release that you want to use, you can still manually import them into your 6.3 server and check in Adobe’s documentation for additional package to be installed in order to support the code at that time.

Here are some sample of dependencies you may need for your project to use Sling Models.

<dependency>
    <groupId>org.apache.sling</groupId>
    <artifactId>org.apache.sling.models.api</artifactId>
    <version>1.3.0</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>org.apache.sling</groupId>
    <artifactId>org.apache.sling.models.jacksonexporter</artifactId>
    <version>1.0.4</version>
    <scope>provided</scope>
</dependency>

For a complete reference, I have created a blog project that’s available on Github. I will start using it to put source codes for the demonstration of all my blogs.

Notice that this project was created from Adobe Archetype 10 and set up for AEM 6.3. If you deploy the code to AEM 6.2 or lower, you may find some imported packaged cannot be resolved. To fix that, you can either lower the version number for related packages in the POM files, or manually upload the latest version of related bundles in AEM bundles (http://localhost:4502/system/console/bundles).

Since Sling Models are annotation-driven Plain Old Java Objects (POJOs), annotations are used a lot. They allow you to map resource properties, assign default values, inject OSGI services and much more.

For example, in my blog project, I have a title component at /apps/blog/components/content/title. And I created two classes related to it, one with WCMUsePojo API, org.myorg.blog.core.use.TitleUse, the other with Sling Models, org.myorg.blog.core.models.TitleModel.

In the TitleModel class, the @Model is required to register the Java class as a Sling Model. You can specify adaptables, resourceType, injection strategy and validation in this annotation. In that class, I was adapting a SlingHttpServletRequest object, and associating the class with the title resource type, so it can be used in the Sling Model exporter later on. Usage of Model annotation can be found in Sling API documentation.

The @Exporter is for Jackson exporter, which basically scan through all the getters that follow the naming convention in the class and serialized them into JSON format. You will need to add a resourceType element in the @Model, and point it to your component’s resourceType. You can request the Sling Models JSON for title component with a “model” selector and “json” extension.

I then used couple injector-specific annotations to get the sling binding object, and map component properties.

The @PostConstruct is usually for initModel()or other methods to call after model option is created. It’s similar to the activate() method in WCMUsePojo that it holds the main logic for processing the data.

You can find reference of all available annotations here.

Lastly in TitleModel class, you will find the getters for the class to return the value for HTL to consume.

After completing my experiment of creating two Java classes for a title component, I’ve found the major differences between implementing with WCMUsePojo and Sling Models are:

  1. WCMUsePojo will need to be extend from that class, whereas Sling Models can be standalone class with @Model annotation and no keyword
  2. With Sling Models, it’s simpler and cleaner to retrieve common objects or property values, instead of writing more line of code to use API
  3. You may use Felix annotation @Reference to reference to an available OSGI service, whereas in Sling Models, you will use @Inject or @OSGiService
  4. With Sling Models API 1.3, you can serialize the model and export it as a JSON file with Jackson exporter, so your front-end application can leverage the same model. It’s not available for WCMUsePojo.
  5. For WCMUsePojo, you will need to overwrite the activate() method, whereas in Sling Models, your init method will be called in the @PostConstruct annotation

It’s also possible to create your own custom injectors and annotations. For custom injectors, you will create a OSGI service that implements the org.apache.sling.models.spi.Injector interface. And for custom annotations, you will create a OSGI service that implements the org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactor interface. Also, you can use servicing ranking to change priority of the injectors. They are invoked from lowest number to highest. Available injectors ranking and information can be found here.

And if you are planning to develop custom injector and annotation, you can reference the source code of OOTB injectors and ACS AEM Commons project.

In terms of presentation layer, which is HTML Template Language (HTL) in AEM, I find both WCMUsePojo and Sling Models are being used the same way, with data-sly-use block statement and calling the getter from Java class.

Overall, I think Sling Models are pure POJOs that separate logic and presentation. They are clean and annotation driven, but also extensible with custom injectors and annotations. Are you ready to make the change and let WCMUsePojo.adaptTo(Sling Models.class)? If you are looking for information on how to make the switch in terms of the JUnit test, check out part two of this blog post. Happy coding.

Subscribe to the Perficient Digital Weekly Digest

* indicates required

Leave a Reply