diff options
5 files changed, 48 insertions, 10 deletions
diff --git a/container-core/src/main/java/com/yahoo/processing/request/CloneHelper.java b/container-core/src/main/java/com/yahoo/processing/request/CloneHelper.java index 8a6a4f30e18..738e6c32c8b 100644 --- a/container-core/src/main/java/com/yahoo/processing/request/CloneHelper.java +++ b/container-core/src/main/java/com/yahoo/processing/request/CloneHelper.java @@ -3,7 +3,7 @@ package com.yahoo.processing.request; import com.yahoo.collections.MethodCache; import com.yahoo.component.provider.FreezableClass; -import com.yahoo.processing.request.properties.PublicCloneable; +import com.yahoo.lang.PublicCloneable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -30,7 +30,7 @@ import java.util.HashMap; */ public class CloneHelper { - private static Logger log = Logger.getLogger(CloneHelper.class.getName()); + private static final Logger log = Logger.getLogger(CloneHelper.class.getName()); private static final MethodCache cloneMethodCache = new MethodCache("clone"); /** @@ -79,28 +79,43 @@ public class CloneHelper { return arrayClone; } + @SuppressWarnings("deprecation") protected Object objectClone(Object object) { // Fastpath for our commonly used classes if (object instanceof FreezableClass) return ((FreezableClass)object).clone(); else if (object instanceof PublicCloneable) return ((PublicCloneable<?>)object).clone(); + else if (object instanceof com.yahoo.processing.request.properties.PublicCloneable) + return ((com.yahoo.processing.request.properties.PublicCloneable<?>)object).clone(); else if (object instanceof LinkedList) return ((LinkedList<?>) object).clone(); else if (object instanceof ArrayList) return ((ArrayList<?>) object).clone(); + try { + return cloneByReflection(object); + } catch (ClassCastException e) { + // When changing bundles you might end up having cached the old method pointing to old bundle, + // That might then lead to a class cast exception when invoking the wrong clone method. + // So we will give dropping the cache a try, and retry the clone. + cloneMethodCache.clear(); + return cloneByReflection(object); + } + + } + private Object cloneByReflection(Object object) { try { Method cloneMethod = cloneMethodCache.get(object); if (cloneMethod == null) { - log.warning("'" + object + "' of class " + object.getClass() + - " is Cloneable, but has no clone method - will use the same instance in all requests"); + log.warning("'" + object + "' of class " + object.getClass() + + " is Cloneable, but has no clone method - will use the same instance in all requests"); return null; } return cloneMethod.invoke(object); } catch (IllegalAccessException e) { - log.warning("'" + object + "' of class " + object.getClass() + - " is Cloneable, but clone method cannot be accessed - will use the same instance in all requests"); + log.warning("'" + object + "' of class " + object.getClass() + + " is Cloneable, but clone method cannot be accessed - will use the same instance in all requests"); return null; } catch (InvocationTargetException e) { throw new RuntimeException("Exception cloning '" + object + "'", e); diff --git a/container-core/src/main/java/com/yahoo/processing/request/properties/PublicCloneable.java b/container-core/src/main/java/com/yahoo/processing/request/properties/PublicCloneable.java index 4c8beea6a5d..9855aab16a6 100644 --- a/container-core/src/main/java/com/yahoo/processing/request/properties/PublicCloneable.java +++ b/container-core/src/main/java/com/yahoo/processing/request/properties/PublicCloneable.java @@ -7,9 +7,11 @@ package com.yahoo.processing.request.properties; * * @author bratseth * @since 5.66 + * @deprecated Use com.yahoo.lang.PublicCloneable instead */ +@Deprecated(forRemoval = true) // TODO: Remove on Vespa 9 public interface PublicCloneable<T> extends Cloneable { - public T clone(); + T clone(); } diff --git a/container-core/src/test/java/com/yahoo/processing/request/test/PropertyMapTestCase.java b/container-core/src/test/java/com/yahoo/processing/request/test/PropertyMapTestCase.java index de5437ab658..129409d3102 100644 --- a/container-core/src/test/java/com/yahoo/processing/request/test/PropertyMapTestCase.java +++ b/container-core/src/test/java/com/yahoo/processing/request/test/PropertyMapTestCase.java @@ -1,8 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.processing.request.test; +import com.yahoo.lang.PublicCloneable; import com.yahoo.processing.request.properties.PropertyMap; -import com.yahoo.processing.request.properties.PublicCloneable; import org.junit.jupiter.api.Test; import java.util.Arrays; diff --git a/vespajlib/src/main/java/com/yahoo/collections/MethodCache.java b/vespajlib/src/main/java/com/yahoo/collections/MethodCache.java index ea8060e203b..4a4331b1c6e 100644 --- a/vespajlib/src/main/java/com/yahoo/collections/MethodCache.java +++ b/vespajlib/src/main/java/com/yahoo/collections/MethodCache.java @@ -3,10 +3,13 @@ package com.yahoo.collections; import com.yahoo.concurrent.CopyOnWriteHashMap; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** + * This will cache methods solved by reflection as reflection is expensive. + * Note that if the bundle from which the method is removed/changed you might have + * a problem... A ClassCastException might be one indication. Then clearing the cache and retrying it + * once to see if it goes away might be a solution. * @author baldersheim */ public final class MethodCache { @@ -18,7 +21,14 @@ public final class MethodCache { this.methodName = methodName; } - public final Method get(Object object) { + /* + Clear all cached methods. Might be a wise thing to do, if you have cached some methods + that have changed due to new bundles being reloaded. + */ + public void clear() { + cache.clear(); + } + public Method get(Object object) { Method m = cache.get(object.getClass().getName()); if (m == null) { m = lookupMethod(object); diff --git a/vespajlib/src/main/java/com/yahoo/lang/PublicCloneable.java b/vespajlib/src/main/java/com/yahoo/lang/PublicCloneable.java new file mode 100644 index 00000000000..57a4bacdb5a --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/lang/PublicCloneable.java @@ -0,0 +1,11 @@ +package com.yahoo.lang; + +/** + * This interface publicly exposes the clone method. + * Implement this to allow faster clone. + * + * @author bratseth + */ +public interface PublicCloneable<T> extends Cloneable { + T clone(); +} |