Using Sling Adapters

Sling offers an Adapter pattern to conveniently translate objects that implement the Adaptable interface. This interface provides a generic adaptTo() method that will translate the object to the class type being passed as the argument.

For example to translate a Resource object to the corresponding Node object, you can simply do:

Node node = resource.adaptTo(Node.class);

Use Cases

There are the following use cases:

Get implementation-specific objects.
For example, a JCR-based implementation of the generic Resource interface provides access to the underlying JCR Node.

Shortcut creation of objects that require internal context objects to be passed.
For example, the JCR-based ResourceResolver holds a reference to the request's JCR Session, which in turn is needed for many objects that will work based on that request session, such as the PageManager or UserManager.

Shortcut to services.
A rare case - sling.getService() is simple as well.

Null Return Value

adaptTo() can return null.

There are various reasons for this, including:

the implementation does not support the target type

an adapter factory handling this case is not active (eg. due to missing service references)

internal condition failed

service is not available

It is important that you handle the null case gracefully. For jsp renderings it might be acceptable to have the jsp fail if that will result in an empty piece of content.

Caching

To improve performance, implementations are free to cache the object returned from a obj.adaptTo() call. If the obj is the same, the returned object is the same.

This caching is performed for all AdapterFactory based cases.

However, there is no general rule - the object could be either a new instance or an existing one. This means that you cannot rely on either behavior. Hence it is important, especially inside AdapterFactory, that objects are reusable in this scenario.

How it works

There are various ways that Adaptable.adaptTo() can be implemented:

By the object itself; implementing the method itself and mapping to certain objects.

By an AdapterFactory, which can map arbitrary objects.
The objects must still implement the Adaptable interface and must extend SlingAdaptable (which passes the adaptTo call to a central adapter manager).
This allows hooks into the adaptTo mechanism for existing classes, such as Resource.

A combination of both.

For the first case, the javadocs can state what adaptTo-targets are possible. However, for specific subclasses such as the JCR-based Resource, often this is not possible. In the latter case, implementations of AdapterFactory are typically part of the private classes of a bundle and thus not exposed in a client API, nor listed in javadocs. Theoretically, it would be possible to access all AdapterFactory implementations from the OSGi service runtime and look at their "adaptables" (sources and targets) configurations, but not to map them to each other. In the end, this depends on the internal logic, which must be documented. Hence this reference.

Returns a convenient-to-use map of the properties, if this is a JCR-node-based resource (or other resource supporting value maps). Can also be achieved (more simply) by usingResourceUtil.getValueMap(Resource) (handles null case, etc.).

Returns the binary content of a "file" resource (if this is a JCR-node-based resource and the node type is nt:file or nt:resource; if this is a bundle resource; file content if this is a file system resource) or the data of a binary JCR property
resource.