Skip to content

Varargs methods cause ClassCastException in AnswerFunctionalInterfaces #2644

Closed

Description

@perlun

Hi,

The other day, I discovered that this code does not work:

        doAnswer(answerVoid((VoidAnswer2<String, Object[]>)
                logger::info
        )).when(mock)
                .info(any(), (Object[]) any());

        // This call will throw an exception
        mock.info("Some message with {} {} {}", "three", "parameters", "");

The exception details looks as follows:

class java.lang.String cannot be cast to class [Ljava.lang.Object; (java.lang.String and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
java.lang.ClassCastException: class java.lang.String cannot be cast to class [Ljava.lang.Object; (java.lang.String and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
	at org.mockito.internal.stubbing.answers.AnswerFunctionalInterfaces$4.answer(AnswerFunctionalInterfaces.java:97)
	at org.mockito.internal.stubbing.answers.AnswerFunctionalInterfaces$4.answer(AnswerFunctionalInterfaces.java:93)
	at org.mockito.internal.stubbing.StubbedInvocationMatcher.answer(StubbedInvocationMatcher.java:42)
	at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:103)
	at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
	at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:34)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:82)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:56)
	at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptAbstract(MockMethodInterceptor.java:161)
	at org.slf4j.Logger$MockitoMock$f4Org7xs.info(Unknown Source)
	at LoggerMockingTest.logger_info_can_be_called_without_exceptions(LoggerMockingTest.java:34)
        [...]

The following works, but feels much less elegant:

        doAnswer( invocation -> {
            String format = invocation.getArgument( 0 );
            Object[] allArguments = invocation.getArguments();
            Object[] arguments = Arrays.copyOfRange( allArguments, 1, allArguments.length );
            logger.info( format, arguments );
            return null;
        } ).when( mock )
                .info( anyString(), (Object[])any() );

Is this to be considered a bug or a feature? 🙂 I get the feeling that varargs (Object[] under the hood) parameters do not really work when used with the answerVoid()-based approach as described above.

Full MCVE

https://github.com/perlun/mockito-slf4-logging-example

Issue checks

  • The mockito message in the stacktrace have useful information, but it didn't help
  • The problematic code (if that's possible) is copied here;
    Note that some configuration are impossible to mock via Mockito
  • Provide versions (mockito / jdk / os / any other relevant information): Reproduced with latest Mockito, 4.5.1
  • Provide a Short, Self Contained, Correct (Compilable), Example of the issue
  • Read the contributing guide

Activity

  1. big-andy-coates commented on Jun 1, 2022

    @big-andy-coates
    Contributor

    I've had a bit of a dig and it looks like a bug to me. returnsArgAt has similar issues. I'm happy to have a look into this.

  2. added 3 commits that reference this issue on Jun 2, 2022
    057c795
    7cbc653
    459efad
  3. added a commit that references this issue on Jun 11, 2022
    ce4e64d
  4. perlun commented on Jul 4, 2022

    @perlun
    ContributorAuthor

    Thanks for the fix @big-andy-coates & @TimvdLippe, appreciated!

  5. perlun commented on Aug 30, 2022

    @perlun
    ContributorAuthor

    (Verified in our project that the fix indeed fixes the original problem. Thanks! 🙏)

  6. perlun commented on Nov 18, 2022

    @perlun
    ContributorAuthor

    Semi-related issue discovered today: #2664 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions