aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--container-core/src/main/java/com/yahoo/processing/request/CloneHelper.java27
-rw-r--r--container-core/src/main/java/com/yahoo/processing/request/properties/PublicCloneable.java4
-rw-r--r--container-core/src/test/java/com/yahoo/processing/request/test/PropertyMapTestCase.java2
-rw-r--r--vespajlib/src/main/java/com/yahoo/collections/MethodCache.java14
-rw-r--r--vespajlib/src/main/java/com/yahoo/lang/PublicCloneable.java11
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();
+}