Calling final methods through a custom assertion, which is inherited from AbstractListAssert, results in a java.lang.ClassCastException
Describe the bug Calling final methods through a custom assertion, which is inherited from AbstractListAssert, results in a java.lang.ClassCastException. In fact, any call to final methods inherited from the underlying Abstract Assert class leads to a java.lang.ClassCastException.
Could you advise on any workaround or point out where I might be handling the custom assertion implementation incorrectly?
- assertj core version: 3.27.3
- java version: 1.17
- groovy version: 4.0.18
- test framework version: spock 2.3-groovy-4.0
- os (if relevant): MacOS/Linux
Test case reproducing the bug
I've implemented an example project that describes the issue: https://github.com/AlexeyAkentyev/assertj-custom-assertions-example/blob/d13162c1537ec1f7ead34df42294a5d9640a7cce/src/test/groovy/org/example/custom/assertions/tests/DomainObjectsAssertionSpec.groovy#L136
Project contains example of domain related assertions.
Test fails with the error:
Caused by: java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Lorg.example.custom.assertions.domain.DomainObject; ([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; [Lorg.example.custom.assertions.domain.DomainObject; is in unnamed module of loader 'app')
An equivalent JUnit reproducer that can be executed in assertj-core-groovy:
package org.example.custom.assertions.tests
import org.example.custom.assertions.DomainSoftAssertions
import org.example.custom.assertions.domain.DomainObject
import org.junit.jupiter.api.Test
import static org.assertj.core.api.BDDAssertions.thenNoException
class MyTest {
@Test
void test() {
// GIVEN
def actualDomainObjects = [new DomainObject('actual', 1),
new DomainObject('actual', 2)]
// WHEN/THEN
thenNoException().isThrownBy {
DomainSoftAssertions.assertSoftly { softly ->
softly.assertThatDomainObjects(actualDomainObjects)
.hasExpectedDomainObjects()
.containsExactlyInAnyOrderElementsOf(actualDomainObjects)
}
}
}
}
which fails with:
java.lang.AssertionError:
Expecting code not to raise a throwable but caught
"java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Lorg.example.custom.assertions.domain.DomainObject; ([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; [Lorg.example.custom.assertions.domain.DomainObject; is in unnamed module of loader 'app')
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$P47T2xhc.containsExactlyInAnyOrderForProxy(Unknown Source)
at org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrder(AbstractIterableAssert.java:433)
at org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrderElementsOf(AbstractIterableAssert.java:449)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$P47T2xhc.containsExactlyInAnyOrderElementsOf$accessor$nyd4a6MD(Unknown Source)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$P47T2xhc$AssertJ$SoftProxies$nIaYve8G.call(Unknown Source)
at org.assertj.core.api.ErrorCollector.intercept(ErrorCollector.java:56)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$P47T2xhc.containsExactlyInAnyOrderElementsOf(Unknown Source)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$P47T2xhc.containsExactlyInAnyOrderElementsOf(Unknown Source)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest$_should_accept_triple_single_quoted_strings_closure1$_closure2.doCall(MyTest.groovy:31)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1007)
at groovy.lang.Closure.call(Closure.java:433)
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:52)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:113)
at jdk.proxy1/jdk.proxy1.$Proxy18.accept(Unknown Source)
at org.assertj.core.api.SoftAssertionsProvider.assertSoftly(SoftAssertionsProvider.java:119)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.DomainSoftAssertions.assertSoftly(DomainSoftAssertions.groovy:11)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest$_should_accept_triple_single_quoted_strings_closure1.doCall(MyTest.groovy:30)
at org.example.custom.assertions.tests.MyTest$_should_accept_triple_single_quoted_strings_closure1.doCall(MyTest.groovy)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1007)
at groovy.lang.Closure.call(Closure.java:433)
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:52)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:113)
at jdk.proxy2/jdk.proxy2.$Proxy15.call(Unknown Source)
at org.assertj.core.api.ThrowableAssert.catchThrowable(ThrowableAssert.java:63)
at org.assertj.core.api.NotThrownAssert.isThrownBy(NotThrownAssert.java:43)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest.should_accept_triple_single_quoted_strings(MyTest.groovy:29)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:775)
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:479)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:161)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:152)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:91)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:112)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:94)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:93)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:87)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:216)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:212)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:156)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:160)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:160)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:201)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:170)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:94)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:59)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:142)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:58)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85)
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39)
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38)
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
"
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest.should_accept_triple_single_quoted_strings(MyTest.groovy:29)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
The previous stack trace fails at:
org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$P47T2xhc.containsExactlyInAnyOrderForProxy(Unknown Source)
so apparently the issue is in the ByteBuddy proxy, although the stack trace reported by Spock doesn't mention it.
When changing the test to:
@Test
void test() {
// GIVEN
def actualDomainObjects = [new DomainObject('actual', 1),
new DomainObject('actual', 2)]
// WHEN/THEN
thenNoException().isThrownBy {
assertThatDomainObjects(actualDomainObjects)
.hasExpectedDomainObjects()
.containsExactlyInAnyOrderElementsOf(actualDomainObjects)
}
}
no failure happens.
To completely rule out issues with final methods, I changed:
https://github.com/assertj/assertj/blob/fae7ffd81ae425d05e95fdecbf4c96ea77d75857/assertj-core/src/main/java/org/assertj/core/api/AbstractIterableAssert.java#L447-L450
to:
@Override
public SELF containsExactlyInAnyOrderElementsOf(Iterable<? extends ELEMENT> values) {
return containsExactlyInAnyOrderForProxy(toArray(values));
}
and the test case still fails:
java.lang.AssertionError:
Expecting code not to raise a throwable but caught
"java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Lorg.example.custom.assertions.domain.DomainObject; ([Ljava.lang.Object; is in module java.base of loader 'bootstrap'; [Lorg.example.custom.assertions.domain.DomainObject; is in unnamed module of loader 'app')
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$MiKaD12S.containsExactlyInAnyOrderForProxy(Unknown Source)
at org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrderElementsOf(AbstractIterableAssert.java:449)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$MiKaD12S.containsExactlyInAnyOrderElementsOf$accessor$Bfn0c0HO(Unknown Source)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$MiKaD12S$AssertJ$SoftProxies$tY5XWFJH.call(Unknown Source)
at org.assertj.core.api.ErrorCollector.intercept(ErrorCollector.java:56)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$MiKaD12S.containsExactlyInAnyOrderElementsOf(Unknown Source)
at org.example.custom.assertions.domain.assertions.ListDomainObjectsAssertion$ByteBuddy$MiKaD12S.containsExactlyInAnyOrderElementsOf(Unknown Source)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest$_test_closure1$_closure2.doCall(MyTest.groovy:31)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1007)
at groovy.lang.Closure.call(Closure.java:433)
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:52)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:113)
at jdk.proxy1/jdk.proxy1.$Proxy18.accept(Unknown Source)
at org.assertj.core.api.SoftAssertionsProvider.assertSoftly(SoftAssertionsProvider.java:119)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.DomainSoftAssertions.assertSoftly(DomainSoftAssertions.groovy:11)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest$_test_closure1.doCall(MyTest.groovy:30)
at org.example.custom.assertions.tests.MyTest$_test_closure1.doCall(MyTest.groovy)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:343)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:328)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:280)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1007)
at groovy.lang.Closure.call(Closure.java:433)
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:52)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:113)
at jdk.proxy2/jdk.proxy2.$Proxy15.call(Unknown Source)
at org.assertj.core.api.ThrowableAssert.catchThrowable(ThrowableAssert.java:63)
at org.assertj.core.api.NotThrownAssert.isThrownBy(NotThrownAssert.java:43)
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest.test(MyTest.groovy:29)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:775)
at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:479)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:161)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:152)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:91)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:112)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:94)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:93)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:87)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:216)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:212)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:156)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:160)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:160)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:146)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:144)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:201)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:170)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:94)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:59)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:142)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:58)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85)
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
at org.junit.platform.launcher.core.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39)
at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25)
at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38)
at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
"
at org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:321)
at org.example.custom.assertions.tests.MyTest.test(MyTest.groovy:29)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Could you advise on any workaround or point out where I might be handling the custom assertion implementation incorrectly?
@AlexeyAkentyev So far, I think the issue happens only with soft assertions. I couldn't pinpoint the root cause, though.
As a workaround, you might consider using satisfies in your test code.
@scordio thanks a lot for the additional investigation details. I appreciate it. Based on your input, I've tried to figure out what conditions lead to the error.
I've modified the ForProxy method signature, and it works perfectly fine for SoftAssertion:
protected SELF containsExactlyInAnyOrderForProxy(List<ELEMENT> values) {
iterables.assertContainsExactlyInAnyOrder(info, actual, toArray(values));
return myself;
}
Your test now passes without any issues:
package org.example.custom.assertions.tests
import org.example.custom.assertions.DomainSoftAssertions
import org.example.custom.assertions.domain.DomainObject
import org.junit.jupiter.api.Test
import static org.assertj.core.api.BDDAssertions.thenNoException
class MyTest {
@Test
void test() {
// GIVEN
def actualDomainObjects = [new DomainObject('actual', 1),
new DomainObject('actual', 2)]
// WHEN/THEN
thenNoException().isThrownBy {
DomainSoftAssertions.assertSoftly { softly ->
softly.assertThatDomainObjects(actualDomainObjects)
.hasExpectedDomainObjects()
.containsExactlyInAnyOrderElementsOf(actualDomainObjects)
}
}
}
}
It looks like the issue is related to arrays. I've reproduced it with other ForProxy methods that use vararg/array parameters as well.
I hope this helps with the root cause analysis and fix.
Thanks for following up on this!
Would you like to create a PR with the fix?
This leads to significant internal changes.
As a solution, it will require switching from Array to List structures for any ForProxy method parameters.
Does this sound like an applicable solution?
If yes, I can try it out and share the results in a PR.
As a solution, it will require switching from Array to List structures for any
ForProxymethod parameters.
I don't see it as a problem 👍
We are already working on the next major version and breaking changes can definitely happen, especially to fix such topics.
So yes, a PR would be very welcome! 🙂
BTW, I haven't played enough with the issue to see if the same can be reproduced also in plain Java and not in Groovy. If plain Java is an option, I would favor it for the new test cases.
Thanks in advance and let us know if you need any support!