From a6fecf80bd1b5792012db891b12bb4cc4f95cd36 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 23 Jul 2026 12:08:40 +0200 Subject: [PATCH 1/4] Fix AddTimeUnitArgument crash on arithmetic argument expressions Rebuilding the entire argument list through a #{any()} JavaTemplate re-parsed the original argument, which misplaced the __TEMPLATE_STOP__ boundary for binary/arithmetic expressions (e.g. 60 * 1000) and produced unparseable Java. Instead, append the TimeUnit argument to the existing argument LST and extend the method type so the original expression is never re-parsed. Fixes #138 --- .../httpclient5/AddTimeUnitArgument.java | 28 +++++++++++++----- .../httpclient5/AddTimeUnitArgumentTest.java | 29 +++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java index ea1cade..2279c9b 100644 --- a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java +++ b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java @@ -22,12 +22,14 @@ import org.openrewrite.Option; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; -import org.openrewrite.internal.StringUtils; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Space; import java.util.ArrayList; import java.util.List; @@ -68,20 +70,32 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu J.MethodInvocation m = super.visitMethodInvocation(method, ctx); if (matcher.matches(m)) { JavaTemplate template = JavaTemplate - .builder(StringUtils.repeat("#{any()}, ", m.getArguments().size()) + "TimeUnit.#{}") + .builder("TimeUnit.#{}") .contextSensitive() .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "httpclient5", "httpcore5")) .imports("java.util.concurrent.TimeUnit") .build(); - List arguments = new ArrayList<>(m.getArguments()); - arguments.add(timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS); - - m = template.apply( + J.MethodInvocation templated = template.apply( updateCursor(m), m.getCoordinates().replaceArguments(), - arguments.toArray(new Object[0]) + timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS ); + Expression timeUnitArgument = templated.getArguments().get(0).withPrefix(Space.SINGLE_SPACE); + + List arguments = new ArrayList<>(m.getArguments()); + arguments.add(timeUnitArgument); + m = m.withArguments(arguments); + + JavaType.Method methodType = m.getMethodType(); + if (methodType != null) { + List parameterTypes = new ArrayList<>(methodType.getParameterTypes()); + parameterTypes.add(timeUnitArgument.getType()); + List parameterNames = new ArrayList<>(methodType.getParameterNames()); + parameterNames.add("timeUnit"); + methodType = methodType.withParameterTypes(parameterTypes).withParameterNames(parameterNames); + m = m.withMethodType(methodType).withName(m.getName().withType(methodType)); + } maybeAddImport("java.util.concurrent.TimeUnit"); } return m; diff --git a/src/test/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgumentTest.java b/src/test/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgumentTest.java index 4931efa..f1c3474 100644 --- a/src/test/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgumentTest.java +++ b/src/test/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgumentTest.java @@ -122,6 +122,35 @@ void test() { ); } + @Test + void arithmeticTimeoutArgument() { + rewriteRun( + spec -> spec.recipe(new AddTimeUnitArgument("A method(int)", null)), + stubCode, + //language=java + java( + """ + class B { + void test() { + A a = new A(); + a.method(60 * 1000); + } + } + """, + """ + import java.util.concurrent.TimeUnit; + + class B { + void test() { + A a = new A(); + a.method(60 * 1000, TimeUnit.MILLISECONDS); + } + } + """ + ) + ); + } + @Test void doesModifyMethodsWithMoreThanOneArgument() { rewriteRun( From 35fe0084cbb72768bbde594f368eab3e069f0f2a Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 23 Jul 2026 12:16:42 +0200 Subject: [PATCH 2/4] Use ListUtils.concat instead of ArrayList copies --- .../apache/httpclient5/AddTimeUnitArgument.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java index 2279c9b..106e658 100644 --- a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java +++ b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java @@ -22,6 +22,7 @@ import org.openrewrite.Option; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; @@ -31,8 +32,6 @@ import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.Space; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; @EqualsAndHashCode(callSuper = false) @@ -82,18 +81,13 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS ); Expression timeUnitArgument = templated.getArguments().get(0).withPrefix(Space.SINGLE_SPACE); - - List arguments = new ArrayList<>(m.getArguments()); - arguments.add(timeUnitArgument); - m = m.withArguments(arguments); + m = m.withArguments(ListUtils.concat(m.getArguments(), timeUnitArgument)); JavaType.Method methodType = m.getMethodType(); if (methodType != null) { - List parameterTypes = new ArrayList<>(methodType.getParameterTypes()); - parameterTypes.add(timeUnitArgument.getType()); - List parameterNames = new ArrayList<>(methodType.getParameterNames()); - parameterNames.add("timeUnit"); - methodType = methodType.withParameterTypes(parameterTypes).withParameterNames(parameterNames); + methodType = methodType + .withParameterTypes(ListUtils.concat(methodType.getParameterTypes(), timeUnitArgument.getType())) + .withParameterNames(ListUtils.concat(methodType.getParameterNames(), "timeUnit")); m = m.withMethodType(methodType).withName(m.getName().withType(methodType)); } maybeAddImport("java.util.concurrent.TimeUnit"); From 0a8240a79ca0fad3de0d564ec181e32bee701bed Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 23 Jul 2026 12:20:41 +0200 Subject: [PATCH 3/4] Drop contextSensitive and inline the JavaTemplate --- .../apache/httpclient5/AddTimeUnitArgument.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java index 106e658..6f5fe27 100644 --- a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java +++ b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java @@ -68,18 +68,16 @@ public TreeVisitor getVisitor() { public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation m = super.visitMethodInvocation(method, ctx); if (matcher.matches(m)) { - JavaTemplate template = JavaTemplate + J.MethodInvocation templated = JavaTemplate .builder("TimeUnit.#{}") - .contextSensitive() .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "httpclient5", "httpcore5")) .imports("java.util.concurrent.TimeUnit") - .build(); - - J.MethodInvocation templated = template.apply( - updateCursor(m), - m.getCoordinates().replaceArguments(), - timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS - ); + .build() + .apply( + updateCursor(m), + m.getCoordinates().replaceArguments(), + timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS + ); Expression timeUnitArgument = templated.getArguments().get(0).withPrefix(Space.SINGLE_SPACE); m = m.withArguments(ListUtils.concat(m.getArguments(), timeUnitArgument)); From f401caf866b7395ece10fe380e9118b05257e06a Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 23 Jul 2026 12:26:38 +0200 Subject: [PATCH 4/4] Drop httpclient5 JavaParser classpath; template only needs JDK TimeUnit --- .../org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java index 6f5fe27..cc636af 100644 --- a/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java +++ b/src/main/java/org/openrewrite/apache/httpclient5/AddTimeUnitArgument.java @@ -24,7 +24,6 @@ import org.openrewrite.TreeVisitor; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; @@ -70,7 +69,6 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu if (matcher.matches(m)) { J.MethodInvocation templated = JavaTemplate .builder("TimeUnit.#{}") - .javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "httpclient5", "httpcore5")) .imports("java.util.concurrent.TimeUnit") .build() .apply(