openrewrite / rewrite-testing-frameworks

OpenRewrite recipes that perform common Java testing migration tasks.
Apache License 2.0
77 stars 73 forks source link

ClassCastException when using JMockitBlockToMockito #619

Open xanaxan opened 1 month ago

xanaxan commented 1 month ago

What version of OpenRewrite are you using?

I am using

How are you running OpenRewrite?

I am using the Maven plugin, and my project is a multi-module project.

<plugin>
                <groupId>org.openrewrite.maven</groupId>
                <artifactId>rewrite-maven-plugin</artifactId>
                <version>5.43.0</version>
                <configuration>
                    <exportDatatables>true</exportDatatables>
                    <activeRecipes>
                        <!--                        <recipe>org.openrewrite.java.testing.jmockit.JMockitAnnotatedArgumentToMockito</recipe>-->
                        <recipe>org.openrewrite.java.testing.jmockit.JMockitBlockToMockito</recipe>
                    </activeRecipes>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.openrewrite.recipe</groupId>
                        <artifactId>rewrite-testing-frameworks</artifactId>
                        <version>2.21.0</version>
                    </dependency>
                    <dependency>
                        <groupId>org.openrewrite</groupId>
                        <artifactId>rewrite-xml</artifactId>
                        <version>LATEST</version>
                    </dependency>
                    <dependency>
                        <groupId>org.openrewrite.recipe</groupId>
                        <artifactId>rewrite-migrate-java</artifactId>
                        <version>LATEST</version>
                    </dependency>
                </dependencies>
            </plugin>

What is the smallest, simplest way to reproduce the problem?

import mockit.Expectations;
import mockit.Mocked;
import mockit.Tested;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import jakarta.enterprise.inject.spi.InjectionPoint;
import java.lang.reflect.Member;

public class LoggerProducerTest {
    @Tested
    private LoggerProducer loggerProducer;

    @Mocked
    private InjectionPoint injectionPoint;

    @Mocked
    private Member member;

    @Test
    public void shouldProduce() {
        this.mockInjectionpoint();

        Assertions.assertNotNull(loggerProducer);
        Assertions.assertNotNull(loggerProducer.createLogger(injectionPoint));
    }

    private void mockInjectionpoint() {
        new Expectations() { //replaced StrictExpectations
            {
                LoggerProducerTest.this.injectionPoint.getMember();
                this.result = member;

                LoggerProducerTest.this.member.getDeclaringClass();
                this.result = LoggerProducerTest.class;
            }
        };
    }
}

@Singleton
public class LoggerProducer {

    @Produces
    Logger createLogger(final InjectionPoint ip) {
        return LoggerFactory.getLogger(ip.getMember().getDeclaringClass());
    }
}

What did you see instead?

Caused by: java.lang.ClassCastException: class org.openrewrite.java.tree.J$FieldAccess cannot be cast to class org.openrewrite.java.tree.J$Identifier (org.openrewrite.java.tree.J$FieldAccess and org.openrewrite.java.tree.J$Identifier are in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @201fd61a)

What is the full stack trace of any errors you encountered?

