Skip to content

Commit e381a98

Browse files
Handle class-form @Type for boolean legacy types in MigrateBooleanMappings (#85)
1 parent 504d4e5 commit e381a98

2 files changed

Lines changed: 145 additions & 34 deletions

File tree

src/main/java/org/openrewrite/hibernate/MigrateBooleanMappings.java

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.openrewrite.hibernate;
1717

1818
import lombok.Getter;
19+
import org.jspecify.annotations.Nullable;
1920
import org.openrewrite.ExecutionContext;
2021
import org.openrewrite.Preconditions;
2122
import org.openrewrite.Recipe;
@@ -26,6 +27,7 @@
2627
import org.openrewrite.java.search.UsesType;
2728
import org.openrewrite.java.tree.Expression;
2829
import org.openrewrite.java.tree.J;
30+
import org.openrewrite.java.tree.JavaType;
2931
import org.openrewrite.java.tree.TypeUtils;
3032

3133
import java.util.HashMap;
@@ -37,12 +39,17 @@ public class MigrateBooleanMappings extends Recipe {
3739
private static final Map<String, String> REPLACEMENTS = new HashMap<>();
3840

3941
static {
40-
REPLACEMENTS.put("org.hibernate.type.TrueFalseBooleanType", "TrueFalseConverter");
42+
// true/false boolean
4143
REPLACEMENTS.put("true_false", "TrueFalseConverter");
42-
REPLACEMENTS.put("org.hibernate.type.YesNoBooleanType", "YesNoConverter");
44+
REPLACEMENTS.put("org.hibernate.type.TrueFalseType", "TrueFalseConverter");
45+
REPLACEMENTS.put("org.hibernate.type.TrueFalseBooleanType", "TrueFalseConverter");
46+
// yes/no boolean
4347
REPLACEMENTS.put("yes_no", "YesNoConverter");
44-
REPLACEMENTS.put("org.hibernate.type.NumericBooleanType", "NumericBooleanConverter");
48+
REPLACEMENTS.put("org.hibernate.type.YesNoType", "YesNoConverter");
49+
REPLACEMENTS.put("org.hibernate.type.YesNoBooleanType", "YesNoConverter");
50+
// numeric boolean
4551
REPLACEMENTS.put("numeric_boolean", "NumericBooleanConverter");
52+
REPLACEMENTS.put("org.hibernate.type.NumericBooleanType", "NumericBooleanConverter");
4653
}
4754

4855
@Getter
@@ -61,47 +68,74 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct
6168
if (!TypeUtils.isOfClassType(ann.getType(), "org.hibernate.annotations.Type")) {
6269
return ann;
6370
}
64-
6571
List<Expression> args = ann.getArguments();
6672
if (args == null) {
6773
return ann;
6874
}
6975

70-
Object type = args.stream()
71-
.filter(exp -> {
72-
if (exp instanceof J.Assignment) {
73-
J.Identifier variable = (J.Identifier) ((J.Assignment) exp).getVariable();
74-
return "type".equals(variable.getSimpleName());
75-
}
76-
return false;
77-
})
78-
.findFirst()
79-
.map(exp -> {
80-
Expression value = ((J.Assignment) exp).getAssignment();
81-
if (value instanceof J.Literal) {
82-
return ((J.Literal) value).getValue();
83-
}
84-
return null;
85-
})
86-
.orElse(null);
87-
88-
if (type instanceof String && REPLACEMENTS.containsKey((String) type)) {
89-
String converterName = REPLACEMENTS.get((String) type);
90-
String converterFQN = String.format("org.hibernate.type.%s", converterName);
76+
String converterName = null;
77+
String legacyClassFQN = null;
78+
for (Expression arg : args) {
79+
String key;
80+
if (arg instanceof J.Assignment) {
81+
J.Assignment a = (J.Assignment) arg;
82+
if (!(a.getVariable() instanceof J.Identifier)) {
83+
continue;
84+
}
85+
String attr = ((J.Identifier) a.getVariable()).getSimpleName();
86+
if ("type".equals(attr) && a.getAssignment() instanceof J.Literal) {
87+
Object v = ((J.Literal) a.getAssignment()).getValue();
88+
key = v instanceof String ? (String) v : null;
89+
} else if ("value".equals(attr)) {
90+
legacyClassFQN = classRefFQN(a.getAssignment());
91+
key = legacyClassFQN;
92+
} else {
93+
continue;
94+
}
95+
} else if (args.size() == 1) {
96+
legacyClassFQN = classRefFQN(arg);
97+
key = legacyClassFQN;
98+
} else {
99+
continue;
100+
}
101+
if (key != null) {
102+
converterName = REPLACEMENTS.get(key);
103+
if (converterName != null) {
104+
break;
105+
}
106+
}
107+
}
108+
if (converterName == null) {
109+
return ann;
110+
}
91111

92-
ann = JavaTemplate.builder(String.format("@Convert(converter = %s.class)", converterName))
93-
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "hibernate-core-6+", "jakarta.persistence-api"))
94-
.imports(converterFQN, "jakarta.persistence.Convert")
95-
.contextSensitive()
96-
.build().apply(getCursor(), ann.getCoordinates().replace());
112+
String converterFQN = "org.hibernate.type." + converterName;
113+
ann = JavaTemplate.builder("@Convert(converter = " + converterName + ".class)")
114+
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "hibernate-core-6+", "jakarta.persistence-api"))
115+
.imports(converterFQN, "jakarta.persistence.Convert")
116+
.contextSensitive()
117+
.build().apply(getCursor(), ann.getCoordinates().replace());
97118

