Saturday, January 6, 2018

Custom Sling Model Exporter in AEM 6.3

Hello Everyone,

You have already seen the magic of Sling Model Exporters in my previous blog.But there is something left with Sling Model Exporters which I would like to continue in this blog.

I have mentioned in the previous blog that we can have custom exporters in
Sling Model Exporters.
So let’s have some examples of creating custom exporters.Here I am going to demonstrate
GSON” and “JAXB” as two custom exporters in the concept of Sling Model Exporters.
ModelExporter Interface
To create a custom exporter, we need to create a service that implements ModelExporter
with these three methods:
modelExporter.PNG
Fig - Model Exporter Interface

Here we will see two implementations of ModelExporter Interface:
  • ModelExporter Example: GSON
@Component(service = ModelExporter.class)
public class NewExporter implements ModelExporter {
  public <T> T export(Object model, Class<T> clazz,
                      Map<String, String> options)
          throws org.apache.sling.models.factory.ExportException {
      return (T) new Gson().toJson(model);
  }
  public String getName()
  {
      return "gson";
  }
  public boolean isSupported(Class Model1)
  {
      return true;
  }
}

And then this “gson” exporter can be used in the Sling Model like this.
@Model(adaptables = Resource.class, resourceType = {"weretail/components/structure/page"}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = "gson", selector = "test",extensions = "json")
public class Model3 {
  @ValueMapValue(name = "jcr:title")
  private String title;
  public String getTitle()
  {
      return title;
  }
}

Fig - Response in JSON format using GSON Exporter
  • ModelExporter Example: JAXB
@Component(service = ModelExporter.class)
public class NewExporter implements ModelExporter {

  public <T> T export(Object model, Class<T> clazz,
                      Map<String, String> options)
          throws org.apache.sling.models.factory.ExportException {
          StringWriter sw = new StringWriter();
      try {
          JAXBContext jaxbContext =
                  JAXBContext.newInstance(model.getClass());
          Marshaller marshaller = jaxbContext.createMarshaller();
          marshaller.marshal(model, sw);
      } catch (JAXBException e) {
          e.printStackTrace();
      }
      return (T) sw.toString();
  }

  public String getName() {
      return "jaxb";
  }

  public boolean isSupported(Class Model1) {
      return true;
  }
}

And then this “jaxb” exporter can be used in the Sling Model like this.
@Model(adaptables = Resource.class, resourceType = {"weretail/components/structure/page"}, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
@Exporter(name = "jaxb", selector = "test",extensions = "xml")
@XmlRootElement
public class Model3 {
  @ValueMapValue(name = "jcr:title")
  private String title;
  @XmlElement
  public String getTitle()
  {
      return title;
  }
}


Fig - Response in XML format using JAXB Exporter

Let's have a demonstration video on Custom Sling Model Exporter:


Tips and Trick of Sling Model Exporters
  • Sling Model Exporters internally works on sling:resourceSuperType as well.If you have defined a resourceType in sling Model Exporter, it will check the resourceType of a request, if it doesn’t present it will go to its sling:resourceSuperType.

You can see the example here:
public class ResolveServletUsingPath extends SlingSafeMethodsServlet {
  @Reference
  private ModelFactory modelFactory;

  @Override
  protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
      Resource resource = request.getResourceResolver().getResource("/content/we-retail/ca/en/experience/jcr:content");
      try {
         response.getWriter().print( modelFactory.exportModelForResource(resource,"jaxb",Model3.class,new HashMap<>()));
      } catch (ExportException e) {
          e.printStackTrace();
      } catch (MissingExporterException e) {
          e.printStackTrace();
      }
  }

Let's have a demonstration video on Tips and Tricks of Sling Model Exporters:

If you have any query or suggestion then kindly comment or mail us at sgaem.blog02@gmail.com

Hope it will help you guys !!
Thanks and Happy Learning.

6 comments:

  1. Hi Team ,

    Please help on this. I couldn't run the below servlet.


    package com.mst.hackathon.core.servlets;

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.HashMap;
    import java.util.Map;

    import javax.jcr.Repository;
    import javax.servlet.Servlet;
    import javax.servlet.ServletException;

    import org.apache.felix.scr.annotations.sling.SlingServlet;
    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.api.SlingHttpServletResponse;
    import org.apache.sling.api.resource.ResourceResolverFactory;
    import org.apache.sling.api.servlets.HttpConstants;
    import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
    import org.apache.sling.commons.json.JSONException;
    import org.apache.sling.commons.json.JSONObject;
    import org.apache.sling.jcr.api.SlingRepository;
    import org.osgi.framework.Constants;
    import org.osgi.service.component.annotations.Component;
    import org.osgi.service.component.annotations.Reference;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;


    @SlingServlet(paths="/bin/mySearchServlet", methods = "GET", metatype=true)

    public class MstHackServlet extends org.apache.sling.api.servlets.SlingAllMethodsServlet {


    @Reference
    private SlingRepository repository;
    @Reference
    public void bindRepository(SlingRepository repository) {
    this.repository = repository;
    }


    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    protected void doGet(final SlingHttpServletRequest req,
    final SlingHttpServletResponse resp) throws ServletException, IOException {

    Map param = new HashMap();
    param.put(ResourceResolverFactory.SUBSERVICE, "datawrite");
    resp.setContentType("application/json");
    String keys[] = repository.getDescriptorKeys();
    log.error("Sling Folder with MstHackServlet>>>>>..MstHackServlet" );
    JSONObject jsonobject = new JSONObject();
    for(int i=0;i<keys.length;i++) {
    try {
    jsonobject.put(keys[i], repository.getDescriptor(keys[i]));
    } catch (JSONException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }


    resp.getWriter().println(jsonobject.toString());

    }
    }

    ReplyDelete
    Replies
    1. You are using some SCR annotations and some OSGI annotations in one class. Either use completely SCR or OSGI DS annotations.

      Delete
    2. Hi Shivani,

      Can you explain the above code and list out OSGI annotations and SCR annotations on the above code

      Delete
  2. I got the below error.

    The resource given by path ' /bin/mySearchServlet ' does not exist. Therefore no resource type could be determined!
    Candidate servlets and scripts in order of preference for method GET:
    com.day.cq.commons.servlets.NonExistingDispatcherServlet (OptingServlet)
    org.apache.sling.servlets.get.impl.DefaultGetServlet
    org.apache.sling.jcr.webdav.impl.servlets.SlingWebDavServlet

    ReplyDelete
  3. Hi Thanks for the tutorial it was very helpul. Do you know how can I change the character encoding in the response of the model exporter. Right now I'm using Jackson as exporter

    ReplyDelete
  4. Nice article for Sling Model information.

    Also found one more article for Adobe AEM with defined information

    https://aemintroduction.blogspot.com/

    ReplyDelete