rewrite-spring icon indicating copy to clipboard operation
rewrite-spring copied to clipboard

Add migration tests and recipes for Spring Batch

Open qwtfps opened this issue 10 months ago • 4 comments

What's changed?

Add corresponding migration recipes:

  • JobParameterToString: Migrate JobParameter.toString() to JobParameter.getValue().toString().
  • MigrateMethodAnnotatedByBatchAPI: Update methods annotated by Spring Batch API.
  • MigrateJobParameter: Ensure job parameters are parameterized.
  • ConvertReceiveTypeWhenCallStepExecutionMethod: Convert receive types in StepExecution method calls.

What's your motivation?

Anything in particular you'd like reviewers to focus on?

Anyone you would like to review specifically?

Have you considered any alternatives or workarounds?

Any additional context

Checklist

  • [x] I've added unit tests to cover both positive and negative cases
  • [x] I've read and applied the recipe conventions and best practices
  • [x] I've used the IntelliJ IDEA auto-formatter on affected files

qwtfps avatar Mar 12 '25 10:03 qwtfps

hi @timtebeek , do you know why ci build failed ? I can build in my local with the latest commit. I check the log , most likely it is not relevant to the new recipe.

qwtfps avatar Mar 18 '25 02:03 qwtfps

It looks like this test failed in a way I hadn't see before 🤔

MigrateJobParameterTest > test1() FAILED
    java.io.UncheckedIOException: java.io.IOException: Failed to create directory /home/runner/.rewrite/classpath/.tt/org/springframework/batch/spring-batch-core
        at org.openrewrite.java.internal.parser.TypeTable$Reader.lambda$writeClassesDir$4(TypeTable.java:247)
        at org.openrewrite.java.internal.parser.TypeTable$Reader$$Lambda$483/0x00007fdfac17b4c8.accept(Unknown Source)
        at java.base/java.util.HashMap$Values.forEach(HashMap.java:1065)
        at org.openrewrite.java.internal.parser.TypeTable$Reader.writeClassesDir(TypeTable.java:244)
        at org.openrewrite.java.internal.parser.TypeTable$Reader.lambda$read$3(TypeTable.java:185)
        at org.openrewrite.java.internal.parser.TypeTable$Reader$$Lambda$480/0x00007fdfac17a098.accept(Unknown Source)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
        at java.base/java.util.stream.SliceOps$1$1.accept(SliceOps.java:200)
        at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
        at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
        at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
        at org.openrewrite.java.internal.parser.TypeTable$Reader.read(TypeTable.java:180)
        at org.openrewrite.java.internal.parser.TypeTable.read(TypeTable.java:123)
        at org.openrewrite.java.internal.parser.TypeTable.<init>(TypeTable.java:111)
        at org.openrewrite.java.internal.parser.TypeTable.fromClasspath(TypeTable.java:97)
        at org.openrewrite.java.JavaParser.dependenciesFromResources(JavaParser.java:128)
        at org.openrewrite.java.JavaParser$Builder.classpathFromResources(JavaParser.java:324)
        at org.openrewrite.java.spring.batch.MigrateJobParameterTest.defaults(MigrateJobParameterTest.java:32)
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:138)
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
        at org.openrewrite.java.spring.batch.MigrateJobParameterTest.test1(MigrateJobParameterTest.java:40)

        Caused by:
        java.io.IOException: Failed to create directory /home/runner/.rewrite/classpath/.tt/org/springframework/batch/spring-batch-core
            at org.openrewrite.java.internal.parser.TypeTable$Reader.lambda$writeClassesDir$4(TypeTable.java:247)
            ... 25 more

timtebeek avatar Mar 18 '25 08:03 timtebeek

@timtebeek How to try rerun the CI. I push the fix commit.

qwtfps avatar Mar 26 '25 02:03 qwtfps

Thanks! I've triggered the CI builds again; that should only be an issue for your first contribution; after that they should start automatically.

timtebeek avatar Mar 26 '25 09:03 timtebeek

Thanks @timtebeek . I saw your commit which helped me refine the code. I check the CI log info summary is below. I think it was irrelevant to this PR . Is it helpful if i sync the code with master ?

208 tests completed, 2 failed, 1 skipped

Detail