org.openrewrite.internal.RecipeRunException: java.lang.ClassCastException: class org.openrewrite.java.tree.J$FieldAccess cannot be cast to class org.openrewrite.java.tree.J$Identifier (org.openrewrite.java.tree.J$FieldAccess and org.openrewrite.java.tree.J$Identifier are in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @201fd61a)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:290)
    at org.openrewrite.TreeVisitor.visitAndCast (TreeVisitor.java:320)
    at org.openrewrite.java.JavaVisitor.visitRightPadded (JavaVisitor.java:1367)
    at org.openrewrite.java.JavaVisitor.lambda$visitBlock$4 (JavaVisitor.java:397)
    at org.openrewrite.internal.ListUtils.map (ListUtils.java:177)
    at org.openrewrite.java.JavaVisitor.visitBlock (JavaVisitor.java:396)
    at org.openrewrite.java.JavaIsoVisitor.visitBlock (JavaIsoVisitor.java:88)
    at org.openrewrite.java.JavaIsoVisitor.visitBlock (JavaIsoVisitor.java:30)
    at org.openrewrite.java.tree.J$Block.acceptJava (J.java:838)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visitAndCast (TreeVisitor.java:320)
    at org.openrewrite.java.JavaVisitor.visitClassDeclaration (JavaVisitor.java:482)
    at org.openrewrite.java.JavaIsoVisitor.visitClassDeclaration (JavaIsoVisitor.java:108)
    at org.openrewrite.java.JavaIsoVisitor.visitClassDeclaration (JavaIsoVisitor.java:30)
    at org.openrewrite.java.tree.J$ClassDeclaration.acceptJava (J.java:1278)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visitAndCast (TreeVisitor.java:320)
    at org.openrewrite.java.JavaVisitor.lambda$visitCompilationUnit$9 (JavaVisitor.java:495)
    at org.openrewrite.internal.ListUtils.map (ListUtils.java:177)
    at org.openrewrite.java.JavaVisitor.visitCompilationUnit (JavaVisitor.java:495)
    at org.openrewrite.java.JavaIsoVisitor.visitCompilationUnit (JavaIsoVisitor.java:113)
    at org.openrewrite.java.JavaIsoVisitor.visitCompilationUnit (JavaIsoVisitor.java:30)
    at org.openrewrite.java.tree.J$CompilationUnit.acceptJava (J.java:1549)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:157)
    at org.openrewrite.Preconditions$Check.visit (Preconditions.java:175)
    at org.openrewrite.Preconditions$Check.visit (Preconditions.java:145)
    at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$6 (RecipeRunCycle.java:186)
    at io.micrometer.core.instrument.AbstractTimer.recordCallable (AbstractTimer.java:178)
    at org.openrewrite.table.RecipeRunStats.recordEdit (RecipeRunStats.java:67)
    at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$7 (RecipeRunCycle.java:182)
    at org.openrewrite.scheduling.RecipeStack.reduce (RecipeStack.java:57)
    at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$8 (RecipeRunCycle.java:155)
    at org.openrewrite.internal.InMemoryLargeSourceSet.lambda$edit$0 (InMemoryLargeSourceSet.java:66)
    at org.openrewrite.internal.ListUtils.map (ListUtils.java:177)
    at org.openrewrite.internal.InMemoryLargeSourceSet.edit (InMemoryLargeSourceSet.java:65)
    at org.openrewrite.scheduling.RecipeRunCycle.editSources (RecipeRunCycle.java:154)
    at org.openrewrite.RecipeScheduler.runRecipeCycles (RecipeScheduler.java:87)
    at org.openrewrite.RecipeScheduler.scheduleRun (RecipeScheduler.java:41)
    at org.openrewrite.Recipe.run (Recipe.java:376)
    at org.openrewrite.Recipe.run (Recipe.java:372)
    at org.openrewrite.Recipe.run (Recipe.java:368)
    at org.openrewrite.maven.AbstractRewriteBaseRunMojo.runRecipe (AbstractRewriteBaseRunMojo.java:243)
    at org.openrewrite.maven.AbstractRewriteBaseRunMojo.listResults (AbstractRewriteBaseRunMojo.java:154)
    at org.openrewrite.maven.AbstractRewriteRunMojo.execute (AbstractRewriteRunMojo.java:64)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:126)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:328)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:193)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:180)
    at java.util.concurrent.FutureTask.run (FutureTask.java:264)
    at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:539)
    at java.util.concurrent.FutureTask.run (FutureTask.java:264)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1136)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:635)
    at java.lang.Thread.run (Thread.java:840)
