Hi Rofe,

Raphael Wegmueller schrieb:
> First of all: I've read the JavaDoc and know
> SyntheticResource#adaptTo() returns null "by design". But I'd still
> like to know if there are any deeper meanings behind this.


Actually SyntheticReosurce.adaptTo(Class) implements
Resource.adaptTo(Class) which in turn is Adaptable.adaptTo(Class) which
I will now be talking about. The deeper meaning is simply that
Resource.adaptTo is a great feature and there are a lot of reasons, why
an adaptTo request cannot be fullfilled. Since such "failure" is
foreseen throwing an exception is bad here IMHO. Rather we have decided
to say, prepare to get null as a result and check it before using it.

This makes both the provider and the consumer easier to implement.

Now, for the SyntheticResource.adaptTo(Class) implementation: The
SyntheticResource class is defined in the Sling API. As such it has
neither access to a concrete implementation of the AdapterManager
service interface to delegate the adaptTo call to nor has the
SyntheticResource access to any BundleContext to find the AdapterManager
service.

Hence, the SyntheticResource, like the NonExistingResource, can only
return null as a result to the adaptTo call.


> I'm building a more complex component using an API relying on the
> ability to adapt resources to other classes/interfaces, which I think
> provides a very convenient and elegant way to retrieve instances of
> classes without actually having to publicly export them in the bundle.
> So for example, I built an interface MyStuff with a private
> MyStuffImpl, and a MyStuffAdapterFactory implementing AdapterFactory
> which handles the actual adapting.
> 
> It all works fine as long as I have an underlying node associated with
> the resource path (which I normally do). But when I statically
> included a component without an existing underlying node, e.g. using
> <sling:include path="fake" resourceType="my/resource/type" /> in the
> JSP of another component, I ran into the obvious problem.
> 
> Although <sling:defineObjects/> is giving me a resource of type
> SyntheticResource with the correct path and resourceType (which made
> me think that was the purpose of having such a 'virtual' resource
> implementation), the fun ends with resource.adaptTo(MyStuff.class)
> always returning null.
> 
> That leaves me with several options, none of which are exactly delightful:
> 
> 1) Make sure the fake node is always in the repository: This extends
> my creation routine, bloats the repository and leaves me with a
> backward compatibility issue; I'd have to provide a way to upgrade
> existing content to ensure the fake nodes everywhere.

Agreed, not an option.

> 
> 2) Check for null and duplicate code in the JSP: Sure I can add all
> these checks,but I still have to copy code from MyStuffImpl where I
> actually need something computed - which practically renders my API
> useless. Unless I make those methods static, which would be
> suboptimal.

Agreed.

Still, of course just for stability reasons, you should (or must?)
always check the result of calling adaptTo, since it is ok to return null.

> 
> 3) Publicly export the implementation in the bundle: That enables me
> to create an instance of MyStuff even if resource.adaptTo() returns
> null. Yuck! :)

As you said: Yuck! ;-)

How about another option:

(4) In you concrete use case you are using some special functionality of
the <sling:include> JSP tag, which allows for including "virtual"
resources. What do you think of enhancing that functionality in such a
way, that it returns a SyntheticResource whose adaptTo() method is
overwritten to call into the AdapterManager ?

or (somewhat interesting) :

(5) Move the o.a.s.api.adapter package to the Sling Adapter module
(which also contains the AdapterManager implementation and the
SlingAdaptable class. Thus the Sling Adapter module would not import
from the Sling API anymore. Instead the Sling API would import from the
Sling Adapter Module. As a consequence the SyntheticResource could
extend the SlingAdaptable class.

> 
> If there are no system-critical reasons behind returning null in
> SyntheticResource#adaptTo(), i.e. breaking core code that relies on
> the fact that it always returns null, I'd suggest to make it adaptable
> by default, and leave it to the AdapterFactory implementation whether
> or not to return null.

Now, SyntheticResource implements Resources extends Adaptable. The
problem is, that just by implementing the Adaptable interface, no
AdapterFactory is called per se. This would be the task of the adaptTo
implementation.

See for example JcrNodeResource which extends from SlingAdaptable. The
SlingAdaptable.adapTo() method calls into the AdapterManager required
for adaptTo to work with AdapterFactorys.

> 
> Of course, I'd have to be warned that some stuff isn't available due
> to the missing data in the repository, but my component could still do
> something useful with a synthetic resource, and I'd rather confine all
> the required checks to the implementation of MyStuff rather than the
> JSP code.
> 
> WDYT?

I kind of favor option (5) even though it is kind of not so nice, that
the o.a.s.api.adapter package is not in the Sling API package any more.

WDYT ?

Regards
Felix
> 
> /rofe
> 

Reply via email to