MigrateResponseStatusExceptionTest > migrateResponseStatusExceptionGetRawStatusCodeMethod() FAILED
    java.lang.AssertionError: [Recipe validation must have no failures] 
    Expecting empty but was: [[Invalid{property='initialization', value='[]', message='DeclarativeRecipe must not contain uninitialized recipes. Be sure to call .initialize() on DeclarativeRecipe.'},
        Invalid{property='org.openrewrite.java.spring.framework.MigrateResponseStatusException.recipeList[0] (in file:///home/runner/work/rewrite-spring/rewrite-spring/build/resources/main/META-INF/rewrite/spring-framework-60.yml)', value='org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetRawStatusCodeMethod', message='recipe 'org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetRawStatusCodeMethod' does not exist.'},
        Invalid{property='org.openrewrite.java.spring.framework.MigrateResponseStatusException.recipeList[1] (in file:///home/runner/work/rewrite-spring/rewrite-spring/build/resources/main/META-INF/rewrite/spring-framework-60.yml)', value='org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetStatusCodeMethod', message='recipe 'org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetStatusCodeMethod' does not exist.'}]]
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:222)
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:125)
        at org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionTest.migrateResponseStatusExceptionGetRawStatusCodeMethod(MigrateResponseStatusExceptionTest.java:91)

MigrateResponseStatusExceptionTest > migrateResponseStatusExceptionGetStatusMethod() FAILED
    java.lang.AssertionError: [Recipe validation must have no failures] 
    Expecting empty but was: [[Invalid{property='initialization', value='[]', message='DeclarativeRecipe must not contain uninitialized recipes. Be sure to call .initialize() on DeclarativeRecipe.'},
        Invalid{property='org.openrewrite.java.spring.framework.MigrateResponseStatusException.recipeList[0] (in file:///home/runner/work/rewrite-spring/rewrite-spring/build/resources/main/META-INF/rewrite/spring-framework-60.yml)', value='org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetRawStatusCodeMethod', message='recipe 'org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetRawStatusCodeMethod' does not exist.'},
        Invalid{property='org.openrewrite.java.spring.framework.MigrateResponseStatusException.recipeList[1] (in file:///home/runner/work/rewrite-spring/rewrite-spring/build/resources/main/META-INF/rewrite/spring-framework-60.yml)', value='org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetStatusCodeMethod', message='recipe 'org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionGetStatusCodeMethod' does not exist.'}]]
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:222)
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
        at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:125)
        at org.openrewrite.java.spring.framework.MigrateResponseStatusExceptionTest.migrateResponseStatusExceptionGetStatusMethod(MigrateResponseStatusExceptionTest.java:61)

qwtfps avatar Apr 02 '25 02:04 qwtfps

Thanks for the ping @qwtfps ! I was out for a few days, but trying to catch up now. The latest failures now are:

MigrateJobParameterTest > addStringClassArguments() FAILED
    org.opentest4j.AssertionFailedError: [Expected recipe to complete in 1 cycle, but took at least one more cycle. Between the last two executed cycles there were changes to "test/PointsReconFileWriterTest.java"] 
    expected: 
      "package test;
      import org.springframework.batch.core.JobParameter;
      import org.springframework.batch.core.JobParameters;
      import java.util.Date;
      import java.util.Map;
      import java.util.HashMap;
      import java.util.UUID;
      public class PointsReconFileWriterTest {
  
          @Test
          public void shouldUpdateMemberStatusWhenDecisionCodeIsA() throws Exception {
              String from = UUID.randomUUID().toString();
              Map<String,JobParameter<?>> parameters = new HashMap<>();
              parameters.put("sellerId", new JobParameter<>(from, String.class));
              parameters.put("smtpHost", new JobParameter<>("localhost", String.class));
  
              JobParameters jobParameters = new JobParameters(parameters);
          }
  
      }"
     but was: 
      "package test;
      import org.springframework.batch.core.JobParameter;
      import org.springframework.batch.core.JobParameters;
      import java.util.Date;
      import java.util.Map;
      import java.util.HashMap;
      import java.util.UUID;
      public class PointsReconFileWriterTest {
  
          @Test
          public void shouldUpdateMemberStatusWhenDecisionCodeIsA() throws Exception {
              String from = UUID.randomUUID().toString();
              Map<String,JobParameter<?>> parameters = new HashMap<>();
              parameters.put("sellerId", new JobParameter<>(from, String.class));
              parameters.put("smtpHost", new JobParameter<>("localhost", String.class, String.class));
  
              JobParameters jobParameters = new JobParameters(parameters);
          }
  
      }"
        at app//org.openrewrite.test.LargeSourceSetCheckingExpectedCycles.afterCycle(LargeSourceSetCheckingExpectedCycles.java:97)
        at app//org.openrewrite.RecipeScheduler.runRecipeCycles(RecipeScheduler.java:98)
        at app//org.openrewrite.RecipeScheduler.scheduleRun(RecipeScheduler.java:41)
        at app//org.openrewrite.Recipe.run(Recipe.java:438)
        at app//org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:377)
        at app//org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
        at app//org.openrewrite.java.spring.batch.MigrateJobParameterTest.addStringClassArguments(MigrateJobParameterTest.java:90)