Caused by: java.lang.ClassCastException: class org.openrewrite.java.tree.J$FieldAccess cannot be cast to class org.openrewrite.java.tree.J$Identifier (org.openrewrite.java.tree.J$FieldAccess and org.openrewrite.java.tree.J$Identifier are in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @201fd61a)
    at org.openrewrite.java.testing.jmockit.SetupStatementsRewriter.isSetupStatement (SetupStatementsRewriter.java:110)
    at org.openrewrite.java.testing.jmockit.SetupStatementsRewriter.rewriteMethodBody (SetupStatementsRewriter.java:69)
    at org.openrewrite.java.testing.jmockit.JMockitBlockToMockito$RewriteJMockitBlockVisitor.visitMethodDeclaration (JMockitBlockToMockito.java:69)
    at org.openrewrite.java.testing.jmockit.JMockitBlockToMockito$RewriteJMockitBlockVisitor.visitMethodDeclaration (JMockitBlockToMockito.java:59)
    at org.openrewrite.java.tree.J$MethodDeclaration.acceptJava (J.java:3651)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visitAndCast (TreeVisitor.java:320)
    at org.openrewrite.java.JavaVisitor.visitRightPadded (JavaVisitor.java:1367)
    at org.openrewrite.java.JavaVisitor.lambda$visitBlock$4 (JavaVisitor.java:397)
    at org.openrewrite.internal.ListUtils.map (ListUtils.java:177)
    at org.openrewrite.java.JavaVisitor.visitBlock (JavaVisitor.java:396)
    at org.openrewrite.java.JavaIsoVisitor.visitBlock (JavaIsoVisitor.java:88)
    at org.openrewrite.java.JavaIsoVisitor.visitBlock (JavaIsoVisitor.java:30)
    at org.openrewrite.java.tree.J$Block.acceptJava (J.java:838)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visitAndCast (TreeVisitor.java:320)
    at org.openrewrite.java.JavaVisitor.visitClassDeclaration (JavaVisitor.java:482)
    at org.openrewrite.java.JavaIsoVisitor.visitClassDeclaration (JavaIsoVisitor.java:108)
    at org.openrewrite.java.JavaIsoVisitor.visitClassDeclaration (JavaIsoVisitor.java:30)
    at org.openrewrite.java.tree.J$ClassDeclaration.acceptJava (J.java:1278)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visitAndCast (TreeVisitor.java:320)
    at org.openrewrite.java.JavaVisitor.lambda$visitCompilationUnit$9 (JavaVisitor.java:495)
    at org.openrewrite.internal.ListUtils.map (ListUtils.java:177)
    at org.openrewrite.java.JavaVisitor.visitCompilationUnit (JavaVisitor.java:495)
    at org.openrewrite.java.JavaIsoVisitor.visitCompilationUnit (JavaIsoVisitor.java:113)
    at org.openrewrite.java.JavaIsoVisitor.visitCompilationUnit (JavaIsoVisitor.java:30)
    at org.openrewrite.java.tree.J$CompilationUnit.acceptJava (J.java:1549)
    at org.openrewrite.java.tree.J.accept (J.java:59)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:250)
    at org.openrewrite.TreeVisitor.visit (TreeVisitor.java:157)
    at org.openrewrite.Preconditions$Check.visit (Preconditions.java:175)
    at org.openrewrite.Preconditions$Check.visit (Preconditions.java:145)
    at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$6 (RecipeRunCycle.java:186)
    at io.micrometer.core.instrument.AbstractTimer.recordCallable (AbstractTimer.java:178)
    at org.openrewrite.table.RecipeRunStats.recordEdit (RecipeRunStats.java:67)
    at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$7 (RecipeRunCycle.java:182)
    at org.openrewrite.scheduling.RecipeStack.reduce (RecipeStack.java:57)
    at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$8 (RecipeRunCycle.java:155)
    at org.openrewrite.internal.InMemoryLargeSourceSet.lambda$edit$0 (InMemoryLargeSourceSet.java:66)
    at org.openrewrite.internal.ListUtils.map (ListUtils.java:177)
    at org.openrewrite.internal.InMemoryLargeSourceSet.edit (InMemoryLargeSourceSet.java:65)
    at org.openrewrite.scheduling.RecipeRunCycle.editSources (RecipeRunCycle.java:154)
    at org.openrewrite.RecipeScheduler.runRecipeCycles (RecipeScheduler.java:87)
    at org.openrewrite.RecipeScheduler.scheduleRun (RecipeScheduler.java:41)
    at org.openrewrite.Recipe.run (Recipe.java:376)
    at org.openrewrite.Recipe.run (Recipe.java:372)
    at org.openrewrite.Recipe.run (Recipe.java:368)
    at org.openrewrite.maven.AbstractRewriteBaseRunMojo.runRecipe (AbstractRewriteBaseRunMojo.java:243)
    at org.openrewrite.maven.AbstractRewriteBaseRunMojo.listResults (AbstractRewriteBaseRunMojo.java:154)
    at org.openrewrite.maven.AbstractRewriteRunMojo.execute (AbstractRewriteRunMojo.java:64)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:126)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:328)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:316)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:174)
    at org.apache.maven.lifecycle.internal.MojoExecutor.access$000 (MojoExecutor.java:75)
    at org.apache.maven.lifecycle.internal.MojoExecutor$1.run (MojoExecutor.java:162)
    at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute (DefaultMojosExecutionStrategy.java:39)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:159)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:105)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:193)
    at org.apache.maven.lifecycle.internal.builder.multithreaded.MultiThreadedBuilder$1.call (MultiThreadedBuilder.java:180)
    at java.util.concurrent.FutureTask.run (FutureTask.java:264)
    at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java:539)
    at java.util.concurrent.FutureTask.run (FutureTask.java:264)
    at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1136)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:635)
    at java.lang.Thread.run (Thread.java:840)

