Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright 2025 the original author or authors.
* <p>
* 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
* <p>
* https://docs.moderne.io/licensing/moderne-source-available-license
* <p>
* 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.jspecify.annotations.Nullable;
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.search.UsesType;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeUtils;

import java.util.List;

import static java.util.Objects.requireNonNull;

public class LoggerLevelArgumentToMethod extends Recipe {
private static final MethodMatcher LOG_MATCHER = new MethodMatcher("org.jboss.logging.Logger log(*,*,..)", true);
private static final MethodMatcher LOGF_MATCHER = new MethodMatcher("org.jboss.logging.Logger logf(*,*,..)", true);
private static final MethodMatcher LOGV_MATCHER = new MethodMatcher("org.jboss.logging.Logger logv(*,*,..)", true);

@Override
public String getDisplayName() {
return "Replace JBoss Logging Level arguments with the corresponding eponymous level method calls";
}

@Override
public String getDescription() {
return "Replace calls to `Logger.log(Level, ...)` with the corresponding eponymous level method calls. For example `Logger.log(Level.INFO, ...)` to `Logger.info(...)`.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
TreeVisitor<?, ExecutionContext> preconditions = Preconditions.and(
new UsesType<>("org.jboss.logging.Logger", true),
new UsesType<>("org.jboss.logging.Logger.Level", true),
Preconditions.or(
new UsesMethod<>(LOG_MATCHER),
new UsesMethod<>(LOGF_MATCHER),
new UsesMethod<>(LOGV_MATCHER)
)
);
return Preconditions.check(preconditions, new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation mi, ExecutionContext ctx) {
J.MethodInvocation m = super.visitMethodInvocation(mi, ctx);
if (!(LOG_MATCHER.matches(m) || LOGF_MATCHER.matches(m) || LOGV_MATCHER.matches(m))) {
return m;
}
List<Expression> args = m.getArguments();
Expression firstArgument = args.get(0);
Expression secondArgument = args.get(1);

String logLevelName;
List<Expression> updatedArguments;
if (TypeUtils.isAssignableTo("org.jboss.logging.Logger.Level", firstArgument.getType())) {
String suffix = "";
if (LOGF_MATCHER.matches(m)) {
suffix = "f";
} else if (LOGV_MATCHER.matches(m)) {
suffix = "v";
}
logLevelName = extractLogLevelName(firstArgument);
if (logLevelName != null) {
logLevelName += suffix;
}
updatedArguments = ListUtils.concat(
(Expression) secondArgument.withPrefix(secondArgument.getPrefix()
.withWhitespace(firstArgument.getPrefix().getWhitespace())),
args.subList(2, args.size()));
} else if (TypeUtils.isAssignableTo("java.lang.String", firstArgument.getType()) &&
TypeUtils.isAssignableTo("org.jboss.logging.Logger.Level", secondArgument.getType()) &&
LOG_MATCHER.matches(m)) { // `logf(String, ..)` and `logv(String, ..)` don't have a logger.level() equivalent
logLevelName = extractLogLevelName(secondArgument);
updatedArguments = ListUtils.filter(args, it -> it != secondArgument);
} else {
return m;
}

// If we can't extract a log level name, we don't change the method call
if (logLevelName == null) {
return m;
}

JavaType.Method updatedMethodType = requireNonNull(m.getMethodType())
.withParameterTypes(ListUtils.filter(m.getMethodType().getParameterTypes(), it -> !TypeUtils.isAssignableTo("org.jboss.logging.Logger.Level", it)))
.withParameterNames(ListUtils.filter(m.getMethodType().getParameterNames(), it -> !"level".equals(it)))
.withName(logLevelName.toLowerCase());

return m
.withArguments(updatedArguments)
.withMethodType(updatedMethodType)
.withName(m.getName().withSimpleName(logLevelName.toLowerCase()));
}

@Nullable
String extractLogLevelName(Expression expression) {
if (expression instanceof J.Identifier) {
J.Identifier identifier = (J.Identifier) expression;
if (identifier.getFieldType() != null &&
identifier.getFieldType().getOwner() instanceof JavaType.Class) {
return identifier.getSimpleName();
}
} else if (expression instanceof J.FieldAccess) {
return ((J.FieldAccess) expression).getSimpleName();
}
return null;
}
}
);
}
}
21 changes: 21 additions & 0 deletions src/main/java/org/openrewrite/java/logging/jboss/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* 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
* <p>
* https://docs.moderne.io/licensing/moderne-source-available-license
* <p>
* 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.
*/
@NullMarked
@NonNullFields
package org.openrewrite.java.logging.jboss;

import org.jspecify.annotations.NullMarked;
import org.openrewrite.internal.lang.NonNullFields;
23 changes: 23 additions & 0 deletions src/main/resources/META-INF/rewrite/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,29 @@ examples:
language: java
---
type: specs.openrewrite.org/v1beta/example
recipeName: org.openrewrite.java.logging.jboss.LoggerLevelArgumentToMethod
examples:
- description: ''
sources:
- before: |
import org.jboss.logging.Logger;

class Test {
void test(Logger logger, String msg) {
logger.log(Logger.Level.INFO, msg);
}
}
after: |
import org.jboss.logging.Logger;

class Test {
void test(Logger logger, String msg) {
logger.info(msg);
}
}
language: java
---
type: specs.openrewrite.org/v1beta/example
recipeName: org.openrewrite.java.logging.jul.LoggerLevelArgumentToMethodRecipes
examples:
- description: ''
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/META-INF/rewrite/jboss.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ tags:
- logging
- jboss
recipeList:
- org.openrewrite.java.logging.jboss.LoggerLevelArgumentToMethod
- org.openrewrite.java.logging.jboss.FormattedArgumentsToVMethodRecipes
- org.openrewrite.java.logging.ArgumentArrayToVarargs
Loading