You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by js...@apache.org on 2021/05/12 13:08:59 UTC
[sling-org-apache-sling-api] 01/01: SLING-10371 - SlingAdaptable:
ConcurrentModificationException on nested adaptTo() calls
This is an automated email from the ASF dual-hosted git repository.
jsedding pushed a commit to branch bug/SLING-10371-jsedding
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-api.git
commit 11566368c35ecdc6edf45d58717c1f42034bd410
Author: Julian Sedding <js...@apache.org>
AuthorDate: Wed May 12 15:08:05 2021 +0200
SLING-10371 - SlingAdaptable: ConcurrentModificationException on nested adaptTo() calls
- propose alternative fix
---
.../apache/sling/api/adapter/SlingAdaptable.java | 35 ++++++++++++----------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/src/main/java/org/apache/sling/api/adapter/SlingAdaptable.java b/src/main/java/org/apache/sling/api/adapter/SlingAdaptable.java
index 5adf0ce..08b337d 100644
--- a/src/main/java/org/apache/sling/api/adapter/SlingAdaptable.java
+++ b/src/main/java/org/apache/sling/api/adapter/SlingAdaptable.java
@@ -18,8 +18,10 @@
*/
package org.apache.sling.api.adapter;
-import java.util.HashMap;
+import org.jetbrains.annotations.NotNull;
+
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* The <code>SlingAdaptable</code> class is an (abstract) default implementation
@@ -74,7 +76,7 @@ public abstract class SlingAdaptable implements Adaptable {
* are intended to be short-lived to not hold on to objects and classes for
* too long.
*/
- private Map<Class<?>, Object> adaptersCache;
+ private volatile Map<Class<?>, Object> adaptersCache;
/**
* Calls into the registered {@link AdapterManager} to adapt this object to
@@ -94,22 +96,23 @@ public abstract class SlingAdaptable implements Adaptable {
*/
@SuppressWarnings("unchecked")
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
- AdapterType result = null;
- synchronized ( this ) {
- if ( adaptersCache != null ) {
- result = (AdapterType) adaptersCache.get(type);
- }
- if ( result == null ) {
- final AdapterManager mgr = ADAPTER_MANAGER;
- result = (mgr == null ? null : mgr.getAdapter(this, type));
- if ( result != null ) {
- if ( adaptersCache == null ) {
- adaptersCache = new HashMap<Class<?>, Object>();
- }
- adaptersCache.put(type, result);
+ final AdapterManager mgr = ADAPTER_MANAGER;
+ if (mgr == null) {
+ return null;
+ }
+ return (AdapterType) getAdaptersCache().computeIfAbsent(type, t -> mgr.getAdapter(this, t));
+ }
+
+ @NotNull
+ private Map<Class<?>, Object> getAdaptersCache() {
+ // correct use of double checked locking using volatile field
+ if (adaptersCache == null) {
+ synchronized (this) {
+ if (adaptersCache == null) {
+ adaptersCache = new ConcurrentHashMap<>();
}
}
}
- return result;
+ return adaptersCache;
}
}