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 >
