April 1, 2020
Estimated Post Reading Time ~

How to Create Custom Adapters in Adobe CQ / AEM

Prerequisite: http://sling.apache.org/documentation/the-sling-engine/adapters.html

Use Case: You often have a case where you want to adaptTo from the existing object to custom Object or Provide adapter functionality for a custom object to an existing object.

Solution: There are mainly two ways you can use adaptTo
Case 1: You want the existing objects to be adaptable to custom objects. For example, you have a specific kind of node and you want Node or Resource to be adaptable to this object.

CustomObject myCustomObject = resource.adaptTo(CustomObject.class)
Or
CustomObject myCustomObject = node.adaptTo(CustomObject.class)
Or
CustomObject myCustomObject = <ANY Adaptable OBJECT>.adaptTo(CustomObject.class)

Case 2: You want the custom objects to be adaptable to an existing object. For example, you have a specific kind of resource and you want this to be adaptable to existing resources.

Node node = CustomObject.adaptTo(Node.class)
Or
Resource resource = CustomObject.adaptTo(Resource.class)
Or
<Any OOTB Adaptable> myObject = MycustomObject.adaptTo(<Any OOTB Adaptable>.class)

Case 1: Example
import javax.jcr.Node;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.adapter.AdapterFactory;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
*
* @author yogeshupadhyay
*
*/

@Component(metatype=false)
@Service (value=AdapterFactory.class)
public class CustomClassAdapterFactory implements AdapterFactory {

private static final Logger log = LoggerFactory.getLogger(CustomClassAdapterFactory.class);
private static final Class<CustomClass> YOUR_CUSTOM_CLASS = CustomClass.class;
@Reference
ResourceResolverFactory resourceResolverFactory;
@Property(name="adapters")
public static final String[] ADAPTER_CLASSES = {
YOUR_CUSTOM_CLASS.getName()
};

//This is where you define what all OOTB object it can adapt to You can also define this in //property of this component as mentioned in document above or //here http://labs.sixdimensions.com/blog/dklco/2012-05-07/new-cq-55-sling-adapters-console

@Property(name="adaptables")
public static final String[] ADAPTABLE_CLASSES = {
Resource.class.getName(), Node.class.getName()
};
public <AdapterType> AdapterType getAdapter(Object adaptable,Class<AdapterType> type) {
if(adaptable instanceof Resource){
return getAdapter((Resource) adaptable, type);
}
if(adaptable instanceof Node){
return getAdapter((Node) adaptable, type);
}
return null;
}
/**
* Adapter for resource
* @param resource
* @param type
* @return
*/
@SuppressWarnings("unchecked")
private <AdapterType> AdapterType getAdapter(Resource resource,Class<AdapterType> type) {
if(null == resource){
return null;
}
try{
if(type == YOUR_CUSTOM_CLASS){
//Logic to adapt your resource to resource
return (AdapterType) new CustomAdapter().adaptResourceToCustomClass(resource);
}
}catch(Exception e){
log.error("Unable to adapt resource {}", resource.getPath());
}
log.error("Unable to adapt resource {}", resource.getPath());
return null;
}
/**
* adapter for node
* @param node
* @param type
* @return
*/
@SuppressWarnings("unchecked")
private <AdapterType> AdapterType getAdapter(Node node,Class<AdapterType> type) {
if(null == node){
return null;
}
try{
if(type == YOUR_CUSTOM_CLASS){
return (AdapterType) new CustomAdapter().adaptNodeToCustomClass(node, this.resourceResolverFactory);
}
}catch(Exception e){
log.error("Unable to adapt node to Your custom class");
}
log.error("Unable to adapt node");
return null;
}
}


Here is how your CustomAdapter will look like

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author yogeshupadhyay
*/
public class CustomAdapter {
private static final Logger logger = LoggerFactory.getLogger(CustomAdapter.class);

protected CustomClass adaptResourceToCustomClass(Resource resource){
if(null!=resource){

//Do your logic to get all info
}
return <Your object after adapt>;
}

protected CustomClass adaptNodeToCustomClass(Node node, ResourceResolverFactory resolverFactory){
ResourceResolver adminResourceResolver = null;
try {
adminResourceResolver = resolverFactory.getAdministrativeResourceResolver(nu ll);
return adaptResourceToCustomClass(adminResourceResolver.getResource(node.getPath()));
} catch (LoginException e) {
logger.error(e.getMessage());
}catch (RepositoryException e) {
logger.error(e.getMessage());
}finally{
if(null!=adminResourceResolver){
adminResourceResolver.close();
}
}
return null;
}
}


Case 2: Example

import org.apache.sling.adapter.SlingAdaptable;
import org.apache.sling.api.resource.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;

public abstract class MyCustomClass extends SlingAdaptable {
protected static final Logger log = LoggerFactory.getLogger(MyCustomClass.class);

/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type == Resource.class) {
return (AdapterType) resource;
} else if (type == Node.class) {
return (AdapterType) resource.adaptTo(Node.class);
}
return null;
}
}


for this, you can use slingAdaptable class https://dev.day.com/docs/en/cq/5-6/javadoc/org/apache/sling/api/adapter/SlingAdaptable.html

One example (You can find more example here) http://svn.apache.org/repos/asf/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java

In pom.xml you need the following include. You can always find dependencies from HOST: PORT/system/console/depfinder

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


<dependency>
    <groupId>org.apache.sling</groupId>    <artifactId>org.apache.sling.adapter</artifactId>    <version>2.0.10</version>    <scope>provided</scope>
</dependency>


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.