From eb96f7fe54194cee5c3b21bfb33bb12b72ff175c Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Mon, 2 Dec 2024 20:45:39 -0800 Subject: [PATCH 1/5] Joda-Time to Java time: Add templates for migrating Joda Interval to Threeten-Extra Interval --- build.gradle.kts | 1 + .../java/migrate/joda/JodaTimeVisitor.java | 2 + .../templates/AbstractIntervalTemplates.java | 64 +++++++++++++ .../migrate/joda/templates/AllTemplates.java | 4 + .../joda/templates/IntervalTemplates.java | 58 ++++++++++++ .../joda/templates/TimeClassNames.java | 7 ++ .../migrate/joda/templates/VarTemplates.java | 1 + .../migrate/joda/JodaTimeVisitorTest.java | 89 +++++++++++++++++-- 8 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java create mode 100644 src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java diff --git a/build.gradle.kts b/build.gradle.kts index d8d2c82ca..e1f2080f8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,6 +50,7 @@ dependencies { testImplementation("com.google.guava:guava:33.0.0-jre") testImplementation("joda-time:joda-time:2.12.3") + testImplementation("org.threeten:threeten-extra:1.8.0") testRuntimeOnly("com.fasterxml.jackson.datatype:jackson-datatype-jsr353") testRuntimeOnly("com.fasterxml.jackson.core:jackson-core") diff --git a/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java b/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java index be5e5652f..54e5348bb 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java @@ -65,6 +65,7 @@ public Javadoc visitReference(Javadoc.Reference reference, ExecutionContext ctx) maybeRemoveImport(JODA_DURATION); maybeRemoveImport(JODA_ABSTRACT_INSTANT); maybeRemoveImport(JODA_INSTANT); + maybeRemoveImport(JODA_INTERVAL); maybeRemoveImport("java.util.Locale"); maybeAddImport(JAVA_DATE_TIME); @@ -79,6 +80,7 @@ public Javadoc visitReference(Javadoc.Reference reference, ExecutionContext ctx) maybeAddImport(JAVA_TEMPORAL_ISO_FIELDS); maybeAddImport(JAVA_CHRONO_FIELD); maybeAddImport(JAVA_UTIL_DATE); + maybeAddImport(THREE_TEN_EXTRA_INTERVAL); return super.visitCompilationUnit(cu, ctx); } diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java new file mode 100644 index 000000000..0e791e974 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java @@ -0,0 +1,64 @@ +/* + * 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.templates; + +import lombok.Getter; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; + +import java.util.ArrayList; +import java.util.List; + +import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.*; + +public class AbstractIntervalTemplates implements Templates { + private final MethodMatcher getStart = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " getStart()"); + private final MethodMatcher getEnd = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " getEnd()"); + private final MethodMatcher toDuration = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " toDuration()"); + private final MethodMatcher toDurationMillis = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " toDurationMillis()"); + private final MethodMatcher contains = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " contains(long)"); + + private final JavaTemplate getStartTemplate = JavaTemplate.builder("#{any(" + THREE_TEN_EXTRA_INTERVAL + ")}.getStart().atZone(ZoneId.systemDefault())") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .imports(JAVA_ZONE_ID) + .build(); + private final JavaTemplate getEndTemplate = JavaTemplate.builder("#{any(" + THREE_TEN_EXTRA_INTERVAL + ")}.getEnd().atZone(ZoneId.systemDefault())") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .imports(JAVA_ZONE_ID) + .build(); + private final JavaTemplate toDurationTemplate = JavaTemplate.builder("#{any(" + THREE_TEN_EXTRA_INTERVAL + ")}.toDuration()") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .build(); + private final JavaTemplate toDurationMillisTemplate = JavaTemplate.builder("#{any(" + THREE_TEN_EXTRA_INTERVAL + ")}.toDuration().toMillis()") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .build(); + private final JavaTemplate containsTemplate = JavaTemplate.builder("#{any(" + THREE_TEN_EXTRA_INTERVAL + ")}.contains(Instant.ofEpochMilli(#{any(long)}))") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .imports(JAVA_INSTANT) + .build(); + + @Getter + private final List templates = new ArrayList() { + { + add(new MethodTemplate(getStart, getStartTemplate)); + add(new MethodTemplate(getEnd, getEndTemplate)); + add(new MethodTemplate(toDuration, toDurationTemplate)); + add(new MethodTemplate(toDurationMillis, toDurationMillisTemplate)); + add(new MethodTemplate(contains, containsTemplate)); + } + }; +} \ No newline at end of file diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/AllTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/AllTemplates.java index dc7e76edc..4be5bb653 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/AllTemplates.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/AllTemplates.java @@ -39,6 +39,8 @@ public class AllTemplates { private static final MethodMatcher ANY_ABSTRACT_DURATION = new MethodMatcher(JODA_ABSTRACT_DURATION + " *(..)"); private static final MethodMatcher ANY_INSTANT = new MethodMatcher(JODA_INSTANT + " *(..)"); private static final MethodMatcher ANY_NEW_INSTANT = new MethodMatcher(JODA_INSTANT + "(..)"); + private static final MethodMatcher ANY_NEW_INTERVAL = new MethodMatcher(JODA_INTERVAL + "(..)"); + private static final MethodMatcher ANY_ABSTRACT_INTERVAL = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " *(..)"); private static List templates = new ArrayList() { { @@ -55,6 +57,8 @@ public class AllTemplates { add(new MatcherAndTemplates(ANY_DATE_TIMEZONE, new TimeZoneTemplates())); add(new MatcherAndTemplates(ANY_INSTANT, new InstantTemplates())); add(new MatcherAndTemplates(ANY_NEW_INSTANT, new InstantTemplates())); + add(new MatcherAndTemplates(ANY_NEW_INTERVAL, new IntervalTemplates())); + add(new MatcherAndTemplates(ANY_ABSTRACT_INTERVAL, new AbstractIntervalTemplates())); } }; diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java new file mode 100644 index 000000000..212f082a5 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java @@ -0,0 +1,58 @@ +/* + * 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.templates; + +import lombok.Getter; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.Expression; + +import java.util.ArrayList; +import java.util.List; + +import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.*; + +public class IntervalTemplates implements Templates { + private final MethodMatcher interval = new MethodMatcher(JODA_INTERVAL + " (long, long)"); + private final MethodMatcher intervalWithTimeZone = new MethodMatcher(JODA_INTERVAL + " (long, long, " + JODA_DATE_TIME_ZONE + ")"); + private final MethodMatcher intervalWithDateTime = new MethodMatcher(JODA_INTERVAL + " (" + JODA_READABLE_INSTANT + ", " + JODA_READABLE_INSTANT + ")"); + private final MethodMatcher intervalWithDateTimeAndDuration = new MethodMatcher(JODA_INTERVAL + " (" + JODA_READABLE_INSTANT + ", " + JODA_READABLE_DURATION + ")"); + + private final JavaTemplate intervalTemplate = JavaTemplate.builder("Interval.of(Instant.ofEpochMilli(#{any(long)}), Instant.ofEpochMilli(#{any(long)}))") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .imports(JAVA_INSTANT, THREE_TEN_EXTRA_INTERVAL) + .build(); + private final JavaTemplate intervalWithDateTimeTemplate = JavaTemplate.builder("Interval.of(#{any(" + JAVA_DATE_TIME + ")}.toInstant(), #{any(" + JAVA_DATE_TIME + ")}.toInstant())") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .imports(THREE_TEN_EXTRA_INTERVAL) + .build(); + private final JavaTemplate intervalWithDateTimeAndDurationTemplate = JavaTemplate.builder("Interval.of(#{any(" + JAVA_DATE_TIME + ")}.toInstant(), #{any(" + JAVA_DURATION + ")})") + .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .imports(THREE_TEN_EXTRA_INTERVAL) + .build(); + + @Getter + private final List templates = new ArrayList() { + { + add(new MethodTemplate(interval, intervalTemplate)); + add(new MethodTemplate(intervalWithTimeZone, intervalTemplate, + m -> new Expression[]{m.getArguments().get(0), m.getArguments().get(1)})); + add(new MethodTemplate(intervalWithDateTime, intervalWithDateTimeTemplate)); + add(new MethodTemplate(intervalWithDateTimeAndDuration, intervalWithDateTimeAndDurationTemplate)); + } + }; +} \ No newline at end of file diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java index 428284174..8e7fed548 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java @@ -27,6 +27,7 @@ public class TimeClassNames { public static final String JODA_TIME_PKG = "org.joda.time"; public static final String JODA_ABSTRACT_DATE_TIME = JODA_TIME_PKG + ".base.AbstractDateTime"; public static final String JODA_ABSTRACT_DURATION = JODA_TIME_PKG + ".base.AbstractDuration"; + public static final String JODA_ABSTRACT_INTERVAL = JODA_TIME_PKG + ".base.AbstractInterval"; public static final String JODA_BASE_DATE_TIME = JODA_TIME_PKG + ".base.BaseDateTime"; public static final String JODA_DATE_TIME = JODA_TIME_PKG + ".DateTime"; public static final String JODA_DATE_TIME_ZONE = JODA_TIME_PKG + ".DateTimeZone"; @@ -39,7 +40,9 @@ public class TimeClassNames { public static final String JODA_DURATION = JODA_TIME_PKG + ".Duration"; public static final String JODA_READABLE_DURATION = JODA_TIME_PKG + ".ReadableDuration"; public static final String JODA_ABSTRACT_INSTANT = JODA_TIME_PKG + ".base.AbstractInstant"; + public static final String JODA_READABLE_INSTANT = JODA_TIME_PKG + ".ReadableInstant"; public static final String JODA_INSTANT = JODA_TIME_PKG + ".Instant"; + public static final String JODA_INTERVAL = JODA_TIME_PKG + ".Interval"; // Java Time classes public static final String JAVA_TIME_PKG = "java.time"; @@ -55,4 +58,8 @@ public class TimeClassNames { public static final String JAVA_LOCAL_TIME = JAVA_TIME_PKG + ".LocalTime"; public static final String JAVA_TEMPORAL_ISO_FIELDS = JAVA_TIME_PKG + ".temporal.IsoFields"; public static final String JAVA_CHRONO_FIELD = JAVA_TIME_PKG + ".temporal.ChronoField"; + + // ThreeTen-Extra classes + public static final String THREE_TEN_EXTRA_PKG = "org.threeten.extra"; + public static final String THREE_TEN_EXTRA_INTERVAL = THREE_TEN_EXTRA_PKG + ".Interval"; } diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java index d555492a3..6cba698a3 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java @@ -35,6 +35,7 @@ public class VarTemplates { put(JODA_LOCAL_TIME, JAVA_LOCAL_TIME); put(JODA_DATE_TIME_ZONE, JAVA_ZONE_ID); put(JODA_DURATION, JAVA_DURATION); + put(JODA_INTERVAL, THREE_TEN_EXTRA_INTERVAL); } }; 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 71118e3a8..538c64ae1 100644 --- a/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java +++ b/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java @@ -32,7 +32,7 @@ class JodaTimeVisitorTest implements RewriteTest { public void defaults(RecipeSpec spec) { spec .recipe(toRecipe(() -> new JodaTimeVisitor(new JodaTimeRecipe.Accumulator(), true, new LinkedList<>()))) - .parser(JavaParser.fromJavaVersion().classpath("joda-time")); + .parser(JavaParser.fromJavaVersion().classpath("joda-time", "threeten-extra")); } @DocumentExample @@ -695,11 +695,11 @@ void unhandledCases() { rewriteRun( java( """ - import org.joda.time.Interval; + import org.joda.time.PeriodType; class A { public void foo() { - new Interval(100, 50); + PeriodType.standard(); } } """ @@ -782,11 +782,90 @@ void unhandledVarDeclaration() { rewriteRun( java( """ + import org.joda.time.PeriodType; + + class A { + public void foo(PeriodType periodType) { + periodType = PeriodType.days(); + } + } + """ + ) + ); + } + + @Test + void migrateInterval() { + // language=java + rewriteRun( + java( + """ + import org.joda.time.DateTime; + import org.joda.time.Duration; import org.joda.time.Interval; + import org.joda.time.DateTimeZone; + + class A { + public void foo() { + System.out.println(new Interval(50, 100)); + System.out.println(new Interval(50, 100, DateTimeZone.UTC)); + System.out.println(new Interval(DateTime.now(), DateTime.now().plusDays(1))); + System.out.println(new Interval(DateTime.now(), Duration.standardDays(1))); + } + } + """, + """ + import org.threeten.extra.Interval; + import java.time.Duration; + import java.time.Instant; + import java.time.ZonedDateTime; + class A { - public void foo(Interval interval) { - interval = new Interval(100, 50); + public void foo() { + System.out.println(Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100))); + System.out.println(Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100))); + System.out.println(Interval.of(ZonedDateTime.now().toInstant(), ZonedDateTime.now().plusDays(1).toInstant())); + System.out.println(Interval.of(ZonedDateTime.now().toInstant(), Duration.ofDays(1))); + } + } + """ + ) + ); + } + + @Test + void migrateAbstractInterval() { + // language=java + rewriteRun( + java( + """ + import org.joda.time.DateTime; + import org.joda.time.Interval; + + class A { + public void foo() { + new Interval(50, 100).getStart(); + new Interval(50, 100).getEnd(); + new Interval(50, 100).toDuration(); + new Interval(50, 100).toDurationMillis(); + new Interval(50, 100).contains(75); + } + } + """, + """ + import org.threeten.extra.Interval; + + import java.time.Instant; + import java.time.ZoneId; + + class A { + public void foo() { + Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100)).getStart().atZone(ZoneId.systemDefault()); + Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100)).getEnd().atZone(ZoneId.systemDefault()); + Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100)).toDuration(); + Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100)).toDuration().toMillis(); + Interval.of(Instant.ofEpochMilli(50), Instant.ofEpochMilli(100)).contains(Instant.ofEpochMilli(75)); } } """ From 9cf2fe6f15809b1f5e8fc113018c17be352a56f0 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Tue, 3 Dec 2024 10:41:16 -0800 Subject: [PATCH 2/5] Syling: remove indent from empty lines --- .../migrate/joda/templates/AbstractIntervalTemplates.java | 6 +++--- .../java/migrate/joda/templates/IntervalTemplates.java | 6 +++--- .../java/migrate/joda/templates/TimeClassNames.java | 2 +- .../openrewrite/java/migrate/joda/JodaTimeVisitorTest.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java index 0e791e974..9028b507c 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractIntervalTemplates.java @@ -31,7 +31,7 @@ public class AbstractIntervalTemplates implements Templates { private final MethodMatcher toDuration = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " toDuration()"); private final MethodMatcher toDurationMillis = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " toDurationMillis()"); private final MethodMatcher contains = new MethodMatcher(JODA_ABSTRACT_INTERVAL + " contains(long)"); - + private final JavaTemplate getStartTemplate = JavaTemplate.builder("#{any(" + THREE_TEN_EXTRA_INTERVAL + ")}.getStart().atZone(ZoneId.systemDefault())") .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) .imports(JAVA_ZONE_ID) @@ -50,7 +50,7 @@ public class AbstractIntervalTemplates implements Templates { .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) .imports(JAVA_INSTANT) .build(); - + @Getter private final List templates = new ArrayList() { { @@ -61,4 +61,4 @@ public class AbstractIntervalTemplates implements Templates { add(new MethodTemplate(contains, containsTemplate)); } }; -} \ No newline at end of file +} diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java index 212f082a5..9ccb8edb0 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java @@ -31,7 +31,7 @@ public class IntervalTemplates implements Templates { private final MethodMatcher intervalWithTimeZone = new MethodMatcher(JODA_INTERVAL + " (long, long, " + JODA_DATE_TIME_ZONE + ")"); private final MethodMatcher intervalWithDateTime = new MethodMatcher(JODA_INTERVAL + " (" + JODA_READABLE_INSTANT + ", " + JODA_READABLE_INSTANT + ")"); private final MethodMatcher intervalWithDateTimeAndDuration = new MethodMatcher(JODA_INTERVAL + " (" + JODA_READABLE_INSTANT + ", " + JODA_READABLE_DURATION + ")"); - + private final JavaTemplate intervalTemplate = JavaTemplate.builder("Interval.of(Instant.ofEpochMilli(#{any(long)}), Instant.ofEpochMilli(#{any(long)}))") .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) .imports(JAVA_INSTANT, THREE_TEN_EXTRA_INTERVAL) @@ -44,7 +44,7 @@ public class IntervalTemplates implements Templates { .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) .imports(THREE_TEN_EXTRA_INTERVAL) .build(); - + @Getter private final List templates = new ArrayList() { { @@ -55,4 +55,4 @@ public class IntervalTemplates implements Templates { add(new MethodTemplate(intervalWithDateTimeAndDuration, intervalWithDateTimeAndDurationTemplate)); } }; -} \ No newline at end of file +} diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java index 8e7fed548..e2007c2ef 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassNames.java @@ -58,7 +58,7 @@ public class TimeClassNames { public static final String JAVA_LOCAL_TIME = JAVA_TIME_PKG + ".LocalTime"; public static final String JAVA_TEMPORAL_ISO_FIELDS = JAVA_TIME_PKG + ".temporal.IsoFields"; public static final String JAVA_CHRONO_FIELD = JAVA_TIME_PKG + ".temporal.ChronoField"; - + // ThreeTen-Extra classes public static final String THREE_TEN_EXTRA_PKG = "org.threeten.extra"; public static final String THREE_TEN_EXTRA_INTERVAL = THREE_TEN_EXTRA_PKG + ".Interval"; 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 538c64ae1..bdf930d1c 100644 --- a/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java +++ b/src/test/java/org/openrewrite/java/migrate/joda/JodaTimeVisitorTest.java @@ -793,7 +793,7 @@ public void foo(PeriodType periodType) { ) ); } - + @Test void migrateInterval() { // language=java @@ -833,7 +833,7 @@ public void foo() { ) ); } - + @Test void migrateAbstractInterval() { // language=java From fa33321abf43ce8f35f072ba4121e5e0b4120252 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Tue, 3 Dec 2024 20:35:59 -0800 Subject: [PATCH 3/5] Add threeten-extra dependency, if needed --- .../java/migrate/joda/JodaTimeVisitor.java | 8 +- .../joda/templates/IntervalTemplates.java | 6 +- .../migrate/joda/templates/TimeClassMap.java | 1 + .../migrate/joda/templates/VarTemplates.java | 6 +- .../META-INF/rewrite/no-joda-time.yml | 33 ++++++ .../java/migrate/joda/NoJodaTimeTest.java | 111 ++++++++++++++++++ 6 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/META-INF/rewrite/no-joda-time.yml create mode 100644 src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java b/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java index 54e5348bb..c99fb43bb 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java @@ -170,9 +170,11 @@ public Javadoc visitReference(Javadoc.Reference reference, ExecutionContext ctx) if (!isJodaVarRef(ident)) { return super.visitIdentifier(ident, ctx); } - Optional mayBeVar = findVarInScope(ident.getSimpleName()); - if (!mayBeVar.isPresent() || acc.getUnsafeVars().contains(mayBeVar.get())) { - return ident; + if (this.safeMigration) { + Optional mayBeVar = findVarInScope(ident.getSimpleName()); + if (!mayBeVar.isPresent() || acc.getUnsafeVars().contains(mayBeVar.get())) { + return ident; + } } JavaType.FullyQualified jodaType = ((JavaType.Class) ident.getType()); diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java index 9ccb8edb0..38fb212c2 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/IntervalTemplates.java @@ -33,15 +33,15 @@ public class IntervalTemplates implements Templates { private final MethodMatcher intervalWithDateTimeAndDuration = new MethodMatcher(JODA_INTERVAL + " (" + JODA_READABLE_INSTANT + ", " + JODA_READABLE_DURATION + ")"); private final JavaTemplate intervalTemplate = JavaTemplate.builder("Interval.of(Instant.ofEpochMilli(#{any(long)}), Instant.ofEpochMilli(#{any(long)}))") - .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .javaParser(JavaParser.fromJavaVersion().classpath("threeten")) .imports(JAVA_INSTANT, THREE_TEN_EXTRA_INTERVAL) .build(); private final JavaTemplate intervalWithDateTimeTemplate = JavaTemplate.builder("Interval.of(#{any(" + JAVA_DATE_TIME + ")}.toInstant(), #{any(" + JAVA_DATE_TIME + ")}.toInstant())") - .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .javaParser(JavaParser.fromJavaVersion().classpath("threeten")) .imports(THREE_TEN_EXTRA_INTERVAL) .build(); private final JavaTemplate intervalWithDateTimeAndDurationTemplate = JavaTemplate.builder("Interval.of(#{any(" + JAVA_DATE_TIME + ")}.toInstant(), #{any(" + JAVA_DURATION + ")})") - .javaParser(JavaParser.fromJavaVersion().classpath("threeten-extra")) + .javaParser(JavaParser.fromJavaVersion().classpath("threeten")) .imports(THREE_TEN_EXTRA_INTERVAL) .build(); diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassMap.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassMap.java index 0b3760297..7663a8389 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassMap.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/TimeClassMap.java @@ -35,6 +35,7 @@ public class TimeClassMap { put(JODA_TIME_FORMATTER, javaTypeClass(JAVA_TIME_FORMATTER, object)); put(JODA_DURATION, javaTypeClass(JAVA_DURATION, object)); put(JODA_READABLE_DURATION, javaTypeClass(JAVA_DURATION, object)); + put(JODA_INTERVAL, javaTypeClass(THREE_TEN_EXTRA_INTERVAL, object)); } }; diff --git a/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java b/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java index 6cba698a3..e6c70ede2 100644 --- a/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java +++ b/src/main/java/org/openrewrite/java/migrate/joda/templates/VarTemplates.java @@ -15,6 +15,7 @@ */ package org.openrewrite.java.migrate.joda.templates; +import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -66,8 +67,9 @@ public static Optional getTemplate(J.VariableDeclarations variable } } return Optional.of(JavaTemplate.builder(template.toString()) - .imports(typeName) - .build()); + .imports(typeName) + .javaParser(JavaParser.fromJavaVersion().classpath("threeten")) + .build()); } public static Optional getTemplate(J.Assignment assignment) { diff --git a/src/main/resources/META-INF/rewrite/no-joda-time.yml b/src/main/resources/META-INF/rewrite/no-joda-time.yml new file mode 100644 index 000000000..609345eef --- /dev/null +++ b/src/main/resources/META-INF/rewrite/no-joda-time.yml @@ -0,0 +1,33 @@ +# +# Copyright 2021 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. +# +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.migrate.joda.NoJodaTime +displayName: Prefer the Java standard library instead of JodaTime +description: >- + Before Java 8, Java lacked a robust date and time library, leading to the widespread use of Joda-Time to fill this + gap. With the release of Java 8, the java.time package was introduced, incorporating most of Joda-Time's concepts. + Features deemed too specialized or bulky for java.time were included in the ThreeTen-Extra library. This recipe + migrates JodaTime types to java.time and threeten-extra types. +tags: + - joda-time +recipeList: + - org.openrewrite.java.migrate.joda.JodaTimeRecipe + - org.openrewrite.java.dependencies.AddDependency: + groupId: org.threeten + artifactId: threeten-extra + version: 1.8.0 + onlyIfUsing: org.joda.time.*Interval* \ No newline at end of file diff --git a/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java b/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java new file mode 100644 index 000000000..b9a26f70b --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java @@ -0,0 +1,111 @@ +/* + * 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.junit.jupiter.api.Test; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.*; +import static org.openrewrite.maven.Assertions.pomXml; + +public class NoJodaTimeTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec + .recipeFromResource("/META-INF/rewrite/no-joda-time.yml", "org.openrewrite.java.migrate.joda.NoJodaTime") + .parser(JavaParser.fromJavaVersion().classpath("joda-time", "threeten-extra")); + } + @Test + void migrateJodaTime() { + rewriteRun( + mavenProject("foo", + srcMainJava( + // language=java + java( + """ + import org.joda.time.DateTime; + import org.joda.time.Interval; + + public class A { + public void foo() { + DateTime dt = new DateTime(); + DateTime dt1 = new DateTime().plusDays(1); + Interval i = new Interval(dt, dt1); + System.out.println(i.toDuration()); + } + } + """, + """ + import org.threeten.extra.Interval; + + import java.time.ZonedDateTime; + + public class A { + public void foo() { + ZonedDateTime dt = ZonedDateTime.now(); + ZonedDateTime dt1 = ZonedDateTime.now().plusDays(1); + Interval i = Interval.of(dt.toInstant(), dt1.toInstant()); + System.out.println(i.toDuration()); + } + } + """ + ), + //language=xml + pomXml( + """ + + 4.0.0 + com.example.foobar + foobar-core + 1.0.0 + + + joda-time + joda-time + 2.12.3 + + + + """, + """ + + 4.0.0 + com.example.foobar + foobar-core + 1.0.0 + + + joda-time + joda-time + 2.12.3 + + + org.threeten + threeten-extra + 1.8.0 + + + + """ + ) + ) + ) + ); + } +} From 6bfc13f93407b688d68fd33e69b26dc81b438a3a Mon Sep 17 00:00:00 2001 From: Anshuman Mishra Date: Tue, 3 Dec 2024 20:50:33 -0800 Subject: [PATCH 4/5] checkstyle --- .../java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java b/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java index b9a26f70b..0698dd766 100644 --- a/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java +++ b/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java @@ -23,7 +23,7 @@ import static org.openrewrite.java.Assertions.*; import static org.openrewrite.maven.Assertions.pomXml; -public class NoJodaTimeTest implements RewriteTest { +class NoJodaTimeTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { From 44f0272723c96660b6b4d86517d0d5fffa881fde Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 4 Dec 2024 11:23:03 +0100 Subject: [PATCH 5/5] Minor polish --- .../META-INF/rewrite/no-joda-time.yml | 14 +++--- .../java/migrate/joda/NoJodaTimeTest.java | 49 ++++++++++--------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/main/resources/META-INF/rewrite/no-joda-time.yml b/src/main/resources/META-INF/rewrite/no-joda-time.yml index 609345eef..d7b223104 100644 --- a/src/main/resources/META-INF/rewrite/no-joda-time.yml +++ b/src/main/resources/META-INF/rewrite/no-joda-time.yml @@ -16,18 +16,18 @@ --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.java.migrate.joda.NoJodaTime -displayName: Prefer the Java standard library instead of JodaTime +displayName: Prefer the Java standard library instead of Joda-Time description: >- - Before Java 8, Java lacked a robust date and time library, leading to the widespread use of Joda-Time to fill this - gap. With the release of Java 8, the java.time package was introduced, incorporating most of Joda-Time's concepts. - Features deemed too specialized or bulky for java.time were included in the ThreeTen-Extra library. This recipe - migrates JodaTime types to java.time and threeten-extra types. + Before Java 8, Java lacked a robust date and time library, leading to the widespread use of Joda-Time to fill this + gap. With the release of Java 8, the `java.time` package was introduced, incorporating most of Joda-Time's concepts. + Features deemed too specialized or bulky for `java.time` were included in the ThreeTen-Extra library. This recipe + migrates Joda-Time types to `java.time` and `threeten-extra` types. tags: - joda-time recipeList: - - org.openrewrite.java.migrate.joda.JodaTimeRecipe - org.openrewrite.java.dependencies.AddDependency: groupId: org.threeten artifactId: threeten-extra version: 1.8.0 - onlyIfUsing: org.joda.time.*Interval* \ No newline at end of file + onlyIfUsing: org.joda.time.*Interval* + - org.openrewrite.java.migrate.joda.JodaTimeRecipe diff --git a/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java b/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java index 0698dd766..f153a0077 100644 --- a/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java +++ b/src/test/java/org/openrewrite/java/migrate/joda/NoJodaTimeTest.java @@ -16,6 +16,7 @@ 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; @@ -31,6 +32,8 @@ public void defaults(RecipeSpec spec) { .recipeFromResource("/META-INF/rewrite/no-joda-time.yml", "org.openrewrite.java.migrate.joda.NoJodaTime") .parser(JavaParser.fromJavaVersion().classpath("joda-time", "threeten-extra")); } + + @DocumentExample @Test void migrateJodaTime() { rewriteRun( @@ -39,32 +42,32 @@ void migrateJodaTime() { // language=java java( """ - import org.joda.time.DateTime; - import org.joda.time.Interval; - - public class A { - public void foo() { - DateTime dt = new DateTime(); - DateTime dt1 = new DateTime().plusDays(1); - Interval i = new Interval(dt, dt1); - System.out.println(i.toDuration()); - } - } - """, + import org.joda.time.DateTime; + import org.joda.time.Interval; + + class A { + void foo() { + DateTime dt = new DateTime(); + DateTime dt1 = new DateTime().plusDays(1); + Interval i = new Interval(dt, dt1); + System.out.println(i.toDuration()); + } + } + """, """ - import org.threeten.extra.Interval; + import org.threeten.extra.Interval; - import java.time.ZonedDateTime; + import java.time.ZonedDateTime; - public class A { - public void foo() { - ZonedDateTime dt = ZonedDateTime.now(); - ZonedDateTime dt1 = ZonedDateTime.now().plusDays(1); - Interval i = Interval.of(dt.toInstant(), dt1.toInstant()); - System.out.println(i.toDuration()); - } - } - """ + class A { + void foo() { + ZonedDateTime dt = ZonedDateTime.now(); + ZonedDateTime dt1 = ZonedDateTime.now().plusDays(1); + Interval i = Interval.of(dt.toInstant(), dt1.toInstant()); + System.out.println(i.toDuration()); + } + } + """ ), //language=xml pomXml(