diff --git a/bom/application/pom.xml b/bom/application/pom.xml index a9e309d627dfb..675daaef498f2 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -4858,6 +4858,11 @@ pom + + org.jboss.marshalling + jboss-marshalling + ${jboss-marshalling.version} + org.jboss.threads jboss-threads diff --git a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/it/TestParameterDevModeIT.java b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/it/TestParameterDevModeIT.java index 6219d4c8ca510..83355e35ca946 100644 --- a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/it/TestParameterDevModeIT.java +++ b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/it/TestParameterDevModeIT.java @@ -7,7 +7,6 @@ import org.apache.maven.shared.invoker.MavenInvocationException; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; @@ -22,7 +21,6 @@ * mvn install -Dit.test=DevMojoIT#methodName */ @DisabledIfSystemProperty(named = "quarkus.test.native", matches = "true") -@Disabled("Needs https://github.com/junit-team/junit5/pull/3820 and #40601") public class TestParameterDevModeIT extends RunAndCheckMojoTestBase { protected int getPort() { 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 da4a434c123b7..0f881f19022ce 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,8 +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; import org.jboss.jandex.AnnotationInstance; @@ -52,7 +50,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 +103,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, @@ -124,7 +121,6 @@ public class QuarkusTestExtension extends AbstractJvmQuarkusTestExtension // needed for @Nested private static final Deque outerInstances = new ArrayDeque<>(1); private static RunningQuarkusApplication runningQuarkusApplication; - private static Pattern clonePattern; private static Throwable firstException; //if this is set then it will be thrown from the very first test that is run, the rest are aborted private static Class quarkusTestMethodContextClass; @@ -260,11 +256,11 @@ public Thread newThread(Runnable r) { runningQuarkusApplication = startupAction .runMainClass(profileInstance.commandLineParameters()); } - String patternString = runningQuarkusApplication.getConfigValue("quarkus.test.class-clone-pattern", String.class) - .orElse("java\\..*"); - clonePattern = Pattern.compile(patternString); + TracingHandler.quarkusStarted(); + deepClone.setRunningQuarkusApplication(runningQuarkusApplication); + //now we have full config reset the hang timer if (hangTaskKey != null) { @@ -351,7 +347,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) { @@ -957,50 +953,14 @@ private Object runExtensionMethod(ReflectiveInvocationContext invocation List argumentsFromTccl = new ArrayList<>(); 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 (testMethodInvokerToUse != null) { + Class argClass = parameters[i].getType(); - if (replacement != null) { - argumentsFromTccl.add(replacement); - } else if (cloneRequired) { - argumentsFromTccl.add(deepClone.clone(arg)); - } else if (testMethodInvokerToUse != null) { argumentsFromTccl.add(testMethodInvokerToUse.getClass().getMethod("methodParamInstance", String.class) .invoke(testMethodInvokerToUse, argClass.getName())); } else { - argumentsFromTccl.add(arg); + Object arg = originalArguments.get(i); + argumentsFromTccl.add(deepClone.clone(arg)); } } @@ -1235,7 +1195,6 @@ protected void doClose() throws IOException { log.error("Failed to shutdown Quarkus", e); } finally { runningQuarkusApplication = null; - clonePattern = null; Thread.currentThread().setContextClassLoader(old); ConfigProviderResolver.setInstance(null); } 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/DeepClone.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/DeepClone.java index e77a4022cacb1..88668b9909833 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/DeepClone.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/DeepClone.java @@ -1,11 +1,15 @@ package io.quarkus.test.junit.internal; +import io.quarkus.bootstrap.app.RunningQuarkusApplication; + /** * Strategy to deep clone an object - * + *

* Used in order to clone an object loaded from one ClassLoader into another */ public interface DeepClone { Object clone(Object objectToClone); + + void setRunningQuarkusApplication(RunningQuarkusApplication runningQuarkusApplication); } 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..b5afc517cf95b --- /dev/null +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/internal/NewSerializingDeepClone.java @@ -0,0 +1,144 @@ +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.function.Supplier; +import java.util.regex.Pattern; + +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; + +import io.quarkus.bootstrap.app.RunningQuarkusApplication; + +/** + * A deep-clone implementation using JBoss Marshalling's fast object cloner. + */ +public final class NewSerializingDeepClone implements DeepClone { + private final ObjectCloner cloner; + private static Pattern clonePattern; + private RunningQuarkusApplication runningQuarkusApplication; + + 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) -> { + // The class we're really dealing with, which might be wrapped inside an array, or a nest of arrays + Class theClassWeCareAbout = original.getClass(); + while (theClassWeCareAbout.isArray()) { + theClassWeCareAbout = theClassWeCareAbout.getComponentType(); + } + + // Short-circuit the checks if we've been configured to clone this + if (!clonePattern.matcher(theClassWeCareAbout.getName()).matches()) { + + if (theClassWeCareAbout.isPrimitive()) { + // avoid copying things that do not need to be copied + return original; + } else if (isUncloneable(theClassWeCareAbout)) { + 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 { + try { + if (runningQuarkusApplication != null && runningQuarkusApplication.getClassLoader() + .loadClass(theClassWeCareAbout.getName()) == theClassWeCareAbout) { + // Don't clone things which are already loaded by the quarkus application's classloader side of the tree + return original; + } + } catch (ClassNotFoundException e) { + + if (original instanceof Supplier s) { + // sneaky + return (Supplier) () -> clone(s.get()); + } else { + throw e; + } + } + + 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); + } + } + + @Override + public void setRunningQuarkusApplication(RunningQuarkusApplication runningQuarkusApplication) { + this.runningQuarkusApplication = runningQuarkusApplication; + String patternString = runningQuarkusApplication.getConfigValue("quarkus.test.class-clone-pattern", String.class) + .orElse("java\\..*"); + clonePattern = Pattern.compile(patternString); + } + +} 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 handleSupplier(final Supplier supplier) { - return new Supplier() { - @Override - public Object get() { - return doClone(supplier.get()); - } - }; - } - - private Object doClone(Object objectToClone) { - XStream xStream = xStreamSupplier.get(); - final String serialized = xStream.toXML(objectToClone); - final Object result = xStream.fromXML(serialized); - if (result == null) { - throw new IllegalStateException("Unable to deep clone object of type '" + objectToClone.getClass().getName() - + "'. Please report the issue on the Quarkus issue tracker."); - } - return result; - } -}