Are you interested in [contributing a fix to OpenRewrite]

don't know if i'm able

timtebeek commented 1 month ago

Thanks for using the very latest to verify; I think the problem is with the unexpected LoggerProducerTest.this.injectionPoint, but would have to check.

xanaxan commented 1 month ago

Yes, you're right. Can't really understand why someone writes it like that. After i fixed that in all the tests i stumbled upon the next problem. A Method inside the Expectations block:

// EXPECTATIONS
new Expectations() { //replaced StrictExpectations
    {
        EntityResolver.valueOf(entityManager,
                TestFixtures.processingContext1());
        this.result = entityResolver;

        for (int count = PersistenceConfig.JDBC_BATCH_SIZE; 0 < count; count--) {
            this.entityResolver();
            entityManager.persist(this.any);
        }
        entityManager.flush();
        entityManager.clear();
        this.entityResolver();
        entityManager.persist(this.any);
        entityManager.flush();
        entityManager.clear();
    }

    private void entityResolver() {
        entityResolver.enrich(TestFixtures.tenant_Mvb_MbgmClearing());
        this.result = entityResolver;

        entityResolver.retrieveState(this.withAny(DialogState.nullValue()));
        this.result = state;

        entityResolver.retrieveEnumeration(this.withAny(Datum.EINLANGE_DAT));
        this.result = enumeration;
        this.times = 3;

        entityResolver.retrieveEnumeration(this.withAny(Referenz.CLEARING_OBJEKT_TRAEGER_REFERENZ));
        this.result = enumeration;
        this.times = 2;
    }
}

Here the ClassCastException happens because the Recipe expects a J.Block but gets a MethodInvocation w/ 'private void entityResolver()'. I never used JMockit, so i can't tell if that's usual procedure.

Is there any way to have a recipe run through ALL files and just continue with the next file if it fails with one?

shivanisky commented 3 weeks ago

When I've seen these types of errors, unfortunately I just delete the file temporarily and rerun. But, yes, it would be great if the framework could keep running for files if see any exception - maybe a flag if don't want to default this? @sambsnyd @timtebeek fyi

In any case, this is a bug if it is generate the exception. The code is unusual however, and with the private method internal to the block, it doesn't seem to follow the expected structure of a Jmockit Expectations block: https://www.javadoc.io/doc/org.jmockit/jmockit/latest/mockit/Expectations.html

shivanisky commented 2 weeks ago

Was able to replicate it:

`   @Test
    void whenMethodInsideBlock() {
        rewriteRun(
          java(
            """
              import mockit.Expectations;
              import mockit.Mocked;
              import mockit.integration.junit5.JMockitExtension;
              import org.junit.jupiter.api.extension.ExtendWith;

              @ExtendWith(JMockitExtension.class)
              class MyTest {
                  @Mocked
                  Object myObject;

                  void test() {
                      new Expectations() {{

                          }
                          private void test() {
                              myObject.wait(anyLong);
                          }
                      };
                      myObject.wait(1L);
                  }
              }
              """,
            """
              import org.junit.jupiter.api.extension.ExtendWith;
              import org.mockito.Mock;
              import org.mockito.junit.jupiter.MockitoExtension;

              @ExtendWith(MockitoExtension.class)
              class MyTest {
                  @Mock
                  Object myObject;

                  void test() {
                      new Expectations() {{

                          }
                          private void test() {
                              myObject.wait(anyLong);
                          }
                      };
                      myObject.wait(1L);
                  }
              }
              """
          )
        );
    }

Caused by: java.lang.ClassCastException: class org.openrewrite.java.tree.J$MethodDeclaration cannot be cast to class org.openrewrite.java.tree.J$Block (org.openrewrite.java.tree.J$MethodDeclaration and org.openrewrite.java.tree.J$Block are in unnamed module of loader 'app') at org.openrewrite.java.testing.jmockit.SetupStatementsRewriter.rewriteMethodBody(SetupStatementsRewriter.java:68) at org.openrewrite.java.testing.jmockit.JMockitBlockToMockito$RewriteJMockitBlockVisitor.visitMethodDeclaration(JMockitBlockToMockito.java:69) at org.openrewrite.java.testing.jmockit.JMockitBlockToMockito$RewriteJMockitBlockVisitor.visitMethodDeclaration(JMockitBlockToMockito.java:59) at org.openrewrite.java.tree.J$MethodDeclaration.acceptJava(J.java:3651) at org.openrewrite.java.tree.J.accept(J.java:59) at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:250) ... 49 more