From ec8663cea6cfa82d065972e231507bf2c4b7acb7 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Fri, 25 Oct 2024 00:29:43 -0700 Subject: [PATCH] [3/3] Implement joda to java time migration recipe (#591) * [3/3] Implement joda to java time migration recipe * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix autosuggestions * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix unit test --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../java/migrate/joda/JodaTimeRecipe.java | 50 +++++ .../java/migrate/joda/JodaTimeScanner.java | 70 ++---- .../java/migrate/joda/JodaTimeVisitor.java | 74 +++++-- .../java/migrate/joda/ScopeAwareVisitor.java | 95 ++++++++ .../migrate/joda/templates/TimeClassMap.java | 10 + .../migrate/joda/templates/VarTemplates.java | 91 ++++++++ .../java/migrate/joda/JodaTimeRecipeTest.java | 206 ++++++++++++++++++ .../migrate/joda/JodaTimeScannerTest.java | 22 +- .../migrate/joda/JodaTimeVisitorTest.java | 32 +-- 9 files changed, 542 insertions(+), 108 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/migrate/joda/JodaTimeRecipe.java create mode 100644 src/main/java/org/openrewrite/java/migrate/joda/ScopeAwareVisitor.java create mode 100644 src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java create mode 100644 src/test/java/org/openrewrite/java/migrate/joda/JodaTimeRecipeTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeRecipe.java b/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeRecipe.java new file mode 100644 index 000000000..faf34af26 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeRecipe.java @@ -0,0 +1,50 @@ +/* + * Copyright 2024 the original author or authors. + *
+ * 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 + *
+ * https://www.apache.org/licenses/LICENSE-2.0 + *
+ * 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.joda;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.ScanningRecipe;
+import org.openrewrite.java.tree.J.VariableDeclarations.NamedVariable;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class JodaTimeRecipe extends ScanningRecipe
+ * 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.joda;
+
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import org.openrewrite.Cursor;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.java.JavaVisitor;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.J.VariableDeclarations.NamedVariable;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Optional;
+import java.util.Set;
+
+@AllArgsConstructor
+public class ScopeAwareVisitor extends JavaVisitor
+ * 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.joda.templates;
+
+import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.*;
+
+public class VarTemplates {
+
+ private static Map
+ * 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.joda;
+
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class JodaTimeRecipeTest implements RewriteTest {
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec
+ .recipe(new JodaTimeRecipe())
+ .parser(JavaParser.fromJavaVersion().classpath("joda-time"));
+ }
+
+ @DocumentExample
+ @Test
+ void migrateSafeVariable() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.joda.time.DateTime;
+
+ class A {
+ public void foo() {
+ DateTime dt = new DateTime();
+ System.out.println(dt.toDateTime());
+ }
+ }
+ """,
+ """
+ import java.time.ZonedDateTime;
+
+ class A {
+ public void foo() {
+ ZonedDateTime dt = ZonedDateTime.now();
+ System.out.println(dt);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontChangeClassVariable() {
+ // not supported yet
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.joda.time.DateTime;
+
+ class A {
+ public void foo() {
+ DateTime dt = new DateTime();
+ System.out.println(dt.toDateTime());
+ System.out.println(new B().dateTime.toDateTime());
+ }
+ public static class B {
+ DateTime dateTime = new DateTime();
+ }
+ }
+ """,
+ """
+ import org.joda.time.DateTime;
+
+ import java.time.ZonedDateTime;
+
+ class A {
+ public void foo() {
+ ZonedDateTime dt = ZonedDateTime.now();
+ System.out.println(dt);
+ System.out.println(new B().dateTime.toDateTime());
+ }
+ public static class B {
+ DateTime dateTime = new DateTime();
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void dontChangeIncompatibleType() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.joda.time.DateTime;
+
+ class A {
+ public void foo() {
+ new B().print(new DateTime()); // print is public method accepting DateTime, not handled yet
+ System.out.println(new B().dateTime);
+ }
+ }
+
+ class B {
+ DateTime dateTime = new DateTime();
+ public void print(DateTime dateTime) {
+ System.out.println(dateTime);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noUnsafeVar() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.joda.time.DateTime;
+ import org.joda.time.DateTimeZone;
+ import java.util.Date;
+
+ class A {
+ public void foo(String city) {
+ DateTimeZone dtz;
+ if ("london".equals(city)) {
+ dtz = DateTimeZone.forID("Europe/London");
+ } else {
+ dtz = DateTimeZone.forID("America/New_York");
+ }
+ DateTime dt = new DateTime(dtz);
+ print(dt.toDate());
+ }
+ private void print(Date date) {
+ System.out.println(date);
+ }
+ }
+ """,
+ """
+ import java.time.ZoneId;
+ import java.time.ZonedDateTime;
+ import java.util.Date;
+
+ class A {
+ public void foo(String city) {
+ ZoneId dtz;
+ if ("london".equals(city)) {
+ dtz = ZoneId.of("Europe/London");
+ } else {
+ dtz = ZoneId.of("America/New_York");
+ }
+ ZonedDateTime dt = ZonedDateTime.now(dtz);
+ print(Date.from(dt.toInstant()));
+ }
+ private void print(Date date) {
+ System.out.println(date);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void localVarUsedReferencedInReturnStatement() { // not supported yet
+ // language=java
+ rewriteRun(
+ java(
+ """
+ import org.joda.time.DateTime;
+ import org.joda.time.DateTimeZone;
+
+ class A {
+ public DateTime foo(String city) {
+ DateTimeZone dtz;
+ if ("london".equals(city)) {
+ dtz = DateTimeZone.forID("Europe/London");
+ } else {
+ dtz = DateTimeZone.forID("America/New_York");
+ }
+ DateTime dt = new DateTime(dtz);
+ return dt.plus(2);
+ }
+ }
+ """
+ )
+ );
+ }
+}
diff --git a/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeScannerTest.java b/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeScannerTest.java
index 520076236..093469353 100644
--- a/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeScannerTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeScannerTest.java
@@ -21,6 +21,8 @@
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
+import java.util.HashSet;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.openrewrite.java.Assertions.java;
@@ -29,14 +31,12 @@
class JodaTimeScannerTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
- spec
- .recipe(toRecipe(JodaTimeScanner::new))
- .parser(JavaParser.fromJavaVersion().classpath("joda-time"));
+ spec.parser(JavaParser.fromJavaVersion().classpath("joda-time"));
}
@Test
void noUnsafeVar() {
- JodaTimeScanner scanner = new JodaTimeScanner();
+ JodaTimeScanner scanner = new JodaTimeScanner(new HashSet<>());
// language=java
rewriteRun(
spec -> spec.recipe(toRecipe(() -> scanner)),
@@ -45,7 +45,7 @@ void noUnsafeVar() {
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.Date;
-
+
class A {
public void foo(String city) {
DateTimeZone dtz;
@@ -69,7 +69,7 @@ private void print(Date date) {
@Test
void hasUnsafeVars() {
- JodaTimeScanner scanner = new JodaTimeScanner();
+ JodaTimeScanner scanner = new JodaTimeScanner(new HashSet<>());
// language=java
rewriteRun(
spec -> spec.recipe(toRecipe(() -> scanner)),
@@ -77,7 +77,7 @@ void hasUnsafeVars() {
"""
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-
+
class A {
DateTime dateTime;
public void foo(String city) {
@@ -110,7 +110,7 @@ private void print(DateTime dateTime) { // method parameter not handled yet
@Test
void localVarReferencingClassVar() { // not supported yet
- JodaTimeScanner scanner = new JodaTimeScanner();
+ JodaTimeScanner scanner = new JodaTimeScanner(new HashSet<>());
// language=java
rewriteRun(
spec -> spec.recipe(toRecipe(() -> scanner)),
@@ -118,7 +118,7 @@ void localVarReferencingClassVar() { // not supported yet
"""
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-
+
class A {
DateTime dateTime;
public void foo(String city) {
@@ -144,7 +144,7 @@ public void foo(String city) {
@Test
void localVarUsedReferencedInReturnStatement() { // not supported yet
- JodaTimeScanner scanner = new JodaTimeScanner();
+ JodaTimeScanner scanner = new JodaTimeScanner(new HashSet<>());
// language=java
rewriteRun(
spec -> spec.recipe(toRecipe(() -> scanner)),
@@ -152,7 +152,7 @@ void localVarUsedReferencedInReturnStatement() { // not supported yet
"""
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-
+
class A {
public DateTime foo(String city) {
DateTimeZone dtz;
diff --git a/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java b/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java
index a56da3890..5fa813c35 100644
--- a/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java
@@ -497,7 +497,7 @@ public void foo() {
// Test will be removed once safe variable migration is implemented
@Test
- void dontChangeMethodAccessOnVariable() {
+ void migrateSafeVariable() {
//language=java
rewriteRun(
java(
@@ -508,36 +508,16 @@ class A {
public void foo() {
DateTime dt = new DateTime();
System.out.println(dt.toDateTime());
- System.out.println(new B().dateTime.toDateTime());
- }
- public static class B {
- DateTime dateTime = new DateTime();
}
}
- """
- )
- );
- }
-
- @Test
- void dontChangeIncompatibleType() {
- //language=java
- rewriteRun(
- java(
+ """,
"""
- import org.joda.time.DateTime;
-
+ import java.time.ZonedDateTime;
+
class A {
public void foo() {
- new B().print(new DateTime()); // print is public method accepting DateTime, not handled yet
- System.out.println(new B().dateTime);
- }
- }
-
- class B {
- DateTime dateTime = new DateTime();
- public void print(DateTime dateTime) {
- System.out.println(dateTime);
+ ZonedDateTime dt = ZonedDateTime.now();
+ System.out.println(dt);
}
}
"""