98-
maybeRemoveImport("org.hibernate.annotations.Type");
99-
maybeAddImport("jakarta.persistence.Convert");
100-
maybeAddImport(converterFQN);
119+
maybeRemoveImport("org.hibernate.annotations.Type");
120+
if (legacyClassFQN != null) {
121+
maybeRemoveImport(legacyClassFQN);
101122
}
102-
123+
maybeAddImport("jakarta.persistence.Convert");
124+
maybeAddImport(converterFQN);
103125
return ann;
104126
}
127+
128+
private @Nullable String classRefFQN(Expression expr) {
129+
if (!(expr instanceof J.FieldAccess)) {
130+
return null;
131+
}
132+
J.FieldAccess fa = (J.FieldAccess) expr;
133+
if (!"class".equals(fa.getName().getSimpleName())) {
134+
return null;
135+
}
136+
JavaType.FullyQualified fqn = TypeUtils.asFullyQualified(fa.getTarget().getType());
137+
return fqn == null ? null : fqn.getFullyQualifiedName();
138+
}
105139
}
106140
);
107141
}

src/test/java/org/openrewrite/hibernate/MigrateBooleanMappingsTest.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,83 @@ public Object getSomeObject() {
231231
);
232232
}
233233

234+
@CsvSource(textBlock = """
235+
NumericBooleanType , NumericBooleanConverter
236+
TrueFalseType , TrueFalseConverter
237+
YesNoType , YesNoConverter
238+
""")
239+
@ParameterizedTest
240+
void classForm_shouldBeReplaced(String legacyType, String converter) {
241+
//language=java
242+
rewriteRun(
243+
spec -> spec.parser(JavaParser.fromJavaVersion()
244+
.classpathFromResources(new InMemoryExecutionContext(),
245+
"hibernate-core-5+", "hibernate-core-6+", "jakarta.persistence-api")),
246+
java(
247+
"""
248+
import jakarta.persistence.Column;
249+
import org.hibernate.annotations.Type;
250+
import org.hibernate.type.%1$s;
251+
252+
public class SomeClass {
253+
254+
@Column(name = "IS_SOMETHING")
255+
@Type(%1$s.class)
256+
private boolean isSomething;
257+
}
258+
""".formatted(legacyType),
259+
"""
260+
import jakarta.persistence.Column;
261+
import jakarta.persistence.Convert;
262+
import org.hibernate.type.%2$s;
263+
264+
public class SomeClass {
265+
266+
@Column(name = "IS_SOMETHING")
267+
@Convert(converter = %2$s.class)
268+
private boolean isSomething;
269+
}
270+
""".formatted(legacyType, converter)
271+
)
272+
);
273+
}
274+
275+
@Test
276+
void valueAttribute_classForm_shouldBeReplaced() {
277+
//language=java
278+
rewriteRun(
279+
spec -> spec.parser(JavaParser.fromJavaVersion()
280+
.classpathFromResources(new InMemoryExecutionContext(),
281+
"hibernate-core-5+", "hibernate-core-6+", "jakarta.persistence-api")),
282+
java(
283+
"""
284+
import jakarta.persistence.Column;
285+
import org.hibernate.annotations.Type;
286+
import org.hibernate.type.NumericBooleanType;
287+
288+
public class SomeClass {
289+
290+
@Column(name = "IS_SOMETHING")
291+
@Type(value = NumericBooleanType.class)
292+
private boolean isSomething;
293+
}
294+
""",
295+
"""
296+
import jakarta.persistence.Column;
297+
import jakarta.persistence.Convert;
298+
import org.hibernate.type.NumericBooleanConverter;
299+
300+
public class SomeClass {
301+
302+
@Column(name = "IS_SOMETHING")
303+
@Convert(converter = NumericBooleanConverter.class)
304+
private boolean isSomething;
305+
}
306+
"""
307+
)
308+
);
309+
}
310+
234311
@Test
235312
void noChange_shouldBeMade_whenTypeIsClass() {
236313
//language=java

0 commit comments

Comments
 (0)