This is an automated email from the ASF dual-hosted git repository. royteeuwen pushed a commit to branch fix/resource-decorator-tracker-cleared-on-modified in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git
commit 6920af3cbb79f303b12778fdd6820d8749c52789 Author: Roy Teeuwen <[email protected]> AuthorDate: Wed May 20 13:35:00 2026 +0200 SLING-13206: ResourceDecorator services lost after @Modified on ResourceResolverFactoryActivator When OSGi fires the @Modified lifecycle callback (e.g. triggered by a bundle deployment causing a configuration change), modified() delegates to deactivateInternal() which calls resourceDecoratorTracker.close(), clearing all registered ResourceDecorator services. Because the decorators use ReferencePolicy.DYNAMIC, OSGi does not re-fire bindResourceDecorator after a @Modified event (no component restart). The tracker is therefore left permanently empty, silently breaking any feature that relies on ResourceDecorator (e.g. path-rewriting decorators). Fix: move resourceDecoratorTracker.close() out of deactivateInternal() and into deactivate() only. deactivateInternal() is still called from both @Modified and @Deactivate, but only the true component teardown path (@Deactivate) now closes the tracker. Also add a null-guard in ResourceDecoratorEntry.compareTo() to prevent NPE when ServiceReference is null. --- .../resourceresolver/impl/ResourceResolverFactoryActivator.java | 7 ++++++- .../resourceresolver/impl/helper/ResourceDecoratorTracker.java | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java index f8bdaee4..b92af50a 100644 --- a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java +++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java @@ -369,6 +369,12 @@ public class ResourceResolverFactoryActivator { // factoryRegistrationHandler must be closed before bundleContext is set to null this.factoryRegistrationHandler.close(); this.bundleContext = null; + // Close the decorator tracker only on true deactivation. The tracker must NOT be + // closed inside deactivateInternal(), which is also called from @Modified. When + // @Modified fires, OSGi does not re-fire bindResourceDecorator for already-bound + // DYNAMIC references, so closing the tracker here would permanently lose all + // registered ResourceDecorators for the lifetime of the component. + this.resourceDecoratorTracker.close(); deactivateInternal(); } @@ -379,7 +385,6 @@ public class ResourceResolverFactoryActivator { this.changeListenerWhiteboard = null; this.resourceProviderTracker.deactivate(); this.resourceProviderTracker = null; - this.resourceDecoratorTracker.close(); } /** diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java index 3eea04a8..d600d73f 100644 --- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java +++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java @@ -141,6 +141,9 @@ public class ResourceDecoratorTracker { } public int compareTo(final ResourceDecoratorEntry o) { + if (this.comparable == null || o.comparable == null) { + return 0; + } return comparable.compareTo(o.comparable); } }
