Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use Lombok Log Annotations #644

Merged
merged 16 commits into from
Jan 5, 2025
Merged
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@ dependencies {
testRuntimeOnly("com.fasterxml.jackson.core:jackson-databind")
testRuntimeOnly("com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider")
testRuntimeOnly("com.fasterxml.jackson.module:jackson-module-jaxb-annotations")
testRuntimeOnly("commons-logging:commons-logging:1.3.2")
testRuntimeOnly("org.apache.logging.log4j:log4j-api:2.23.1")
testRuntimeOnly("org.apache.johnzon:johnzon-core:1.2.18")
testRuntimeOnly("org.codehaus.groovy:groovy:latest.release")
testRuntimeOnly("org.jboss.logging:jboss-logging:3.6.0.Final")
testRuntimeOnly("jakarta.annotation:jakarta.annotation-api:2.1.1")
testRuntimeOnly("org.springframework:spring-core:6.1.13")
testRuntimeOnly("com.google.code.findbugs:jsr305:3.0.2")
Expand Down
106 changes: 106 additions & 0 deletions src/main/java/org/openrewrite/java/migrate/lombok/log/LogVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright 2021 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
* <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.migrate.lombok.log;

import lombok.EqualsAndHashCode;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.java.*;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.TypeUtils;

import static java.util.Comparator.comparing;

@EqualsAndHashCode(callSuper = false)
class LogVisitor extends JavaIsoVisitor<ExecutionContext> {

private final String logType;
private final String factoryType;
private final MethodMatcher factoryMethodMatcher;
private final String logAnnotation;
@Nullable
private final String fieldName;

LogVisitor(String logType, String factoryMethodPattern, String logAnnotation, @Nullable String fieldName) {
this.logType = logType;
this.factoryType = factoryMethodPattern.substring(0, factoryMethodPattern.indexOf(' '));
this.factoryMethodMatcher = new MethodMatcher(factoryMethodPattern);
this.logAnnotation = logAnnotation;
this.fieldName = fieldName;
}

@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
J.ClassDeclaration visitClassDeclaration = super.visitClassDeclaration(classDecl, ctx);
if (visitClassDeclaration != classDecl) {
maybeRemoveImport(logType);
maybeRemoveImport(factoryType);
maybeAddImport(logAnnotation);
return JavaTemplate
.builder("@" + logAnnotation.substring(logAnnotation.lastIndexOf('.') + 1) + "\n")
.javaParser(JavaParser.fromJavaVersion().classpath("lombok"))
.imports(logAnnotation)
.build()
.apply(
updateCursor(visitClassDeclaration),
visitClassDeclaration.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)));
}
return classDecl;
}

@Override
public J.@Nullable VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) {
if (!multiVariable.hasModifier(J.Modifier.Type.Private) ||
!multiVariable.hasModifier(J.Modifier.Type.Static) ||
!multiVariable.hasModifier(J.Modifier.Type.Final) ||
multiVariable.getVariables().size() != 1 ||
!TypeUtils.isAssignableTo(logType, multiVariable.getType())) {
return multiVariable;
}

// name needs to match the name of the field that lombok creates
J.VariableDeclarations.NamedVariable var = multiVariable.getVariables().get(0);
if (fieldName != null && !fieldName.equals(var.getSimpleName())) {
return multiVariable;
}

if (!factoryMethodMatcher.matches(var.getInitializer())) {
return multiVariable;
}

J.ClassDeclaration classDeclaration = getCursor().firstEnclosing(J.ClassDeclaration.class);
if (classDeclaration == null || classDeclaration.getType() == null) {
return multiVariable;
}

J.MethodInvocation methodCall = (J.MethodInvocation) var.getInitializer();
if (methodCall.getArguments().size() != 1 ||
!getFactoryParameter(classDeclaration.getSimpleName())
.equals(methodCall.getArguments().get(0).toString())) {
return multiVariable;
}

if (!"log".equals(var.getSimpleName())) {
doAfterVisit(new ChangeFieldName<>(classDeclaration.getType().getFullyQualifiedName(), var.getSimpleName(), "log"));
}

return null;
}