MigrateJobParameterTest > test3() FAILED
    org.opentest4j.AssertionFailedError: [Expected recipe to complete in 1 cycle, but took at least one more cycle. Between the last two executed cycles there were changes to "test/PointsReconFileWriterTest.java"] 
    expected: 
      "package test;
      import org.springframework.batch.core.JobParameter;
      import org.springframework.batch.core.JobParameters;
      import java.util.Date;
      import java.util.HashMap;
      import java.util.Map;
      import java.util.UUID;
      public class PointsReconFileWriterTest {
  
          @Test
          public void shouldUpdateMemberStatusWhenDecisionCodeIsA() throws Exception {
              final Map<String,JobParameter<?>> paramMap = new HashMap<>() {{
                          put("Target", new JobParameter<>("JOB_NAME", String.class));
              }};
          }
  
      }"
     but was: 
      "package test;
      import org.springframework.batch.core.JobParameter;
      import org.springframework.batch.core.JobParameters;
      import java.util.Date;
      import java.util.HashMap;
      import java.util.Map;
      import java.util.UUID;
      public class PointsReconFileWriterTest {
  
          @Test
          public void shouldUpdateMemberStatusWhenDecisionCodeIsA() throws Exception {
              final Map<String,JobParameter<?>> paramMap = new HashMap<>() {{
                          put("Target", new JobParameter<>("JOB_NAME", String.class, String.class));
              }};
          }
  
      }"
        at app//org.openrewrite.test.LargeSourceSetCheckingExpectedCycles.afterCycle(LargeSourceSetCheckingExpectedCycles.java:97)
        at app//org.openrewrite.RecipeScheduler.runRecipeCycles(RecipeScheduler.java:98)
        at app//org.openrewrite.RecipeScheduler.scheduleRun(RecipeScheduler.java:41)
        at app//org.openrewrite.Recipe.run(Recipe.java:438)
        at app//org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:377)
        at app//org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
        at app//org.openrewrite.java.spring.batch.MigrateJobParameterTest.test3(MigrateJobParameterTest.java:144)

MigrateJobParameterTest > addClassArguments() FAILED
    org.opentest4j.AssertionFailedError: [Expected recipe to complete in 1 cycle, but took at least one more cycle. Between the last two executed cycles there were changes to "test/PointsReconFileWriterTest.java"] 
    expected: 
      "package test;
      import org.springframework.batch.core.JobParameter;
      import org.springframework.batch.core.JobParameters;
      import java.util.Date;
      import java.util.Map;
  
      public class PointsReconFileWriterTest {
  
          @Test
          public void shouldUpdateMemberStatusWhenDecisionCodeIsA() throws Exception {
              JobParameters jobParameters = new JobParameters(Map.of(
                      "inputFile", new JobParameter<>("TEST_INPUT_FILE", String.class),
                      "emailId", new JobParameter<>(new Date(), Date.class),
                      "pgpKey", new JobParameter<>(new Integer[]{1}, java.lang.Integer[].class)
              ));
          }
  
      }"
     but was: 
      "package test;
      import org.springframework.batch.core.JobParameter;
      import org.springframework.batch.core.JobParameters;
      import java.util.Date;
      import java.util.Map;
  
      public class PointsReconFileWriterTest {
  
          @Test
          public void shouldUpdateMemberStatusWhenDecisionCodeIsA() throws Exception {
              JobParameters jobParameters = new JobParameters(Map.of(
                      "inputFile", new JobParameter<>("TEST_INPUT_FILE", String.class, String.class),
                      "emailId", new JobParameter<>(new Date(), Date.class),
                      "pgpKey", new JobParameter<>(new Integer[]{1}, java.lang.Integer[].class, java.lang.Integer[].class)
              ));
          }
  
      }"
        at app//org.openrewrite.test.LargeSourceSetCheckingExpectedCycles.afterCycle(LargeSourceSetCheckingExpectedCycles.java:97)
        at app//org.openrewrite.RecipeScheduler.runRecipeCycles(RecipeScheduler.java:98)
        at app//org.openrewrite.RecipeScheduler.scheduleRun(RecipeScheduler.java:41)
        at app//org.openrewrite.Recipe.run(Recipe.java:438)
        at app//org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:377)
        at app//org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
        at app//org.openrewrite.java.spring.batch.MigrateJobParameterTest.addClassArguments(MigrateJobParameterTest.java:40)

timtebeek avatar Apr 04 '25 19:04 timtebeek

FYI, a follow-up has been merged: #703. I thought you might be interested.

greg-at-moderne avatar Apr 25 '25 13:04 greg-at-moderne