This is an automated email from the ASF dual-hosted git repository.

enorman pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-bundleresource-impl.git


The following commit(s) were added to refs/heads/master by this push:
     new b0ec7d4  SLING-13028 Resolve various sonar warnings (#9)
b0ec7d4 is described below

commit b0ec7d436ea33dad6ec5b92457771b39239bdccb
Author: Eric Norman <[email protected]>
AuthorDate: Thu Jan 29 15:18:24 2026 -0800

    SLING-13028 Resolve various sonar warnings (#9)
---
 .../sling/bundleresource/impl/Activator.java       |  29 ++---
 .../sling/bundleresource/impl/BundleResource.java  |  26 +++--
 .../bundleresource/impl/BundleResourceCache.java   |  24 +++-
 .../impl/BundleResourceProvider.java               |  24 ++--
 .../impl/BundleResourceURLConnection.java          |   4 +
 .../impl/BundleResourceWebConsolePlugin.java       |  90 +++++++--------
 .../sling/bundleresource/impl/PathMapping.java     |  12 +-
 .../sling/bundleresource/impl/ActivatorTest.java   |  70 ++++++++++++
 .../bundleresource/impl/BundleResourceMapTest.java | 124 +++++++++++++++++++++
 .../impl/BundleResourceProviderTest.java           |  20 ++--
 .../bundleresource/impl/BundleResourceTest.java    |  12 +-
 .../impl/BundleResourceWebConsolePluginTest.java   |  20 ++++
 .../bundleresource/impl/NoBundleContextTest.java   |  11 +-
 .../sling/bundleresource/impl/PathMappingTest.java |   6 +-
 14 files changed, 355 insertions(+), 117 deletions(-)

diff --git a/src/main/java/org/apache/sling/bundleresource/impl/Activator.java 
b/src/main/java/org/apache/sling/bundleresource/impl/Activator.java
index 58f614d..67c5bc2 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/Activator.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/Activator.java
@@ -93,16 +93,13 @@ public class Activator implements BundleActivator, 
BundleListener {
      */
     @Override
     public void bundleChanged(final BundleEvent event) {
-        switch (event.getType()) {
-            case BundleEvent.STARTED:
-                // register resource provider for the started bundle
-                addBundleResourceProvider(event.getBundle());
-                break;
-
-            case BundleEvent.STOPPED:
-                // remove resource provider after the bundle has stopped
-                removeBundleResourceProvider(event.getBundle());
-                break;
+        final int type = event.getType();
+        if (BundleEvent.STARTED == type) {
+            // register resource provider for the started bundle
+            addBundleResourceProvider(event.getBundle());
+        } else if (BundleEvent.STOPPED == type) {
+            // remove resource provider after the bundle has stopped
+            removeBundleResourceProvider(event.getBundle());
         }
     }
 
@@ -120,8 +117,10 @@ public class Activator implements BundleActivator, 
BundleListener {
                 if (prefixes != null) {
                     log.debug(
                             "addBundleResourceProvider: Registering resources 
'{}' for bundle {}:{} ({}) as service ",
-                            new Object[] {prefixes, bundle.getSymbolicName(), 
bundle.getVersion(), bundle.getBundleId()
-                            });
+                            prefixes,
+                            bundle.getSymbolicName(),
+                            bundle.getVersion(),
+                            bundle.getBundleId());
 
                     final PathMapping[] roots = PathMapping.getRoots(prefixes);
                     providers = new BundleResourceProvider[roots.length];
@@ -143,7 +142,7 @@ public class Activator implements BundleActivator, 
BundleListener {
                     log.debug("addBundleResourceProvider: Service ID = {}", 
id);
                 }
             }
-        } catch (final Throwable t) {
+        } catch (final Throwable t) { // NOSONAR
             log.error(
                     "activate: Problem while registering bundle resources for 
bundle " + bundle.getSymbolicName() + ":"
                             + bundle.getVersion() + " (" + 
bundle.getBundleId() + ")",
@@ -159,7 +158,9 @@ public class Activator implements BundleActivator, 
BundleListener {
         if (brp != null) {
             log.debug(
                     "removeBundleResourceProvider: Unregistering resources for 
bundle {}:{} ({})",
-                    new Object[] {bundle.getSymbolicName(), 
bundle.getVersion(), bundle.getBundleId()});
+                    bundle.getSymbolicName(),
+                    bundle.getVersion(),
+                    bundle.getBundleId());
             for (final BundleResourceProvider provider : brp) {
                 try {
                     provider.unregisterService();
diff --git 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResource.java 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResource.java
index 1c69e03..f1fae21 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/BundleResource.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/BundleResource.java
@@ -32,6 +32,7 @@ import jakarta.json.Json;
 import jakarta.json.JsonArray;
 import jakarta.json.JsonNumber;
 import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
 import jakarta.json.JsonString;
 import jakarta.json.JsonValue;
 import org.apache.sling.api.resource.AbstractResource;
@@ -141,10 +142,12 @@ public class BundleResource extends AbstractResource {
                 try {
                     final URL url = this.cache.getEntry(propsPath);
                     if (url != null) {
-                        final JsonObject obj =
-                                
Json.createReader(url.openStream()).readObject();
+                        final JsonObject obj;
+                        try (JsonReader reader = 
Json.createReader(url.openStream())) {
+                            obj = reader.readObject();
+                        }
                         for (final Map.Entry<String, JsonValue> entry : 
obj.entrySet()) {
-                            final Object value = getValue(entry.getValue(), 
true);
+                            final Object value = getValue(entry.getValue());
                             if (value != null) {
                                 if (value instanceof Map) {
                                     if (children == null) {
@@ -184,17 +187,18 @@ public class BundleResource extends AbstractResource {
                     resources = ((BundleResource) result).subResources;
                 } else {
                     result = null;
-                    break;
                 }
             } else {
                 result = null;
+            }
+            if (result == null) {
                 break;
             }
         }
         return result;
     }
 
-    private static Object getValue(final JsonValue value, final boolean 
topLevel) {
+    private static Object getValue(final JsonValue value) {
         switch (value.getValueType()) {
             // type NULL -> return null
             case NULL:
@@ -218,7 +222,7 @@ public class BundleResource extends AbstractResource {
             case ARRAY:
                 final List<Object> array = new ArrayList<>();
                 for (final JsonValue x : ((JsonArray) value)) {
-                    array.add(getValue(x, false));
+                    array.add(getValue(x));
                 }
                 return array;
             // type OBJECT -> return map
@@ -226,7 +230,7 @@ public class BundleResource extends AbstractResource {
                 final Map<String, Object> map = new HashMap<>();
                 final JsonObject obj = (JsonObject) value;
                 for (final Map.Entry<String, JsonValue> entry : 
obj.entrySet()) {
-                    map.put(entry.getKey(), getValue(entry.getValue(), false));
+                    map.put(entry.getKey(), getValue(entry.getValue()));
                 }
                 return map;
         }
@@ -264,13 +268,13 @@ public class BundleResource extends AbstractResource {
 
     @Override
     @SuppressWarnings("unchecked")
-    public <Type> Type adaptTo(Class<Type> type) {
+    public <T> T adaptTo(Class<T> type) {
         if (type == InputStream.class) {
-            return (Type) getInputStream(); // unchecked cast
+            return (T) getInputStream(); // unchecked cast
         } else if (type == URL.class) {
-            return (Type) getURL(); // unchecked cast
+            return (T) getURL(); // unchecked cast
         } else if (type == ValueMap.class) {
-            return (Type) valueMap; // unchecked cast
+            return (T) valueMap; // unchecked cast
         }
 
         // fall back to adapter factories
diff --git 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java
index 11e0bd3..66933f5 100644
--- 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java
+++ 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceCache.java
@@ -225,7 +225,7 @@ class BundleResourceCache {
      * {@link #removeEldestEntry(Entry)} method to implement the size limit,
      * which is set in the constructor.
      */
-    private static class BundleResourceMap<K, V> extends LinkedHashMap<String, 
V> {
+    private static class BundleResourceMap<K, V> extends LinkedHashMap<K, V> {
 
         private static final long serialVersionUID = 7455098291380945276L;
 
@@ -251,7 +251,7 @@ class BundleResourceCache {
             // we need the access-order to implement the LRU mechanism
             super(8, 0.75f, true);
 
-            // normalize size to a possitive number
+            // normalize size to a positive number
             if (limit <= 0) {
                 limit = DEFAULT_LIMIT;
             }
@@ -264,8 +264,26 @@ class BundleResourceCache {
          * map exceeds the configured limit.
          */
         @Override
-        protected boolean removeEldestEntry(Entry<String, V> eldest) {
+        protected boolean removeEldestEntry(Entry<K, V> eldest) {
             return size() > limit;
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + limit;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (!super.equals(obj)) return false;
+            if (getClass() != obj.getClass()) return false;
+            @SuppressWarnings("rawtypes")
+            BundleResourceMap other = (BundleResourceMap) obj;
+            return limit == other.limit;
+        }
     }
 }
diff --git 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
index 5fae749..b988fef 100644
--- 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
+++ 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceProvider.java
@@ -44,7 +44,7 @@ public class BundleResourceProvider extends 
ResourceProvider<Object> {
     private final PathMapping root;
 
     @SuppressWarnings("rawtypes")
-    private volatile ServiceRegistration<ResourceProvider> serviceRegistration;
+    private ServiceRegistration<ResourceProvider> serviceRegistration;
 
     /**
      * Creates Bundle resource provider accessing entries in the given Bundle 
an
@@ -60,10 +60,10 @@ public class BundleResourceProvider extends 
ResourceProvider<Object> {
 
     long registerService() {
         final Bundle bundle = this.cache.getBundle();
-        final Dictionary<String, Object> props = new Hashtable<>();
+        final Dictionary<String, Object> props = new Hashtable<>(); // NOSONAR
         props.put(
                 Constants.SERVICE_DESCRIPTION,
-                "Provider of bundle based resources from bundle " + 
String.valueOf(bundle.getBundleId()));
+                "Provider of bundle based resources from bundle " + 
bundle.getBundleId());
         props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
         props.put(ResourceProvider.PROPERTY_ROOT, this.root.getResourceRoot());
         props.put(PROP_BUNDLE, bundle.getBundleId());
@@ -125,15 +125,13 @@ public class BundleResourceProvider extends 
ResourceProvider<Object> {
 
             // here we either have a folder for which no same-named item exists
             // or a bundle file
-            if (entry != null) {
-                // check if a JSON props file is directly requested
-                // if so, we deny the access
-                if (this.root.getJSONPropertiesExtension() == null
-                        || 
!entryPath.endsWith(this.root.getJSONPropertiesExtension())) {
-
-                    return new BundleResource(
-                            ctx.getResourceResolver(), cache, mappedPath, 
resourcePath, null, isFolder);
-                }
+            // check if a JSON props file is directly requested
+            // if so, we deny the access
+            if (entry != null
+                    && (this.root.getJSONPropertiesExtension() == null
+                            || 
!entryPath.endsWith(this.root.getJSONPropertiesExtension()))) {
+
+                return new BundleResource(ctx.getResourceResolver(), cache, 
mappedPath, resourcePath, null, isFolder);
             }
 
             // the bundle does not contain the path
@@ -162,7 +160,7 @@ public class BundleResourceProvider extends 
ResourceProvider<Object> {
 
     @Override
     public Iterator<Resource> listChildren(final ResolveContext<Object> ctx, 
final Resource parent) {
-        if (parent instanceof BundleResource && ((BundleResource) 
parent).getBundle() == this.cache) {
+        if (parent instanceof BundleResource br && br.getBundle() == 
this.cache) {
             // bundle resources can handle this request directly when the 
parent
             // resource is in the same bundle as this provider.
             return new BundleResourceIterator((BundleResource) parent);
diff --git 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceURLConnection.java
 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceURLConnection.java
index 190f435..9601134 100644
--- 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceURLConnection.java
+++ 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceURLConnection.java
@@ -66,6 +66,7 @@ public class BundleResourceURLConnection extends 
URLConnection {
     }
 
     /** Returns the input stream of the Bundle provided URLConnection */
+    @Override
     public InputStream getInputStream() throws IOException {
         connect();
 
@@ -73,6 +74,7 @@ public class BundleResourceURLConnection extends 
URLConnection {
     }
 
     /** Returns the content length of the Bundle provided URLConnection */
+    @Override
     public int getContentLength() {
         try {
             connect();
@@ -87,6 +89,7 @@ public class BundleResourceURLConnection extends 
URLConnection {
      * Returns the last modification time of the underlying bundle, which is 
the
      * last time the bundle was installed or updated
      */
+    @Override
     public long getLastModified() {
         try {
             connect();
@@ -98,6 +101,7 @@ public class BundleResourceURLConnection extends 
URLConnection {
     }
 
     /** Returns the content type of the Bundle provided URLConnection */
+    @Override
     public String getContentType() {
         try {
             connect();
diff --git 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
index 5a4ed20..9d18c16 100644
--- 
a/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
+++ 
b/src/main/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePlugin.java
@@ -83,67 +83,69 @@ class BundleResourceWebConsolePlugin extends HttpServlet {
     @Override
     protected void doGet(final HttpServletRequest req, final 
HttpServletResponse res)
             throws ServletException, IOException {
-        PrintWriter pw = res.getWriter();
+        try (PrintWriter pw = res.getWriter()) {
+            pw.println("<table class='content' cellpadding='0' cellspacing='0' 
width='100%'>");
 
-        pw.println("<table class='content' cellpadding='0' cellspacing='0' 
width='100%'>");
+            pw.println("<tr class='content'>"); // NOSONAR
+            pw.println("<th colspan='2' class='content container'>Bundle 
Resource Provider</th>");
+            pw.println("</tr>"); // NOSONAR
 
-        pw.println("<tr class='content'>");
-        pw.println("<th colspan='2' class='content container'>Bundle Resource 
Provider</th>");
-        pw.println("</tr>");
+            BundleResourceProvider[] brp = provider.toArray(new 
BundleResourceProvider[provider.size()]);
+            for (BundleResourceProvider bundleResourceProvider : brp) {
 
-        BundleResourceProvider[] brp = provider.toArray(new 
BundleResourceProvider[provider.size()]);
-        for (BundleResourceProvider bundleResourceProvider : brp) {
+                BundleResourceCache cache = 
bundleResourceProvider.getBundleResourceCache();
+                PathMapping path = bundleResourceProvider.getMappedPath();
 
-            BundleResourceCache cache = 
bundleResourceProvider.getBundleResourceCache();
-            PathMapping path = bundleResourceProvider.getMappedPath();
+                pw.println("<tr class='content'>");
 
-            pw.println("<tr class='content'>");
+                pw.println("<td class='content'>"); // NOSONAR
+                pw.println(cache.getBundle().getBundleId());
+                pw.println("</td>"); // NOSONAR
 
-            pw.println("<td class='content'>");
-            pw.println(cache.getBundle().getBundleId());
-            pw.println("</td>");
+                pw.println("<td class='content'>");
+                pw.println(getName(cache.getBundle()));
+                pw.println("</td>");
 
-            pw.println("<td class='content'>");
-            pw.println(getName(cache.getBundle()));
-            pw.println("</td>");
+                pw.println("</tr>");
 
-            pw.println("</tr>");
+                pw.println("<tr class='content'>");
+                pw.println("<td class='content'>&nbsp;</td>");
 
-            pw.println("<tr class='content'>");
-            pw.println("<td class='content'>&nbsp;</td>");
+                pw.println("<td class='content'>");
 
-            pw.println("<td class='content'>");
+                pw.println("<table>");
 
-            pw.println("<table>");
+                pw.println("<tr>");
+                pw.println("<td>Mapping</td>");
+                pw.println("<td>");
+                pw.print(path.getResourceRoot());
+                if (path.getEntryRoot() != null) {
+                    pw.print(" ==> ");
+                    pw.print(path.getEntryRoot());
+                }
+                pw.println("</td>");
+                pw.println("</tr>");
 
-            pw.println("<tr>");
-            pw.println("<td>Mapping</td>");
-            pw.println("<td>");
-            pw.print(path.getResourceRoot());
-            if (path.getEntryRoot() != null) {
-                pw.print(" ==> ");
-                pw.print(path.getEntryRoot());
-            }
-            pw.println("</td>");
-            pw.println("</tr>");
+                pw.println("<tr>");
+                pw.println("<td>Entry Cache</td>");
+                pw.printf("<td>Size: %d, Limit: %d</td>%n", 
cache.getEntryCacheSize(), cache.getEntryCacheMaxSize());
+                pw.println("</tr>");
 
-            pw.println("<tr>");
-            pw.println("<td>Entry Cache</td>");
-            pw.printf("<td>Size: %d, Limit: %d</td>%n", 
cache.getEntryCacheSize(), cache.getEntryCacheMaxSize());
-            pw.println("</tr>");
+                pw.println("<tr>");
+                pw.println("<td>List Cache</td>");
+                pw.printf("<td>Size: %d, Limit: %d</td>%n", 
cache.getListCacheSize(), cache.getListCacheMaxSize());
+                pw.println("</tr>");
 
-            pw.println("<tr>");
-            pw.println("<td>List Cache</td>");
-            pw.printf("<td>Size: %d, Limit: %d</td>%n", 
cache.getListCacheSize(), cache.getListCacheMaxSize());
-            pw.println("</tr>");
+                pw.println("</table>");
 
-            pw.println("</table>");
+                pw.println("</td>");
+                pw.println("</tr>");
+            }
 
-            pw.println("</td>");
-            pw.println("</tr>");
+            pw.println("</table>");
+        } catch (IOException ioe) {
+            log("Failed to write response: " + ioe.getMessage(), ioe);
         }
-
-        pw.println("</table>");
     }
 
     @SuppressWarnings("rawtypes")
diff --git 
a/src/main/java/org/apache/sling/bundleresource/impl/PathMapping.java 
b/src/main/java/org/apache/sling/bundleresource/impl/PathMapping.java
index e1ee6ff..6623a37 100644
--- a/src/main/java/org/apache/sling/bundleresource/impl/PathMapping.java
+++ b/src/main/java/org/apache/sling/bundleresource/impl/PathMapping.java
@@ -28,7 +28,7 @@ class PathMapping {
     public static final String DIR_PATH = "path";
     public static final String DIR_JSON = "propsJSON";
 
-    private static final char prefixSeparatorChar = '!';
+    private static final char PREFIX_SEPARATOR_CHAR = '!';
     private final String resourceRoot;
     private final String resourceRootPrefix;
     private final String entryRoot;
@@ -56,7 +56,7 @@ class PathMapping {
     static PathMapping create(final String configPath, final String 
expandDirective) {
         String resourceRoot;
         String entryRoot;
-        int prefixSep = configPath.indexOf(prefixSeparatorChar);
+        int prefixSep = configPath.indexOf(PREFIX_SEPARATOR_CHAR);
         if (prefixSep >= 0) {
             entryRoot = configPath.substring(prefixSep + 1);
             resourceRoot = configPath.substring(0, 
prefixSep).concat(entryRoot);
@@ -126,7 +126,7 @@ class PathMapping {
     }
 
     private static String ensureLeadingDot(final String path) {
-        if (path == null || path.length() == 0) {
+        if (path == null || path.isEmpty()) {
             return null;
         }
 
@@ -138,7 +138,7 @@ class PathMapping {
     }
 
     private static String ensureNoTrailingSlash(final String path) {
-        if (path == null || path.length() == 0) {
+        if (path == null || path.isEmpty()) {
             return null;
         }
 
@@ -150,7 +150,7 @@ class PathMapping {
     }
 
     private static String ensureTrailingSlash(final String path) {
-        if (path == null || path.length() == 0) {
+        if (path == null || path.isEmpty()) {
             return null;
         }
 
@@ -162,7 +162,7 @@ class PathMapping {
     }
 
     private static String ensureLeadingSlash(final String path) {
-        if (path == null || path.length() == 0) {
+        if (path == null || path.isEmpty()) {
             return null;
         }
 
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/ActivatorTest.java 
b/src/test/java/org/apache/sling/bundleresource/impl/ActivatorTest.java
new file mode 100644
index 0000000..8d306ab
--- /dev/null
+++ b/src/test/java/org/apache/sling/bundleresource/impl/ActivatorTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.bundleresource.impl;
+
+import java.util.Hashtable;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class ActivatorTest {
+
+    private Bundle bundle;
+
+    @BeforeEach
+    void setUp() {
+        bundle = mock(Bundle.class);
+        // Return an empty headers dictionary so that addBundleResourceProvider
+        // finds no prefixes and returns early without performing 
registrations.
+        when(bundle.getHeaders()).thenReturn(new Hashtable<>());
+    }
+
+    @Test
+    void bundleChanged_handlesStartedEventWithoutThrowing() {
+        final Activator activator = new Activator();
+        final BundleEvent startedEvent = new BundleEvent(BundleEvent.STARTED, 
bundle);
+
+        // Verify the STARTED branch runs (and does not throw).
+        assertDoesNotThrow(() -> activator.bundleChanged(startedEvent));
+    }
+
+    @Test
+    void bundleChanged_handlesStoppedEventWithoutThrowing() {
+        final Activator activator = new Activator();
+        final BundleEvent stoppedEvent = new BundleEvent(BundleEvent.STOPPED, 
bundle);
+
+        // Verify the STOPPED branch runs (and does not throw).
+        assertDoesNotThrow(() -> activator.bundleChanged(stoppedEvent));
+    }
+
+    @Test
+    void bundleChanged_handlesOtherEventWithoutThrowing() {
+        final Activator activator = new Activator();
+        final BundleEvent stoppedEvent = new BundleEvent(BundleEvent.RESOLVED, 
bundle);
+
+        // Verify nothing happens (and does not throw).
+        assertDoesNotThrow(() -> activator.bundleChanged(stoppedEvent));
+    }
+}
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceMapTest.java 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceMapTest.java
new file mode 100644
index 0000000..021e87f
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceMapTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.bundleresource.impl;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests for the private static inner class BundleResourceMap inside
+ * BundleResourceCache. The class is private, so we access it via reflection
+ * and treat instances as plain Maps to exercise equals() and hashCode().
+ */
+class BundleResourceMapTest {
+
+    /**
+     * Create an instance of the private inner class BundleResourceMap using
+     * reflection. The constructor used takes a single int parameter (limit).
+     */
+    @SuppressWarnings("unchecked")
+    private <K, V> Map<K, V> createMap(int limit) throws Exception {
+        Class<?> outer = BundleResourceCache.class;
+        Class<?> target = null;
+        for (Class<?> c : outer.getDeclaredClasses()) {
+            if ("BundleResourceMap".equals(c.getSimpleName())) { // NOSONAR
+                target = c;
+                break;
+            }
+        }
+        if (target == null) {
+            throw new IllegalStateException("BundleResourceMap inner class not 
found");
+        }
+
+        Constructor<?> ctor = target.getDeclaredConstructor(int.class);
+        ctor.setAccessible(true);
+        Object instance = ctor.newInstance(limit);
+        return (Map<K, V>) instance;
+    }
+
+    @Test
+    void equalsAndHashCode_sameLimitAndContent() throws Exception {
+        Map<String, String> m1 = createMap(10);
+        Map<String, String> m2 = createMap(10);
+
+        // same content
+        m1.put("a", "1");
+        m1.put("b", "2");
+
+        m2.put("a", "1");
+        m2.put("b", "2");
+
+        // equals should be true and hashCodes equal
+        assertTrue(m1.equals(m2), "Maps with same limit and same entries 
should be equal"); // NOSONAR
+        assertTrue(m2.equals(m1), "Equality should be symmetric"); // NOSONAR
+        assertEquals(m1.hashCode(), m2.hashCode(), "hashCode must be equal for 
equal maps");
+
+        // same instance equals itself
+        assertTrue(m1.equals(m1)); // NOSONAR
+    }
+
+    @Test
+    void equals_differentLimits() throws Exception {
+        Map<String, String> m1 = createMap(5);
+        Map<String, String> m2 = createMap(10);
+
+        // same content
+        m1.put("k", "v");
+        m2.put("k", "v");
+
+        // equals should be false because limits differ even though content 
equals
+        assertFalse(m1.equals(m2), "Maps with same entries but different 
limits should NOT be equal"); // NOSONAR
+        assertFalse(m2.equals(m1), "Symmetry for inequality"); // NOSONAR
+
+        // hashCodes are very likely different; at least they shouldn't be 
required to be equal
+        // but we can assert that when equals is false, hashCodes may differ 
(not a strict requirement),
+        // so we don't assert anything about hashCode here beyond that calling 
it doesn't throw.
+        m1.hashCode();
+        m2.hashCode();
+    }
+
+    @Test
+    void equals_differentContent() throws Exception {
+        Map<String, String> m1 = createMap(7);
+        Map<String, String> m2 = createMap(7);
+
+        m1.put("x", "1");
+        m2.put("y", "2");
+
+        assertFalse(m1.equals(m2), "Maps with same limit but different content 
should NOT be equal"); // NOSONAR
+    }
+
+    @Test
+    void equals_againstOtherTypesAndNull() throws Exception {
+        Map<String, String> m1 = createMap(3);
+        m1.put("foo", "bar");
+
+        assertFalse(m1.equals(null), "Should not be equal to null"); // NOSONAR
+        final HashMap<Object, Object> otherMap = new HashMap<>();
+        otherMap.put("foo", "bar");
+        assertFalse(m1.equals(otherMap), "Should not be equal to an unrelated 
object"); // NOSONAR
+    }
+}
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceProviderTest.java
 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceProviderTest.java
index 56454bd..ab73539 100644
--- 
a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceProviderTest.java
+++ 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceProviderTest.java
@@ -45,7 +45,7 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public class BundleResourceProviderTest {
+class BundleResourceProviderTest {
 
     Bundle getBundle() {
         Bundle bundle = mock(Bundle.class);
@@ -104,18 +104,18 @@ public class BundleResourceProviderTest {
     }
 
     @BeforeEach
-    public void setup() {
+    void setup() {
         ResourceURLStreamHandlerFactory.init();
     }
 
     @AfterEach
-    public void finish() {
+    void finish() {
         ResourceURLStreamHandler.reset();
     }
 
     @SuppressWarnings("unchecked")
     @Test
-    public void testFileResource() throws IOException {
+    void testFileResource() throws IOException {
         final Bundle bundle = getBundle();
         addContent(bundle, "/libs/foo/test.json", "HELLOWORLD");
 
@@ -130,7 +130,7 @@ public class BundleResourceProviderTest {
 
     @SuppressWarnings("unchecked")
     @Test
-    public void testJSONResource() throws IOException {
+    void testJSONResource() throws IOException {
         final Bundle bundle = getBundle();
         addContent(bundle, "/libs/foo/test.json", 
Collections.singletonMap("test", (Object) "foo"));
 
@@ -150,7 +150,7 @@ public class BundleResourceProviderTest {
 
     @SuppressWarnings("unchecked")
     @Test
-    public void testFileAndJSONResource() throws IOException {
+    void testFileAndJSONResource() throws IOException {
         final Bundle bundle = getBundle();
         addContent(bundle, "/libs/foo/test", "HELLOWORLD");
         addContent(bundle, "/libs/foo/test.json", 
Collections.singletonMap("test", (Object) "foo"));
@@ -171,7 +171,7 @@ public class BundleResourceProviderTest {
     }
 
     @Test
-    public void testTreeWithoutDeepJSON() throws IOException {
+    void testTreeWithoutDeepJSON() throws IOException {
         testTreeWithoutDeepJSON("");
         testTreeWithoutDeepJSON("/SLING-INF");
     }
@@ -194,7 +194,7 @@ public class BundleResourceProviderTest {
         finishContent(bundle);
 
         final PathMapping path;
-        if (prefix.length() == 0) {
+        if (prefix.isEmpty()) {
             path = new PathMapping("/libs/foo", null, "json");
         } else {
             path = new PathMapping("/libs/foo", prefix + "/libs/foo", "json");
@@ -230,7 +230,7 @@ public class BundleResourceProviderTest {
     }
 
     @Test
-    public void testTreeWithDeepJSON() throws IOException {
+    void testTreeWithDeepJSON() throws IOException {
         testTreeWithDeepJSON("");
         testTreeWithDeepJSON("/SLING-INF");
     }
@@ -292,7 +292,7 @@ public class BundleResourceProviderTest {
         finishContent(bundle);
 
         final PathMapping path;
-        if (prefix.length() == 0) {
+        if (prefix.isEmpty()) {
             path = new PathMapping("/libs/foo", null, "json");
         } else {
             path = new PathMapping("/libs/foo", prefix + "/libs/foo", "json");
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceTest.java 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceTest.java
index 8300df8..a006ba5 100644
--- a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceTest.java
+++ b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceTest.java
@@ -39,7 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public class BundleResourceTest {
+class BundleResourceTest {
 
     BundleResourceCache getBundleResourceCache() {
         Bundle bundle = mock(Bundle.class);
@@ -52,12 +52,12 @@ public class BundleResourceTest {
     }
 
     @BeforeEach
-    public void setup() {
+    void setup() {
         ResourceURLStreamHandlerFactory.init();
     }
 
     @AfterEach
-    public void finish() {
+    void finish() {
         ResourceURLStreamHandler.reset();
     }
 
@@ -76,7 +76,7 @@ public class BundleResourceTest {
     }
 
     @Test
-    public void testFileResource() throws MalformedURLException {
+    void testFileResource() throws MalformedURLException {
         final BundleResourceCache cache = getBundleResourceCache();
         when(cache.getEntry("/libs/foo/test.json")).thenReturn(new 
URL("file:/libs/foo/test.json"));
         final BundleResource rsrc = new BundleResource(
@@ -88,7 +88,7 @@ public class BundleResourceTest {
     }
 
     @Test
-    public void testJSONResource() throws IOException {
+    void testJSONResource() throws IOException {
         final BundleResourceCache cache = getBundleResourceCache();
         addContent(cache, "/libs/foo/test.json", 
Collections.singletonMap("test", (Object) "foo"));
         final BundleResource rsrc = new BundleResource(
@@ -105,7 +105,7 @@ public class BundleResourceTest {
      *  JSONPropertiesExtension is loaded
      */
     @Test
-    public void testJSONResourceForMappedFile() throws IOException {
+    void testJSONResourceForMappedFile() throws IOException {
         final BundleResourceCache cache = getBundleResourceCache();
         addContent(cache, "/SLING_INF/libs/foo/test.txt", "Hello Text");
         addContent(cache, "/SLING-INF/libs/foo/test.txt.json", 
Collections.singletonMap("test", (Object) "foo"));
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePluginTest.java
 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePluginTest.java
index 8c9dd23..0af0d60 100644
--- 
a/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePluginTest.java
+++ 
b/src/test/java/org/apache/sling/bundleresource/impl/BundleResourceWebConsolePluginTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.bundleresource.impl;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
@@ -43,6 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -59,6 +61,24 @@ import static org.mockito.Mockito.when;
  */
 class BundleResourceWebConsolePluginTest {
 
+    @Test
+    void testDoGetWithCaughtIOException() throws Exception {
+        testPlugin((ctx, reg, plugin) -> {
+            plugin = Mockito.spy(plugin);
+            Mockito.doNothing().when(plugin).log(anyString(), 
any(Exception.class));
+
+            // Prepare mocks for servlet invocation and capture output
+            HttpServletRequest req = mock(HttpServletRequest.class);
+            HttpServletResponse resp = mock(HttpServletResponse.class);
+            Mockito.doThrow(IOException.class).when(resp).getWriter();
+
+            plugin.doGet(req, resp);
+
+            // verify the error log message was invoked
+            verify(plugin, times(1)).log(anyString(), any(Exception.class));
+        });
+    }
+
     @Test
     void testActivateDoGetDeactivate() throws Exception {
         testPlugin((ctx, reg, plugin) -> {
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/NoBundleContextTest.java 
b/src/test/java/org/apache/sling/bundleresource/impl/NoBundleContextTest.java
index 5abf2c7..d8bab2b 100644
--- 
a/src/test/java/org/apache/sling/bundleresource/impl/NoBundleContextTest.java
+++ 
b/src/test/java/org/apache/sling/bundleresource/impl/NoBundleContextTest.java
@@ -18,7 +18,6 @@
  */
 package org.apache.sling.bundleresource.impl;
 
-import java.io.IOException;
 import java.util.Dictionary;
 
 import org.apache.sling.spi.resource.provider.ResourceProvider;
@@ -38,24 +37,22 @@ import static org.mockito.Mockito.when;
 /**
  * SLING-11649 - verify check for null BundleContext while registering bundle 
resources
  */
-public class NoBundleContextTest {
+class NoBundleContextTest {
 
     @Test
-    public void verifyIllegalStateExceptionWhenNoBundleContextIsAvailable() 
throws IOException {
+    void verifyIllegalStateExceptionWhenNoBundleContextIsAvailable() {
         final Bundle bundle = mock(Bundle.class);
         when(bundle.getBundleContext()).thenReturn(null);
         final PathMapping path = new PathMapping("/libs/foo", null, null);
 
         final BundleResourceProvider provider = new BundleResourceProvider(new 
BundleResourceCache(bundle), path);
-        Exception exception = assertThrows(IllegalStateException.class, () -> {
-            provider.registerService();
-        });
+        Exception exception = assertThrows(IllegalStateException.class, 
provider::registerService);
         assertTrue(exception.getMessage().contains("No BundleContext was 
found"));
     }
 
     @SuppressWarnings("unchecked")
     @Test
-    public void verifyNoIllegalStateExceptionWhenBundleContextIsAvailable() 
throws IOException {
+    void verifyNoIllegalStateExceptionWhenBundleContextIsAvailable() {
         final Bundle bundle = mock(Bundle.class);
         final BundleContext bc = mock(BundleContext.class);
         when(bundle.getBundleContext()).thenReturn(bc);
diff --git 
a/src/test/java/org/apache/sling/bundleresource/impl/PathMappingTest.java 
b/src/test/java/org/apache/sling/bundleresource/impl/PathMappingTest.java
index 1124025..6ce7b3c 100644
--- a/src/test/java/org/apache/sling/bundleresource/impl/PathMappingTest.java
+++ b/src/test/java/org/apache/sling/bundleresource/impl/PathMappingTest.java
@@ -23,10 +23,10 @@ import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
-public class PathMappingTest {
+class PathMappingTest {
 
     @Test
-    public void testSimpleRoot() {
+    void testSimpleRoot() {
         final PathMapping[] paths = PathMapping.getRoots("/libs/foo");
         assertEquals(1, paths.length);
         assertNull(paths[0].getEntryRoot());
@@ -37,7 +37,7 @@ public class PathMappingTest {
     }
 
     @Test
-    public void testSimpleRootWithJSON() {
+    void testSimpleRootWithJSON() {
         final PathMapping[] paths = PathMapping.getRoots("/libs/foo;" + 
PathMapping.DIR_JSON + ":=json");
         assertEquals(1, paths.length);
         assertNull(paths[0].getEntryRoot());


Reply via email to