DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Composite Requests in Salesforce Are a Great Idea
  • Leveraging Salesforce Using Spring Boot
  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve
  • Unlocking the Benefits of a Private API in AWS API Gateway

Trending

  • Unlocking AI Coding Assistants Part 3: Generating Diagrams, Open API Specs, And Test Data
  • Integrating Security as Code: A Necessity for DevSecOps
  • Unlocking the Potential of Apache Iceberg: A Comprehensive Analysis
  • Beyond ChatGPT, AI Reasoning 2.0: Engineering AI Models With Human-Like Reasoning
  1. DZone
  2. Data Engineering
  3. Databases
  4. Using Apache Sling adaptTo API

Using Apache Sling adaptTo API

Sling and AdapterFactory classes are demonstrated with a contacts app.

By 
Francisco Ribeiro user avatar
Francisco Ribeiro
·
Aug. 17, 16 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
13.5K Views

Join the DZone community and get the full member experience.

Join For Free

apache sling provides a way to adpat sling related classes to our domain classes. the resource and resourceresolver interface provides the adaptto method, which adapts the objects to other classes.

image title

examples of the usage of this api would be when we want to get the jcr node instance from the current resource object. the api documentation can be found here .

in this post we will change our contact list application a bit to use the adaptto api.

creating our first adapter

the first thing we are going to do is to create our model class, contact . it basically will contain the attributes of our contact model. it will be a simple pojo:

public class contact {

    private string name;
    private string email;
    private string phone;
    private string address;
    private string contactimage;

    //..getters and setters
} 

now in order to be able to adapt resource objects to our contact class we need to create an adapterfactory . the adapter factories are registered as osgi services. for that we need to implement the adpaterfactory interface and the method getadapter . the adapterfactory have two key properties that should be defined:

  • adaptables : an array of the classes that can adapted to other classes defined in the adapters property
  • adapters : an array of the classes that can be adapted from the classes defined in the adaptables property

in our example we will create an adpaterfactory that will make us able to adapt an instance of resource class to our contact class.

we can see it below:

@component
@service
public class contactadapterfactory implements adapterfactory{

@property(name="adapters")
public static final string[] adapter_classes = {
contact.class.getname()
};

@property(name="adaptables")
    public static final string[] adaptable_classes = {
            resource.class.getname()
};


@override
@suppresswarnings("unchecked")
public <adaptertype> adaptertype getadapter(object adaptable, class<adaptertype> type) {
if(adaptable instanceof resource &&
type.equals(contact.class)) {
contact contact = new contact();
resource resource = (resource)adaptable;
valuemap valuemap = resourceutil.getvaluemap((resource)adaptable);
contact.setname(valuemap.get("name", string.class));
contact.setemail(valuemap.get("email", string.class));
contact.setphone(valuemap.get("phone", string.class));
contact.setaddress(valuemap.get("address", string.class));

resource contactimage = resource.getchild("contactimage");

if(contactimage != null) {
contact.setcontactimage(contactimage.getpath());
}
system.out.println(contact);
return (adaptertype)contact;
} else {
return null;
}
}

}

let’s explain it a bit:

we can see the adapters and adaptables properties being set below:

@property(name="adapters")
public static final string[] adapter_classes = {
        contact.class.getname()
};

@property(name="adaptables")
public static final string[] adaptable_classes = {
        resource.class.getname()
};

as we could see we’ve set the adaptables to resource class and the adapters to contact class.

then the next step is the getadapter method which is responsible to create an instance of the adapter class from the adaptable instance. we can see it below:

public <adaptertype> adaptertype getadapter(object adaptable, class<adaptertype> type) {
    if(adaptable instanceof resource &&
            type.equals(contact.class)) {
        contact contact = new contact();
        resource resource = (resource)adaptable;
        valuemap valuemap = resourceutil.getvaluemap((resource)adaptable);
        contact.setname(valuemap.get("name", string.class));
        contact.setemail(valuemap.get("email", string.class));
        contact.setphone(valuemap.get("phone", string.class));
        contact.setaddress(valuemap.get("address", string.class));

        resource contactimage = resource.getchild("contactimage");

        if(contactimage != null) {
            contact.setcontactimage(contactimage.getpath());
        }
        return (adaptertype)contact;
    } else {
        return null;
    }
}

it receives two arguments; adaptable, which is the instance of the adaptable class, and type, the class we are going to adapt to. basically we check if the adaptable is instance of our expected adaptable class and if the type matches our expected adapter class. if so, we create our contact instance and set its properties with the resource properties.

now if we deploy our osgi bundle, we can see our adapter registered in the apache felix web console on sling -> sling adapters section:

contact form

now we can change our jsp to use our adapter, so we can adapt our contact nodes to the contact class. we can see the changed part of the jsp below:

<c:foreach var="contact" items="${contacts}" >
  <sling:adaptto adaptable="${contact}" adaptto="com.xicojunior.contacts.models.contact" var="contactprops" />

  <li class="list-group-item">
          <div class="col-xs-12 col-sm-3">
          <c:if test="${not empty contactprops.contactimage }">
              <img src="${contactprops.contactimage}" alt="${contactprops.name}" class="img-responsive img-circle">
          </c:if>
          </div>
          <div class="col-xs-12 col-sm-9">
              <span class="name">${contactprops.name}</span><br>
              <span class="glyphicon glyphicon-map-marker text-muted c-info" data-toggle="tooltip" title="" data-original-title="${contactprops.address}"></span>
              <span class="visible-xs"> <span class="text-muted">${contactprops.address}</span><br></span>
              <span class="glyphicon glyphicon-earphone text-muted c-info" data-toggle="tooltip" title="" data-original-title="${contactprops.phone}"></span>
              <span class="visible-xs"> <span class="text-muted">${contactprops.phone}</span><br></span>
              <span class="fa fa-comments text-muted c-info" data-toggle="tooltip" title="" data-original-title="${contactprops.email}"></span>
              <span class="visible-xs"> <span class="text-muted">${contactprops.email}</span><br></span>
          </div>
          <div class="clearfix"></div>
      </li>
  </c:foreach>


the main change is that instead of adapting to valuemap class we are adapting to our contact class:

<sling:adaptto adaptable="${contact}" adaptto="com.xicojunior.contacts.models.contact" var="contactprops" />

then we can acces our pojo attributes using the jsp expression language.

the jsp became a little bit cleaner but we can make it a bit better.

as we can see, we still need to get the the contacts node using the taglib and to adapt each contact node to our contact class. let’s make it a bit better. let’s create another adapterfactory that will return us the complete contact list so we do not need to use all those taglibs.

for this, we will create another pojo, contactlist :

public class contactlist {
    private list<contact> contacts = new arraylist<contact>();

    //... getters and setters

    public void addcontact(contact contact) {
        this.contacts.add(contact);
    }

} 

now our adapterfactory will have as adaptable slinghttpservletrequest and as adapter contactlist. we can see it below:

@component
@service
public class contactlistadapterfactory implements adapterfactory{

@property(name="adapters")
public static final string[] adapter_classes = {
contactlist.class.getname()
};

@property(name="adaptables")
    public static final string[] adaptable_classes = {
            slinghttpservletrequest.class.getname()
};

public static string contacts_node = "contacts";

@override
@suppresswarnings("unchecked")
public <adaptertype> adaptertype getadapter(object adaptable, class<adaptertype> type) {
if(adaptable instanceof slinghttpservletrequest
&& type.equals(contactlist.class)) {

contactlist contactlist = new contactlist();
slinghttpservletrequest request = (slinghttpservletrequest)adaptable;

resource appresource = request.getresource();
resource contactsnode = appresource.getchild(contacts_node);
iterable<resource> contacts = contactsnode.getchildren();
iterator<resource> contactsiterator = contacts.iterator();
while(contactsiterator.hasnext()) {
contactlist.addcontact(contactsiterator.next().adaptto(contact.class));
}

return (adaptertype)contactlist;
}
return null;
}

}

this is very similar to our contactadapterfactory, but now adapting from slinghttpservletrequest class. basically we get the contacts node than its children. also we can see our first adapterfactory in action when we make:

contactsiterator.next().adaptto(contact.class) 

after we deploy our osgi bundle with our new adapter factory we can see it registered in the web console:

contact form

now we can rewrite our jsp to be like below:

<sling:adaptto adaptable="${slingrequest}" adaptto="com.xicojunior.contacts.models.contactlist" var="contactlist" />
<ul class="list-group" id="contact-list">
<c:set var="contacts" value="${contactlist.contacts}" />
<c:foreach var="contact" items="${contacts}" >
<li class="list-group-item">
        <div class="col-xs-12 col-sm-3">
        <c:if test="${not empty contact.contactimage }">
            <img src="${contact.contactimage}" alt="${contact.name}" class="img-responsive img-circle">
        </c:if>
        </div>
        <div class="col-xs-12 col-sm-9">
            <span class="name">${contact.name}</span><br>
            <span class="glyphicon glyphicon-map-marker text-muted c-info" data-toggle="tooltip" title="" data-original-title="${contact.address}"></span>
            <span class="visible-xs"> <span class="text-muted">${contact.address}</span><br></span>
            <span class="glyphicon glyphicon-earphone text-muted c-info" data-toggle="tooltip" title="" data-original-title="${contact.phone}"></span>
            <span class="visible-xs"> <span class="text-muted">${contact.phone}</span><br></span>
            <span class="fa fa-comments text-muted c-info" data-toggle="tooltip" title="" data-original-title="${contact.email}"></span>
            <span class="visible-xs"> <span class="text-muted">${contact.email}</span><br></span>
        </div>
        <div class="clearfix"></div>
    </li>
</c:foreach>
</ul>

now we just need to adapt the slingrequet to our contactlist and use the jstl core tags to iterate over the contacts and print display their properties using el.

conclusion

with the adaptto api we can convert the sling related objects to our model objects by using the adapterfactory classes. by checking the sling adapters console we can see that is used a lot in the apache sling framework.

the complete source code is my github repo in a new branch adapt_to.

in order to deploy the code you just need:

git clone https://github.com/fjunior87/sling-contact-list.git
cd sling-contact-list
git checkout adapt_to
mvn clean install -p autoinstallbundle

and access the application.

that’s it for today, i hope you enjoyed it.

thanks and see you in the next post.

Apache Sling API Contacts (Apple)

Published at DZone with permission of Francisco Ribeiro, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Composite Requests in Salesforce Are a Great Idea
  • Leveraging Salesforce Using Spring Boot
  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve
  • Unlocking the Benefits of a Private API in AWS API Gateway

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!