protected String getFactoryParameter(String className) {
return className + ".class";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
* <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.migrate.lombok.log;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.TreeVisitor;

@Value
@EqualsAndHashCode(callSuper = false)
public class UseCommonsLog extends UseLogRecipeTemplate {

@Override
public String getDisplayName() {
return getDisplayName("@CommonsLog");
}

@Override
public String getDescription() {
return getDescription("@CommonsLog", "org.apache.commons.logging.Log");
}

@Option(displayName = "Name of the log field",
description = FIELD_NAME_DESCRIPTION,
example = "LOGGER",
required = false)
@Nullable
String fieldName;

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new LogVisitor(
"org.apache.commons.logging.Log",
"org.apache.commons.logging.LogFactory getLog(..)",
"lombok.extern.apachecommons.CommonsLog",
fieldName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
* <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.migrate.lombok.log;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.TreeVisitor;

@Value
@EqualsAndHashCode(callSuper = false)
public class UseJBossLog extends UseLogRecipeTemplate {

@Override
public String getDisplayName() {
return getDisplayName("@JBossLog");
}

@Override
public String getDescription() {
return getDescription("@JBossLog", "org.jboss.logging.Logger");
}

@Option(displayName = "Name of the log field",
description = FIELD_NAME_DESCRIPTION,
example = "LOGGER",
required = false)
@Nullable
String fieldName;

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new LogVisitor(
"org.jboss.logging.Logger",
"org.jboss.logging.Logger getLogger(..)",
"lombok.extern.jbosslog.JBossLog",
fieldName);
}

}
60 changes: 60 additions & 0 deletions src/main/java/org/openrewrite/java/migrate/lombok/log/UseLog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
* <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.migrate.lombok.log;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.TreeVisitor;

@Value
@EqualsAndHashCode(callSuper = false)
public class UseLog extends UseLogRecipeTemplate {

@Override
public String getDisplayName() {
return getDisplayName("@Log");
}

@Override
public String getDescription() {
return getDescription("@Log", "java.util.logging.Logger");
}

@Option(displayName = "Name of the log field",
description = FIELD_NAME_DESCRIPTION,
example = "LOGGER",
required = false)
@Nullable
String fieldName;

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new LogVisitor(
"java.util.logging.Logger",
"java.util.logging.Logger getLogger(String)",
"lombok.extern.java.Log",
fieldName) {

@Override
protected String getFactoryParameter(String className) {
return className + ".class.getName()";
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
* <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.migrate.lombok.log;

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.TreeVisitor;

@Value
@EqualsAndHashCode(callSuper = false)
public class UseLog4j2 extends UseLogRecipeTemplate {

@Override
public String getDisplayName() {
return getDisplayName("@Log4j2");
}

@Override
public String getDescription() {
return getDescription("@Log4j2", "org.apache.logging.log4j.Logger");
}

@Option(displayName = "Name of the log field",
description = FIELD_NAME_DESCRIPTION,
example = "LOGGER",
required = false)
@Nullable
String fieldName;

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new LogVisitor(
"org.apache.logging.log4j.Logger",
"org.apache.logging.log4j.LogManager getLogger(..)",
"lombok.extern.log4j.Log4j2",
fieldName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
* <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.migrate.lombok.log;

import org.openrewrite.Recipe;

abstract class UseLogRecipeTemplate extends Recipe {

protected static final String FIELD_NAME_DESCRIPTION = "Name of the log field to replace. " +
"If not specified, the field name is not checked and any field that satisfies the other checks is converted.";

protected String getDisplayName(String annotation) {
return String.format("Use `%s` instead of explicit fields", annotation);
}

protected String getDescription(String annotation, String pathToLogger) {
//language=markdown
return String.format("Prefer the lombok annotation `%s` over explicitly written out `%s` fields.", annotation, pathToLogger);
}

}
Loading
Loading