Skip to content

Commit 41a76c8

Browse files
authored
Joda time to Java time: Add few more templates for migration (#594)
* Joda time to Java time: Add few more templates for migration * Fix OutOfMemory for tests by increasing Heap Size
1 parent 88cf8f5 commit 41a76c8

16 files changed

+700
-91
lines changed

build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ dependencies {
6565
tasks.withType(Javadoc::class.java) {
6666
exclude("**/PlanJavaMigration.java")
6767
}
68+
69+
tasks.test {
70+
maxHeapSize = "2g" // Set max heap size to 2GB or adjust as necessary
71+
}

src/main/java/org/openrewrite/java/migrate/joda/JodaTimeVisitor.java

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import org.jspecify.annotations.Nullable;
2020
import org.openrewrite.ExecutionContext;
2121
import org.openrewrite.java.JavaTemplate;
22-
import org.openrewrite.java.MethodMatcher;
2322
import org.openrewrite.java.migrate.joda.templates.*;
2423
import org.openrewrite.java.tree.*;
2524
import org.openrewrite.java.tree.J.VariableDeclarations.NamedVariable;
@@ -31,15 +30,6 @@
3130

3231
public class JodaTimeVisitor extends ScopeAwareVisitor {
3332

34-
private final MethodMatcher anyNewDateTime = new MethodMatcher(JODA_DATE_TIME + "<constructor>(..)");
35-
private final MethodMatcher anyDateTime = new MethodMatcher(JODA_DATE_TIME + " *(..)");
36-
private final MethodMatcher anyBaseDateTime = new MethodMatcher(JODA_BASE_DATE_TIME + " *(..)");
37-
private final MethodMatcher zoneFor = new MethodMatcher(JODA_DATE_TIME_ZONE + " for*(..)");
38-
private final MethodMatcher anyTimeFormatter = new MethodMatcher(JODA_TIME_FORMAT + " *(..)");
39-
private final MethodMatcher anyNewDuration = new MethodMatcher(JODA_DURATION + "<constructor>(..)");
40-
private final MethodMatcher anyDuration = new MethodMatcher(JODA_DURATION + " *(..)");
41-
private final MethodMatcher anyAbstractInstant = new MethodMatcher(JODA_ABSTRACT_INSTANT + " *(..)");
42-
4333
private final Set<NamedVariable> unsafeVars;
4434

4535
public JodaTimeVisitor(Set<NamedVariable> unsafeVars, LinkedList<VariablesInScope> scopes) {
@@ -62,6 +52,7 @@ public JodaTimeVisitor() {
6252
maybeRemoveImport(JODA_TIME_FORMAT);
6353
maybeRemoveImport(JODA_DURATION);
6454
maybeRemoveImport(JODA_ABSTRACT_INSTANT);
55+
maybeRemoveImport(JODA_INSTANT);
6556
maybeRemoveImport("java.util.Locale");
6657

6758
maybeAddImport(JAVA_DATE_TIME);
@@ -135,11 +126,9 @@ public JodaTimeVisitor() {
135126
if (hasJodaType(updated.getArguments())) {
136127
return newClass;
137128
}
138-
if (anyNewDateTime.matches(newClass)) {
139-
return applyTemplate(newClass, updated, DateTimeTemplates.getTemplates()).orElse(newClass);
140-
}
141-
if (anyNewDuration.matches(newClass)) {
142-
return applyTemplate(newClass, updated, DurationTemplates.getTemplates()).orElse(newClass);
129+
MethodTemplate template = AllTemplates.getTemplate(newClass);
130+
if (template != null) {
131+
return applyTemplate(newClass, updated, template).orElse(newClass);
143132
}
144133
if (areArgumentsAssignable(updated)) {
145134
return updated;
@@ -154,24 +143,11 @@ public JodaTimeVisitor() {
154143
if (hasJodaType(m.getArguments()) || isJodaVarRef(m.getSelect())) {
155144
return method;
156145
}
157-
if (zoneFor.matches(method)) {
158-
return applyTemplate(method, m, TimeZoneTemplates.getTemplates()).orElse(method);
159-
}
160-
if (anyDateTime.matches(method) || anyBaseDateTime.matches(method)) {
161-
return applyTemplate(method, m, DateTimeTemplates.getTemplates()).orElse(method);
162-
}
163-
if (anyAbstractInstant.matches(method)) {
164-
return applyTemplate(method, m, AbstractInstantTemplates.getTemplates()).orElse(method);
165-
}
166-
if (anyTimeFormatter.matches(method)) {
167-
return applyTemplate(method, m, DateTimeFormatTemplates.getTemplates()).orElse(method);
168-
}
169-
if (anyDuration.matches(method)) {
170-
return applyTemplate(method, m, DurationTemplates.getTemplates()).orElse(method);
146+
MethodTemplate template = AllTemplates.getTemplate(method);
147+
if (template != null) {
148+
return applyTemplate(method, m, template).orElse(method);
171149
}
172-
if (method.getSelect() != null &&
173-
method.getSelect().getType() != null &&
174-
method.getSelect().getType().isAssignableFrom(JODA_CLASS_PATTERN)) {
150+
if (method.getMethodType().getDeclaringType().isAssignableFrom(JODA_CLASS_PATTERN)) {
175151
return method; // unhandled case
176152
}
177153
if (areArgumentsAssignable(m)) {
@@ -219,15 +195,13 @@ private boolean hasJodaType(List<Expression> exprs) {
219195
return false;
220196
}
221197

222-
private Optional<J> applyTemplate(MethodCall original, MethodCall updated, List<MethodTemplate> templates) {
223-
for (MethodTemplate template : templates) {
224-
if (template.getMatcher().matches(original)) {
225-
Expression[] args = template.getTemplateArgsFunc().apply(updated);
226-
if (args.length == 0) {
227-
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace()));
228-
}
229-
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace(), (Object[]) args));
198+
private Optional<J> applyTemplate(MethodCall original, MethodCall updated, MethodTemplate template) {
199+
if (template.getMatcher().matches(original)) {
200+
Expression[] args = template.getTemplateArgsFunc().apply(updated);
201+
if (args.length == 0) {
202+
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace()));
230203
}
204+
return Optional.of(template.getTemplate().apply(updateCursor(updated), updated.getCoordinates().replace(), (Object[]) args));
231205
}
232206
return Optional.empty(); // unhandled case
233207
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.migrate.joda.templates;
17+
18+
import lombok.Getter;
19+
import org.openrewrite.java.JavaTemplate;
20+
import org.openrewrite.java.MethodMatcher;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.JAVA_DATE_TIME;
26+
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.JODA_ABSTRACT_DATE_TIME;
27+
28+
public class AbstractDateTimeTemplates implements Templates {
29+
private final MethodMatcher getDayOfMonth = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getDayOfMonth()");
30+
private final MethodMatcher getDayOfWeek = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getDayOfWeek()");
31+
private final MethodMatcher getHourOfDay = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getHourOfDay()");
32+
private final MethodMatcher getMillisOfSecond = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getMillisOfSecond()");
33+
private final MethodMatcher getMinuteOfDay = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getMinuteOfDay()");
34+
private final MethodMatcher getMinuteOfHour = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getMinuteOfHour()");
35+
private final MethodMatcher getMonthOfYear = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getMonthOfYear()");
36+
private final MethodMatcher getSecondOfDay = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getSecondOfDay()");
37+
private final MethodMatcher getSecondOfMinute = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getSecondOfMinute()");
38+
private final MethodMatcher getWeekOfWeekyear = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " getWeekOfWeekyear()");
39+
private final MethodMatcher toString = new MethodMatcher(JODA_ABSTRACT_DATE_TIME + " toString()");
40+
41+
private final JavaTemplate getDayOfMonthTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getDayOfMonth()").build();
42+
private final JavaTemplate getDayOfWeekTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getDayOfWeek().getValue()").build();
43+
private final JavaTemplate getHourOfDayTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getHour()").build();
44+
private final JavaTemplate getMillisOfSecondTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.get(ChronoField.MILLI_OF_SECOND)").imports("java.time.temporal.ChronoField").build();
45+
private final JavaTemplate getMinuteOfDayTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.get(ChronoField.MINUTE_OF_DAY)").imports("java.time.temporal.ChronoField").build();
46+
private final JavaTemplate getMinuteOfHourTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getMinute()").build();
47+
private final JavaTemplate getMonthOfYearTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getMonthValue()").build();
48+
private final JavaTemplate getSecondOfDayTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.get(ChronoField.SECOND_OF_DAY)").imports("java.time.temporal.ChronoField").build();
49+
private final JavaTemplate getSecondOfMinuteTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getSecond()").build();
50+
private final JavaTemplate getWeekOfWeekyearTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.get(ChronoField.ALIGNED_WEEK_OF_YEAR)").imports("java.time.temporal.ChronoField").build();
51+
private final JavaTemplate toStringTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.toString()").build();
52+
53+
@Getter
54+
private final List<MethodTemplate> templates = new ArrayList<MethodTemplate>() {
55+
{
56+
add(new MethodTemplate(getDayOfMonth, getDayOfMonthTemplate));
57+
add(new MethodTemplate(getDayOfWeek, getDayOfWeekTemplate));
58+
add(new MethodTemplate(getHourOfDay, getHourOfDayTemplate));
59+
add(new MethodTemplate(getMillisOfSecond, getMillisOfSecondTemplate));
60+
add(new MethodTemplate(getMinuteOfDay, getMinuteOfDayTemplate));
61+
add(new MethodTemplate(getMinuteOfHour, getMinuteOfHourTemplate));
62+
add(new MethodTemplate(getMonthOfYear, getMonthOfYearTemplate));
63+
add(new MethodTemplate(getSecondOfDay, getSecondOfDayTemplate));
64+
add(new MethodTemplate(getSecondOfMinute, getSecondOfMinuteTemplate));
65+
add(new MethodTemplate(getWeekOfWeekyear, getWeekOfWeekyearTemplate));
66+
add(new MethodTemplate(toString, toStringTemplate));
67+
}
68+
};
69+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/package org.openrewrite.java.migrate.joda.templates;
16+
17+
import lombok.Getter;
18+
import org.openrewrite.java.JavaTemplate;
19+
import org.openrewrite.java.MethodMatcher;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.JAVA_DURATION;
25+
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.JODA_DURATION;
26+
27+
public class AbstractDurationTemplates implements Templates {
28+
private final MethodMatcher isLongerThan = new MethodMatcher(JODA_DURATION + " isLongerThan(..)");
29+
private final MethodMatcher toPeriod = new MethodMatcher(JODA_DURATION + " toPeriod()");
30+
31+
private final JavaTemplate isLongerThanTemplate = JavaTemplate.builder("#{any(" + JAVA_DURATION + ")}.compareTo(#{any(" + JAVA_DURATION + ")}) > 0").build();
32+
private final JavaTemplate toPeriodTemplate = JavaTemplate.builder("#{any(" + JAVA_DURATION + ")}.toPeriod()").build();
33+
34+
@Getter
35+
private final List<MethodTemplate> templates = new ArrayList<MethodTemplate>() {
36+
{
37+
add(new MethodTemplate(isLongerThan, isLongerThanTemplate));
38+
add(new MethodTemplate(toPeriod, toPeriodTemplate));
39+
}
40+
};
41+
}

src/main/java/org/openrewrite/java/migrate/joda/templates/AbstractInstantTemplates.java

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,98 @@
1515
*/
1616
package org.openrewrite.java.migrate.joda.templates;
1717

18+
import lombok.Getter;
1819
import org.openrewrite.java.JavaTemplate;
1920
import org.openrewrite.java.MethodMatcher;
21+
import org.openrewrite.java.tree.Expression;
22+
import org.openrewrite.java.tree.J;
23+
import org.openrewrite.java.tree.MethodCall;
2024

2125
import java.util.ArrayList;
26+
import java.util.Arrays;
2227
import java.util.List;
28+
import java.util.regex.Pattern;
2329

24-
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.JAVA_UTIL_DATE;
25-
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.JODA_ABSTRACT_INSTANT;
30+
import static org.openrewrite.java.migrate.joda.templates.TimeClassNames.*;
2631

27-
public class AbstractInstantTemplates {
32+
public class AbstractInstantTemplates implements Templates {
33+
private final MethodMatcher equals = new MethodMatcher(JODA_ABSTRACT_INSTANT + " equals(java.lang.Object)");
34+
private final MethodMatcher getZone = new MethodMatcher(JODA_ABSTRACT_INSTANT + " getZone()");
35+
private final MethodMatcher isAfterLong = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isAfter(long)");
36+
private final MethodMatcher isAfter = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isAfter(org.joda.time.ReadableInstant)");
37+
private final MethodMatcher isBeforeLong = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isBefore(long)");
38+
private final MethodMatcher isBefore = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isBefore(org.joda.time.ReadableInstant)");
39+
private final MethodMatcher isBeforeNow = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isBeforeNow()");
40+
private final MethodMatcher isEqualLong = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isEqual(long)");
41+
private final MethodMatcher isEqualReadableInstant = new MethodMatcher(JODA_ABSTRACT_INSTANT + " isEqual(org.joda.time.ReadableInstant)");
2842
private final MethodMatcher toDate = new MethodMatcher(JODA_ABSTRACT_INSTANT + " toDate()");
43+
private final MethodMatcher toInstant = new MethodMatcher(JODA_ABSTRACT_INSTANT + " toInstant()");
44+
private final MethodMatcher toString = new MethodMatcher(JODA_ABSTRACT_INSTANT + " toString()");
45+
private final MethodMatcher toStringFormatter = new MethodMatcher(JODA_ABSTRACT_INSTANT + " toString(org.joda.time.format.DateTimeFormatter)");
2946

30-
private final JavaTemplate toDateTemplate = JavaTemplate.builder("Date.from(#{any(java.time.ZonedDateTime)}.toInstant())")
47+
private final JavaTemplate equalsTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.equals(#{any(java.lang.Object)})").build();
48+
private final JavaTemplate getZoneTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.getZone()").build();
49+
private final JavaTemplate isAfterLongTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isAfter(Instant.ofEpochMilli(#{any(long)}).atZone(ZoneId.systemDefault()))")
50+
.imports(JAVA_INSTANT, JAVA_ZONE_ID).build();
51+
private final JavaTemplate isAfterLongTemplateWithInstant = JavaTemplate.builder("#{any(" + JAVA_INSTANT + ")}.isAfter(Instant.ofEpochMilli(#{any(long)}))")
52+
.imports(JAVA_INSTANT).build();
53+
private final JavaTemplate isAfterTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isAfter(#{any(" + JAVA_DATE_TIME + ")})").build();
54+
private final JavaTemplate isAfterTemplateWithInstant = JavaTemplate.builder("#{any(" + JAVA_INSTANT + ")}.isAfter(#{any(" + JAVA_INSTANT + ")})").build();
55+
private final JavaTemplate isBeforeLongTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isBefore(Instant.ofEpochMilli(#{any(long)}).atZone(ZoneId.systemDefault()))")
56+
.imports(JAVA_INSTANT, JAVA_ZONE_ID).build();
57+
private final JavaTemplate isBeforeLongTemplateWithInstant = JavaTemplate.builder("#{any(" + JAVA_INSTANT + ")}.isBefore(Instant.ofEpochMilli(#{any(long)}))")
58+
.imports(JAVA_INSTANT).build();
59+
private final JavaTemplate isBeforTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isBefore(#{any(" + JAVA_DATE_TIME + ")})").build();
60+
private final JavaTemplate isBeforeTemplateWithInstant = JavaTemplate.builder("#{any(" + JAVA_INSTANT + ")}.isBefore(#{any(" + JAVA_INSTANT + ")})").build();
61+
private final JavaTemplate isBeforeNowTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isBefore(ZonedDateTime.now())")
62+
.imports(JAVA_DATE_TIME).build();
63+
private final JavaTemplate isEqualLongTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isEqual(Instant.ofEpochMilli(#{any(long)}).atZone(ZoneId.systemDefault()))")
64+
.imports(JAVA_INSTANT, JAVA_ZONE_ID).build();
65+
private final JavaTemplate isEqualReadableInstantTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.isEqual(#{any(" + JAVA_DATE_TIME + ")})").build();
66+
private final JavaTemplate toDateTemplate = JavaTemplate.builder("Date.from(#{any(" + JAVA_DATE_TIME + ")}.toInstant())")
3167
.imports(JAVA_UTIL_DATE)
3268
.build();
69+
private final JavaTemplate toInstantTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.toInstant()").build();
70+
private final JavaTemplate toStringTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.toString()").build();
71+
private final JavaTemplate toStringFormatterTemplate = JavaTemplate.builder("#{any(" + JAVA_DATE_TIME + ")}.format(#{any(" + JAVA_TIME_FORMATTER + ")})").build();
3372

73+
@Getter
3474
private final List<MethodTemplate> templates = new ArrayList<MethodTemplate>() {
3575
{
76+
add(new MethodTemplate(equals, equalsTemplate));
77+
add(new MethodTemplate(getZone, getZoneTemplate));
78+
add(new MethodTemplate(isAfterLong, isAfterLongTemplate));
79+
add(new MethodTemplate(isAfterLong, isAfterLongTemplateWithInstant));
80+
add(new MethodTemplate(isAfter, isAfterTemplate));
81+
add(new MethodTemplate(isAfter, isAfterTemplateWithInstant));
82+
add(new MethodTemplate(isBeforeLong, isBeforeLongTemplate));
83+
add(new MethodTemplate(isBeforeLong, isBeforeLongTemplateWithInstant));
84+
add(new MethodTemplate(isBefore, isBeforTemplate));
85+
add(new MethodTemplate(isBefore, isBeforeTemplateWithInstant));
86+
add(new MethodTemplate(isBeforeNow, isBeforeNowTemplate));
87+
add(new MethodTemplate(isEqualLong, isEqualLongTemplate));
88+
add(new MethodTemplate(isEqualReadableInstant, isEqualReadableInstantTemplate));
3689
add(new MethodTemplate(toDate, toDateTemplate));
90+
add(new MethodTemplate(toInstant, toInstantTemplate));
91+
add(new MethodTemplate(toString, toStringTemplate));
92+
add(new MethodTemplate(toStringFormatter, toStringFormatterTemplate));
3793
}
3894
};
3995

40-
public static List<MethodTemplate> getTemplates() {
41-
return new AbstractInstantTemplates().templates;
96+
@Override
97+
public boolean matchesMethodCall(MethodCall method, MethodTemplate template) {
98+
if (method instanceof J.NewClass) {
99+
return true;
100+
}
101+
Expression select = ((J.MethodInvocation) method).getSelect();
102+
if (select != null && select.getType() != null && select.getType().isAssignableFrom(Pattern.compile(JODA_INSTANT))) {
103+
return Arrays.asList(
104+
isAfterLongTemplateWithInstant,
105+
isAfterTemplateWithInstant,
106+
isBeforeLongTemplateWithInstant,
107+
isBeforeTemplateWithInstant
108+
).contains(template.getTemplate());
109+
}
110+
return true;
42111
}
43112
}

0 commit comments

Comments
 (0)