diff --git a/src/main/java/org/openrewrite/java/logging/ArgumentArrayToVarargs.java b/src/main/java/org/openrewrite/java/logging/ArgumentArrayToVarargs.java new file mode 100644 index 00000000..229578b5 --- /dev/null +++ b/src/main/java/org/openrewrite/java/logging/ArgumentArrayToVarargs.java @@ -0,0 +1,81 @@ +/* + * Copyright 2025 the original author or authors. + *
+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * https://docs.moderne.io/licensing/moderne-source-available-license + *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.logging;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.MethodMatcher;
+import org.openrewrite.java.search.UsesMethod;
+import org.openrewrite.java.tree.*;
+
+import java.time.Duration;
+import java.util.List;
+
+public class ArgumentArrayToVarargs extends Recipe {
+ // Match logger methods that end with Object[] - but we'll verify if it's varargs later
+ private static final MethodMatcher LOGGER_METHOD = new MethodMatcher("*..*Log* *(.., Object[])");
+
+ @Override
+ public String getDisplayName() {
+ return "Unpack Logger method `new Object[] {...}` into varargs";
+ }
+
+ @Override
+ public String getDescription() {
+ return "For Logger methods that support varargs, convert any final explicit `Object[]` arguments into their unpacked values.";
+ }
+
+ @Override
+ public Duration getEstimatedEffortPerOccurrence() {
+ return Duration.ofMinutes(2);
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(new UsesMethod<>(LOGGER_METHOD), new JavaIsoVisitor
+# Licensed under the Moderne Source Available License (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://docs.moderne.io/licensing/moderne-source-available-license
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+---
+type: specs.openrewrite.org/v1beta/recipe
+name: org.openrewrite.java.logging.jboss.JBossLoggingBestPractices
+displayName: JBoss Logging Best Practices
+description: |-
+ This recipe applies best practices for logging in JBoss applications.
+ It includes converting argument arrays to varargs for better readability and performance.
+tags:
+ - logging
+ - jboss
+recipeList:
+ - org.openrewrite.java.logging.jboss.FormattedArgumentsToVMethodRecipes
+ - org.openrewrite.java.logging.ArgumentArrayToVarargs
diff --git a/src/main/resources/META-INF/rewrite/slf4j.yml b/src/main/resources/META-INF/rewrite/slf4j.yml
index 86907ff2..8f5ca64d 100644
--- a/src/main/resources/META-INF/rewrite/slf4j.yml
+++ b/src/main/resources/META-INF/rewrite/slf4j.yml
@@ -138,6 +138,7 @@ tags:
- logging
- slf4j
recipeList:
+ - org.openrewrite.java.logging.ArgumentArrayToVarargs
- org.openrewrite.java.logging.slf4j.LoggersNamedForEnclosingClass
- org.openrewrite.java.logging.slf4j.Slf4jLogShouldBeConstant
- org.openrewrite.java.logging.slf4j.ParameterizedLogging
diff --git a/src/test/java/org/openrewrite/java/logging/ArgumentArrayToVarargsTest.java b/src/test/java/org/openrewrite/java/logging/ArgumentArrayToVarargsTest.java
new file mode 100644
index 00000000..eed88448
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/logging/ArgumentArrayToVarargsTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.logging;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.InMemoryExecutionContext;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+@SuppressWarnings("RedundantArrayCreation")
+class ArgumentArrayToVarargsTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new ArgumentArrayToVarargs())
+ .parser(JavaParser.fromJavaVersion()
+ .classpathFromResources(new InMemoryExecutionContext(), "slf4j-api-2.1.+"));
+ }
+
+ @DocumentExample
+ @Test
+ void objectArrayToVarargs() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.info("Message {} {} {}", new Object[]{"old", "style", "args"});
+ }
+ }
+ """,
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.info("Message {} {} {}", "old", "style", "args");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void emptyObjectArray() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.info("Message without placeholders", new Object[]{});
+ }
+ }
+ """,
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.info("Message without placeholders");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void singleElementArray() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.warn("Single placeholder: {}", new Object[]{"value"});
+ }
+ }
+ """,
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.warn("Single placeholder: {}", "value");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @SuppressWarnings("ConfusingArgumentToVarargsMethod")
+ @Test
+ void nonObjectArrayNotConverted() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.info("Message {}", new String[]{"test"});
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void notLastArgumentNotConverted() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ logger.info("Message {} {}", new Object[]{"test"}, "other");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void variableArrayNotConverted() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.slf4j.Logger;
+ class Test {
+ Logger logger;
+ void method() {
+ Object[] args = {"old", "style", "args"};
+ logger.info("Message {} {} {}", args);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void notVarargsMethodParameterTypeNotConverted() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import java.util.logging.Level;
+ import java.util.logging.Logger;
+ class Test {
+ Logger logger;
+ void method(Level level, String msg, Object o) {
+ logger.log(level, msg, new Object[]{o});
+ }
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/src/test/java/org/openrewrite/java/logging/jboss/JBossLoggingBestPracticesTest.java b/src/test/java/org/openrewrite/java/logging/jboss/JBossLoggingBestPracticesTest.java
new file mode 100644
index 00000000..b74710e4
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/logging/jboss/JBossLoggingBestPracticesTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.logging.jboss;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class JBossLoggingBestPracticesTest implements RewriteTest {
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipeFromResource(
+ "/META-INF/rewrite/jboss.yml",
+ "org.openrewrite.java.logging.jboss.JBossLoggingBestPractices"
+ );
+ }
+
+ @DocumentExample
+ @Test
+ void convertInfo() {
+ rewriteRun(
+ //language=java
+ java(
+ """
+ import org.jboss.logging.Logger;
+
+ class Test {
+ void test(Logger logger, String msg, Object o) {
+ logger.info(msg, new Object[]{o});
+ }
+ }
+ """,
+ """
+ import org.jboss.logging.Logger;
+
+ class Test {
+ void test(Logger logger, String msg, Object o) {
+ logger.infov(msg, o);
+ }
+ }
+ """
+ )
+ );
+ }
+}