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

Replace Guava Optional with JDK Optional #202

Merged
merged 15 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .sdkmanrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=11.0.16-tem
java=11.0.18-tem
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies {

testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
testImplementation("org.junit-pioneer:junit-pioneer:2.0.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:latest.release")

testImplementation("org.openrewrite:rewrite-test")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2023 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.guava;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.search.UsesMethod;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.J;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class PreferJavaUtilOptionalOrElseNull extends Recipe {
@Override
public String getDisplayName() {
return "Prefer `java.util.Optional#orElse(null)` over `com.google.common.base.Optional#orNull()`";
}

@Override
public String getDescription() {
return "Replaces `com.google.common.base.Optional#orNull()` with `java.util.Optional#orElse(null)`.";
}

@Override
public Duration getEstimatedEffortPerOccurrence() {
return Duration.ofMinutes(5);
}

@Override
public Set<String> getTags() {
return new HashSet<>(Arrays.asList("RSPEC-4738", "guava"));
}

@Override
protected UsesType<ExecutionContext> getApplicableTest() {
return new UsesType<>("com.google.common.base.Optional");
}

@Override
protected UsesMethod<ExecutionContext> getSingleSourceApplicableTest() {
return new UsesMethod<>("com.google.common.base.Optional orNull()");
}

@Override
protected JavaIsoVisitor<ExecutionContext> getVisitor() {
return new PreferJavaUtilOptionalOrElseNullVisitor();
}

private static class PreferJavaUtilOptionalOrElseNullVisitor extends JavaIsoVisitor<ExecutionContext> {
private static final MethodMatcher guavaCreateTempDirMatcher = new MethodMatcher("com.google.common.base.Optional orNull()");
timtebeek marked this conversation as resolved.
Show resolved Hide resolved

@Override
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext executionContext) {
J.CompilationUnit c = super.visitCompilationUnit(cu, executionContext);
maybeAddImport("java.util.Optional");
maybeRemoveImport("com.google.common.base.Optional");
return c;
}

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
J.MethodInvocation mi = super.visitMethodInvocation(method, executionContext);
if (guavaCreateTempDirMatcher.matches(mi)) {
return mi.withName(mi.getName().withSimpleName("orElse"))
.withTemplate(JavaTemplate.builder(this::getCursor, "null").build(), mi.getCoordinates().replaceArguments());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this is actually the problem of the ChangeType recipe (I will investigate this further, when I find time), but as you can see in the following screenshot from the debugger, the type attribution of the optional parameter refers to the correct new type, but as its owner still refers to the old JavaType.Method object:
image

}
return mi;
}
}
}
29 changes: 29 additions & 0 deletions src/main/resources/META-INF/rewrite/no-guava.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ recipeList:
- org.openrewrite.java.migrate.guava.NoGuavaSetsNewConcurrentHashSet
- org.openrewrite.java.migrate.guava.NoGuavaSetsNewLinkedHashSet
- org.openrewrite.java.migrate.guava.PreferJavaUtilFunction
- org.openrewrite.java.migrate.guava.PreferJavaUtilOptional
- org.openrewrite.java.migrate.guava.PreferJavaUtilPredicate
- org.openrewrite.java.migrate.guava.PreferJavaUtilSupplier
- org.openrewrite.java.migrate.guava.PreferJavaUtilObjectsEquals
Expand Down Expand Up @@ -70,6 +71,34 @@ recipeList:
oldFullyQualifiedTypeName: com.google.common.base.Function
newFullyQualifiedTypeName: java.util.function.Function

---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.guava.PreferJavaUtilOptional
displayName: Prefer `java.util.Optional`
description: Prefer `java.util.Optional` instead of using `com.google.common.base.Optional`.
tags:
- guava, RSPEC-4738
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
recipeList:
- org.openrewrite.java.migrate.guava.PreferJavaUtilOptionalOrElseNull
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.google.common.base.Optional absent()
newMethodName: empty
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.google.common.base.Optional fromNullable(..)
newMethodName: ofNullable
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.google.common.base.Optional or(com.google.common.base.Supplier)
newMethodName: orElseGet
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.google.common.base.Optional or(..)
newMethodName: orElse
- org.openrewrite.java.ChangeMethodName:
methodPattern: com.google.common.base.Optional transform(com.google.common.base.Function)
newMethodName: map
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: com.google.common.base.Optional
newFullyQualifiedTypeName: java.util.Optional

---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.guava.PreferJavaUtilPredicate
Expand Down