diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index f103249dc515f..4aa774e0e5e72 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -120,6 +120,7 @@
1.7.0.Final
1.0.1.Final
2.4.1.Final
+ 2.1.4.SP1
3.6.1.Final
4.5.7
4.5.14
@@ -4796,6 +4797,11 @@
pom
+
+ org.jboss.marshalling
+ jboss-marshalling
+ ${jboss-marshalling.version}
+
org.jboss.threads
jboss-threads
diff --git a/test-framework/junit5/pom.xml b/test-framework/junit5/pom.xml
index 132c4db1b6531..449f8fda37df5 100644
--- a/test-framework/junit5/pom.xml
+++ b/test-framework/junit5/pom.xml
@@ -49,10 +49,8 @@
quarkus-core
- com.thoughtworks.xstream
- xstream
-
- 1.4.20
+ org.jboss.marshalling
+ jboss-marshalling
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java
index f2707e915346b..15fa6c360e67b 100644
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java
+++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java
@@ -40,7 +40,6 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.function.Supplier;
import java.util.regex.Pattern;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
@@ -52,7 +51,6 @@
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
@@ -106,7 +104,7 @@
import io.quarkus.test.junit.callback.QuarkusTestContext;
import io.quarkus.test.junit.callback.QuarkusTestMethodContext;
import io.quarkus.test.junit.internal.DeepClone;
-import io.quarkus.test.junit.internal.SerializationWithXStreamFallbackDeepClone;
+import io.quarkus.test.junit.internal.NewSerializingDeepClone;
public class QuarkusTestExtension extends AbstractJvmQuarkusTestExtension
implements BeforeEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, AfterEachCallback,
@@ -355,7 +353,7 @@ private void shutdownHangDetection() {
}
private void populateDeepCloneField(StartupAction startupAction) {
- deepClone = new SerializationWithXStreamFallbackDeepClone(startupAction.getClassLoader());
+ deepClone = new NewSerializingDeepClone(originalCl, startupAction.getClassLoader());
}
private void populateTestMethodInvokers(ClassLoader quarkusClassLoader) {
@@ -962,49 +960,13 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation
Parameter[] parameters = invocationContext.getExecutable().getParameters();
for (int i = 0; i < originalArguments.size(); i++) {
Object arg = originalArguments.get(i);
- boolean cloneRequired = false;
- Object replacement = null;
Class> argClass = parameters[i].getType();
- if (arg != null) {
- Class> theclass = argClass;
- while (theclass.isArray()) {
- theclass = theclass.getComponentType();
- }
- if (theclass.isPrimitive()) {
- cloneRequired = false;
- } else if (TestInfo.class.isAssignableFrom(theclass)) {
- TestInfo info = (TestInfo) arg;
- Method newTestMethod = info.getTestMethod().isPresent()
- ? determineTCCLExtensionMethod(info.getTestMethod().get(), testClassFromTCCL)
- : null;
- replacement = new TestInfoImpl(info.getDisplayName(), info.getTags(),
- Optional.of(testClassFromTCCL),
- Optional.ofNullable(newTestMethod));
- } else if (clonePattern.matcher(theclass.getName()).matches()) {
- cloneRequired = true;
- } else {
- try {
- cloneRequired = runningQuarkusApplication.getClassLoader()
- .loadClass(theclass.getName()) != theclass;
- } catch (ClassNotFoundException e) {
- if (arg instanceof Supplier) {
- cloneRequired = true;
- } else {
- throw e;
- }
- }
- }
- }
- if (replacement != null) {
- argumentsFromTccl.add(replacement);
- } else if (cloneRequired) {
- argumentsFromTccl.add(deepClone.clone(arg));
- } else if (testMethodInvokerToUse != null) {
+ if (testMethodInvokerToUse != null) {
argumentsFromTccl.add(testMethodInvokerToUse.getClass().getMethod("methodParamInstance", String.class)
.invoke(testMethodInvokerToUse, argClass.getName()));
} else {
- argumentsFromTccl.add(arg);
+ argumentsFromTccl.add(deepClone.clone(arg));
}
}
@@ -1014,7 +976,7 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation
.invoke(testMethodInvokerToUse, effectiveTestInstance, newMethod, argumentsFromTccl,
extensionContext.getRequiredTestClass().getName());
} else {
- return newMethod.invoke(effectiveTestInstance, argumentsFromTccl.toArray(new Object[0]));
+ return newMethod.invoke(effectiveTestInstance, argumentsFromTccl.toArray(Object[]::new));
}
} catch (InvocationTargetException e) {
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomListConverter.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomListConverter.java
deleted file mode 100644
index ddb8642d0056c..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomListConverter.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Predicate;
-
-import com.thoughtworks.xstream.converters.collections.CollectionConverter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-/**
- * A custom List converter that always uses ArrayList for unmarshalling.
- * This is probably not semantically correct 100% of the time, but it's likely fine
- * for all the cases where we are using marshalling / unmarshalling.
- *
- * The reason for doing this is to avoid XStream causing illegal access issues
- * for internal JDK lists
- */
-public class CustomListConverter extends CollectionConverter {
-
- // if we wanted to be 100% sure, we'd list all the List.of methods, but I think it's pretty safe to say
- // that the JDK won't add custom implementations for the other classes
-
- private final Predicate supported = new Predicate() {
-
- private final Set JDK_LIST_CLASS_NAMES = Set.of(
- List.of().getClass().getName(),
- List.of(Integer.MAX_VALUE).getClass().getName(),
- Arrays.asList(Integer.MAX_VALUE).getClass().getName(),
- Collections.unmodifiableList(List.of()).getClass().getName(),
- Collections.emptyList().getClass().getName(),
- List.of(Integer.MIN_VALUE, Integer.MAX_VALUE).subList(0, 1).getClass().getName());
-
- @Override
- public boolean test(String className) {
- return JDK_LIST_CLASS_NAMES.contains(className);
- }
- }.or(new Predicate<>() {
-
- private static final String GUAVA_LISTS_PACKAGE = "com.google.common.collect.Lists";
-
- @Override
- public boolean test(String className) {
- return className.startsWith(GUAVA_LISTS_PACKAGE);
- }
- });
-
- public CustomListConverter(Mapper mapper) {
- super(mapper);
- }
-
- @Override
- public boolean canConvert(Class type) {
- return (type != null) && supported.test(type.getName());
- }
-
- @Override
- protected Object createCollection(Class type) {
- return new ArrayList<>();
- }
-}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapConverter.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapConverter.java
deleted file mode 100644
index fe93cb8594587..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapConverter.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-import com.thoughtworks.xstream.converters.collections.MapConverter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-/**
- * A custom Map converter that always uses HashMap for unmarshalling.
- * This is probably not semantically correct 100% of the time, but it's likely fine
- * for all the cases where we are using marshalling / unmarshalling.
- *
- * The reason for doing this is to avoid XStream causing illegal access issues
- * for internal JDK maps
- */
-public class CustomMapConverter extends MapConverter {
-
- // if we wanted to be 100% sure, we'd list all the Set.of methods, but I think it's pretty safe to say
- // that the JDK won't add custom implementations for the other classes
- private final Set SUPPORTED_CLASS_NAMES = Set.of(
- Map.of().getClass().getName(),
- Map.of(Integer.MAX_VALUE, Integer.MAX_VALUE).getClass().getName(),
- Collections.emptyMap().getClass().getName());
-
- public CustomMapConverter(Mapper mapper) {
- super(mapper);
- }
-
- @Override
- public boolean canConvert(Class type) {
- return (type != null) && SUPPORTED_CLASS_NAMES.contains(type.getName());
- }
-
- @Override
- protected Object createCollection(Class type) {
- return new HashMap<>();
- }
-}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapEntryConverter.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapEntryConverter.java
deleted file mode 100644
index f20a7fe3e3f36..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomMapEntryConverter.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.util.AbstractMap;
-import java.util.Map;
-import java.util.Set;
-
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.converters.collections.MapConverter;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-/**
- * A custom Map.Entry converter that always uses AbstractMap.SimpleEntry for unmarshalling.
- * This is probably not semantically correct 100% of the time, but it's likely fine
- * for all the cases where we are using marshalling / unmarshalling.
- *
- * The reason for doing this is to avoid XStream causing illegal access issues
- * for internal JDK types
- */
-@SuppressWarnings({ "rawtypes", "unchecked" })
-public class CustomMapEntryConverter extends MapConverter {
-
- private final Set SUPPORTED_CLASS_NAMES = Set
- .of(Map.entry(Integer.MAX_VALUE, Integer.MAX_VALUE).getClass().getName());
-
- public CustomMapEntryConverter(Mapper mapper) {
- super(mapper);
- }
-
- @Override
- public boolean canConvert(Class type) {
- return (type != null) && SUPPORTED_CLASS_NAMES.contains(type.getName());
- }
-
- @Override
- public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
- var entryName = mapper().serializedClass(Map.Entry.class);
- var entry = (Map.Entry) source;
- writer.startNode(entryName);
- writeCompleteItem(entry.getKey(), context, writer);
- writeCompleteItem(entry.getValue(), context, writer);
- writer.endNode();
- }
-
- @Override
- public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
- reader.moveDown();
- var key = readCompleteItem(reader, context, null);
- var value = readCompleteItem(reader, context, null);
- reader.moveUp();
- return new AbstractMap.SimpleEntry(key, value);
- }
-}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomSetConverter.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomSetConverter.java
deleted file mode 100644
index 88d434cfaf34a..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/CustomSetConverter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import com.thoughtworks.xstream.converters.collections.CollectionConverter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-/**
- * A custom Set converter that always uses HashSet for unmarshalling.
- * This is probably not semantically correct 100% of the time, but it's likely fine
- * for all the cases where we are using marshalling / unmarshalling.
- *
- * The reason for doing this is to avoid XStream causing illegal access issues
- * for internal JDK sets
- */
-public class CustomSetConverter extends CollectionConverter {
-
- // if we wanted to be 100% sure, we'd list all the Set.of methods, but I think it's pretty safe to say
- // that the JDK won't add custom implementations for the other classes
- private final Set SUPPORTED_CLASS_NAMES = Set.of(
- Set.of().getClass().getName(),
- Set.of(Integer.MAX_VALUE).getClass().getName(),
- Collections.emptySet().getClass().getName());
-
- public CustomSetConverter(Mapper mapper) {
- super(mapper);
- }
-
- @Override
- public boolean canConvert(Class type) {
- return (type != null) && SUPPORTED_CLASS_NAMES.contains(type.getName());
- }
-
- @Override
- protected Object createCollection(Class type) {
- return new HashSet<>();
- }
-}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/NewSerializingDeepClone.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/NewSerializingDeepClone.java
new file mode 100644
index 0000000000000..682a196e00c71
--- /dev/null
+++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/NewSerializingDeepClone.java
@@ -0,0 +1,113 @@
+package io.quarkus.test.junit.internal;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.jboss.marshalling.cloner.ClassCloner;
+import org.jboss.marshalling.cloner.ClonerConfiguration;
+import org.jboss.marshalling.cloner.ObjectCloner;
+import org.jboss.marshalling.cloner.ObjectCloners;
+import org.junit.jupiter.api.TestInfo;
+
+/**
+ * A deep-clone implementation using JBoss Marshalling's fast object cloner.
+ */
+public final class NewSerializingDeepClone implements DeepClone {
+ private final ObjectCloner cloner;
+
+ public NewSerializingDeepClone(final ClassLoader sourceLoader, final ClassLoader targetLoader) {
+ ClonerConfiguration cc = new ClonerConfiguration();
+ cc.setSerializabilityChecker(clazz -> clazz != Object.class);
+ cc.setClassCloner(new ClassCloner() {
+ public Class> clone(final Class> original) {
+ if (isUncloneable(original)) {
+ return original;
+ }
+ try {
+ return targetLoader.loadClass(original.getName());
+ } catch (ClassNotFoundException ignored) {
+ return original;
+ }
+ }
+
+ public Class> cloneProxy(final Class> proxyClass) {
+ // not really supported
+ return proxyClass;
+ }
+ });
+ cc.setCloneTable(
+ (original, objectCloner, classCloner) -> {
+ if (EXTRA_IDENTITY_CLASSES.contains(original.getClass())) {
+ // avoid copying things that do not need to be copied
+ return original;
+ } else if (isUncloneable(original.getClass())) {
+ if (original instanceof Supplier> s) {
+ // sneaky
+ return (Supplier>) () -> clone(s.get());
+ } else {
+ return original;
+ }
+ } else if (original instanceof TestInfo info) {
+ // copy the test info correctly
+ return new TestInfoImpl(info.getDisplayName(), info.getTags(),
+ info.getTestClass().map(this::cloneClass),
+ info.getTestMethod().map(this::cloneMethod));
+ } else if (original == sourceLoader) {
+ return targetLoader;
+ }
+ // let the default cloner handle it
+ return null;
+ });
+ cloner = ObjectCloners.getSerializingObjectClonerFactory().createCloner(cc);
+ }
+
+ private static boolean isUncloneable(Class> clazz) {
+ return clazz.isHidden() && !Serializable.class.isAssignableFrom(clazz);
+ }
+
+ private Class> cloneClass(Class> clazz) {
+ try {
+ return (Class>) cloner.clone(clazz);
+ } catch (IOException | ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ private Method cloneMethod(Method method) {
+ try {
+ Class> declaring = (Class>) cloner.clone(method.getDeclaringClass());
+ Class>[] argTypes = (Class>[]) cloner.clone(method.getParameterTypes());
+ return declaring.getDeclaredMethod(method.getName(), argTypes);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public Object clone(final Object objectToClone) {
+ try {
+ return cloner.clone(objectToClone);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Classes which do not need to be cloned.
+ */
+ private static final Set> EXTRA_IDENTITY_CLASSES = Set.of(
+ Object.class,
+ byte[].class,
+ short[].class,
+ int[].class,
+ long[].class,
+ char[].class,
+ boolean[].class,
+ float[].class,
+ double[].class);
+}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/SerializationDeepClone.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/SerializationDeepClone.java
deleted file mode 100644
index 3da2c0c16e372..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/SerializationDeepClone.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.ObjectStreamClass;
-
-/**
- * Cloning strategy that just serializes and deserializes using plain old java serialization.
- */
-class SerializationDeepClone implements DeepClone {
-
- private final ClassLoader classLoader;
-
- SerializationDeepClone(ClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
- @Override
- public Object clone(Object objectToClone) {
- ByteArrayOutputStream byteOut = new ByteArrayOutputStream(512);
- try (ObjectOutputStream objOut = new ObjectOutputStream(byteOut)) {
- objOut.writeObject(objectToClone);
- try (ObjectInputStream objIn = new ClassLoaderAwareObjectInputStream(byteOut)) {
- return objIn.readObject();
- }
- } catch (IOException | ClassNotFoundException e) {
- throw new IllegalStateException("Unable to deep clone object of type '" + objectToClone.getClass().getName()
- + "'. Please report the issue on the Quarkus issue tracker.", e);
- }
- }
-
- private class ClassLoaderAwareObjectInputStream extends ObjectInputStream {
-
- public ClassLoaderAwareObjectInputStream(ByteArrayOutputStream byteOut) throws IOException {
- super(new ByteArrayInputStream(byteOut.toByteArray()));
- }
-
- @Override
- protected Class> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
- return Class.forName(desc.getName(), true, classLoader);
- }
- }
-}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/SerializationWithXStreamFallbackDeepClone.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/SerializationWithXStreamFallbackDeepClone.java
deleted file mode 100644
index 36da89a82e804..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/SerializationWithXStreamFallbackDeepClone.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.io.Serializable;
-import java.util.Optional;
-
-import org.jboss.logging.Logger;
-
-/**
- * Cloning strategy delegating to {@link SerializationDeepClone}, falling back to {@link XStreamDeepClone} in case of error.
- */
-public class SerializationWithXStreamFallbackDeepClone implements DeepClone {
-
- private static final Logger LOG = Logger.getLogger(SerializationWithXStreamFallbackDeepClone.class);
-
- private final SerializationDeepClone serializationDeepClone;
- private final XStreamDeepClone xStreamDeepClone;
-
- public SerializationWithXStreamFallbackDeepClone(ClassLoader classLoader) {
- this.serializationDeepClone = new SerializationDeepClone(classLoader);
- this.xStreamDeepClone = new XStreamDeepClone(classLoader);
- }
-
- @Override
- public Object clone(Object objectToClone) {
- if (objectToClone instanceof Serializable) {
- try {
- return serializationDeepClone.clone(objectToClone);
- } catch (RuntimeException re) {
- LOG.debugf("SerializationDeepClone failed (will fall back to XStream): %s",
- Optional.ofNullable(re.getCause()).orElse(re));
- }
- }
- return xStreamDeepClone.clone(objectToClone);
- }
-}
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/TestInfoImpl.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/TestInfoImpl.java
similarity index 95%
rename from test-framework/junit5/src/main/java/io/quarkus/test/junit/TestInfoImpl.java
rename to test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/TestInfoImpl.java
index 498cc5ff64447..7cc0be697b719 100644
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/TestInfoImpl.java
+++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/TestInfoImpl.java
@@ -1,4 +1,4 @@
-package io.quarkus.test.junit;
+package io.quarkus.test.junit.internal;
import java.lang.reflect.Method;
import java.util.Optional;
diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/XStreamDeepClone.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/XStreamDeepClone.java
deleted file mode 100644
index 9951f96734d44..0000000000000
--- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/XStreamDeepClone.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package io.quarkus.test.junit.internal;
-
-import java.util.function.Supplier;
-
-import com.thoughtworks.xstream.XStream;
-
-/**
- * Super simple cloning strategy that just serializes to XML and deserializes it using xstream
- */
-class XStreamDeepClone implements DeepClone {
-
- private final Supplier xStreamSupplier;
-
- XStreamDeepClone(ClassLoader classLoader) {
- // avoid doing any work eagerly since the cloner is rarely used
- xStreamSupplier = () -> {
- XStream result = new XStream();
- result.allowTypesByRegExp(new String[] { ".*" });
- result.setClassLoader(classLoader);
- result.registerConverter(new CustomListConverter(result.getMapper()));
- result.registerConverter(new CustomSetConverter(result.getMapper()));
- result.registerConverter(new CustomMapConverter(result.getMapper()));
- result.registerConverter(new CustomMapEntryConverter(result.getMapper()));
-
- return result;
- };
- }
-
- @Override
- public Object clone(Object objectToClone) {
- if (objectToClone == null) {
- return null;
- }
-
- if (objectToClone instanceof Supplier) {
- return handleSupplier((Supplier>) objectToClone);
- }
-
- return doClone(objectToClone);
- }
-
- private Supplier