diff --git a/build.gradle.kts b/build.gradle.kts index 8dc20b9..c0d9636 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,6 +19,8 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:latest.release") - testRuntimeOnly("org.hibernate:hibernate-core:5.6.15.Final") + testRuntimeOnly("org.hibernate:hibernate-core:6.4.4.Final") + testRuntimeOnly("javax.xml.bind:jaxb-api:2.3.1") + testRuntimeOnly("javax.persistence:javax.persistence-api:2.2") testRuntimeOnly("jakarta.persistence:jakarta.persistence-api:3.1.0") } diff --git a/src/main/java/org/openrewrite/hibernate/MigrateBooleanMappings.java b/src/main/java/org/openrewrite/hibernate/MigrateBooleanMappings.java new file mode 100644 index 0000000..5997a67 --- /dev/null +++ b/src/main/java/org/openrewrite/hibernate/MigrateBooleanMappings.java @@ -0,0 +1,112 @@ +/* + * 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.hibernate;
+
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.Expression;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.TypeUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MigrateBooleanMappings extends Recipe {
+
+ private static final 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.hibernate;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+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 MigrateBooleanMappingsTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new MigrateBooleanMappings())
+ .parser(JavaParser.fromJavaVersion()
+ .classpath("hibernate-core", "jakarta.persistence-api")
+ );
+ }
+
+ @DocumentExample
+ @Test
+ void allMappings_shouldBeReplaced() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import jakarta.persistence.Column;
+ import org.hibernate.annotations.Type;
+
+ public class SomeClass {
+
+ @Column(name = "IS_SOMETHING")
+ @Type(type = "true_false")
+ private boolean isSomething;
+
+ @Column(name = "IS_SOMETHING_ELSE")
+ @Type(type = "org.hibernate.type.YesNoBooleanType")
+ private boolean isSomethingElse;
+
+ }
+ """,
+ """
+ import jakarta.persistence.Column;
+ import jakarta.persistence.Convert;
+ import org.hibernate.type.TrueFalseConverter;
+ import org.hibernate.type.YesNoConverter;
+
+ public class SomeClass {
+
+ @Column(name = "IS_SOMETHING")
+ @Convert(converter = TrueFalseConverter.class)
+ private boolean isSomething;
+
+ @Column(name = "IS_SOMETHING_ELSE")
+ @Convert(converter = YesNoConverter.class)
+ private boolean isSomethingElse;
+
+ }
+ """
+ )
+ );
+ }
+
+ @ParameterizedTest
+ @CsvSource(textBlock = """
+ numeric_boolean , NumericBooleanConverter
+ true_false , TrueFalseConverter
+ yes_no , YesNoConverter
+ org.hibernate.type.YesNoBooleanType , YesNoConverter
+ org.hibernate.type.TrueFalseBooleanType , TrueFalseConverter
+ org.hibernate.type.NumericBooleanType , NumericBooleanConverter
+ """)
+ void mapping_shouldBeReplaced_whenMethodIsAnnotated(String usertype, String converter) {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import jakarta.persistence.Column;
+ import org.hibernate.annotations.Type;
+
+ public class SomeClass {
+
+ private boolean isSomething;
+
+ @Column(name = "IS_SOMETHING")
+ @Type(type = "%s")
+ public boolean isSomething() {
+ return isSomething;
+ }
+ }
+ """.formatted(usertype),
+ """
+ import jakarta.persistence.Column;
+ import jakarta.persistence.Convert;
+ import org.hibernate.type.%1$s;
+
+ public class SomeClass {
+
+ private boolean isSomething;
+
+ @Column(name = "IS_SOMETHING")
+ @Convert(converter = %1$s.class)
+ public boolean isSomething() {
+ return isSomething;
+ }
+ }
+ """.formatted(converter)
+ )
+ );
+ }
+
+ @ParameterizedTest
+ @CsvSource(textBlock = """
+ numeric_boolean , NumericBooleanConverter
+ true_false , TrueFalseConverter
+ yes_no , YesNoConverter
+ org.hibernate.type.YesNoBooleanType , YesNoConverter
+ org.hibernate.type.TrueFalseBooleanType , TrueFalseConverter
+ org.hibernate.type.NumericBooleanType , NumericBooleanConverter
+ """)
+ void trueFalseMapping_shouldBeReplaced_whenFieldIsAnnotated(String usertype, String converter) {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import jakarta.persistence.Column;
+ import org.hibernate.annotations.Type;
+
+ public class SomeClass {
+
+ @Column(name = "IS_SOMETHING")
+ @Type(type = "%s")
+ private boolean isSomething;
+
+ public boolean isSomething() {
+ return isSomething;
+ }
+ }
+ """.formatted(usertype),
+ """
+ import jakarta.persistence.Column;
+ import jakarta.persistence.Convert;
+ import org.hibernate.type.%1$s;
+
+ public class SomeClass {
+
+ @Column(name = "IS_SOMETHING")
+ @Convert(converter = %1$s.class)
+ private boolean isSomething;
+
+ public boolean isSomething() {
+ return isSomething;
+ }
+ }
+ """.formatted(converter)
+ )
+ );
+ }
+
+ @Test
+ void typeImport_shouldNotBeRemoved_ifUsedElsewhere() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.hibernate.annotations.Type;
+ import jakarta.persistence.Column;
+
+ public class SomeClass {
+
+ private boolean isSomething;
+ private Object someObject;
+
+ @Column(name = "IS_SOMETHING")
+ @Type(type = "true_false")
+ public boolean isSomething() {
+ return isSomething;
+ }
+
+ @Column(name = "SOME_OBJECT")
+ @Type(type = Object.class)
+ public Object getSomeObject() {
+ return someObject;
+ }
+ }
+ """,
+ """
+ import jakarta.persistence.Convert;
+ import org.hibernate.annotations.Type;
+ import org.hibernate.type.TrueFalseConverter;
+ import jakarta.persistence.Column;
+
+ public class SomeClass {
+
+ private boolean isSomething;
+ private Object someObject;
+
+ @Column(name = "IS_SOMETHING")
+ @Convert(converter = TrueFalseConverter.class)
+ public boolean isSomething() {
+ return isSomething;
+ }
+
+ @Column(name = "SOME_OBJECT")
+ @Type(type = Object.class)
+ public Object getSomeObject() {
+ return someObject;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noChange_shouldBeMade_whenTypeIsClass() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.hibernate.annotations.Type;
+ import jakarta.persistence.Column;
+
+ public class SomeClass {
+
+ private Object someObject;
+
+ @Column(name = "SOME_OBJECT")
+ @Type(type = Object.class) // we just need some class, it is not checked
+ public Object getSomeObject() {
+ return someObject;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noChange_shouldBeMade_whenTypeIsNameOfClass() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import org.hibernate.annotations.Type;
+ import jakarta.persistence.Column;
+
+ public class SomeClass {
+
+ private Object someObject;
+
+ @Column(name = "SOME_OBJECT")
+ @Type(type = "java.lang.Object") // we just need some class name, it is not checked
+ public Object getSomeObject() {
+ return someObject;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noChange_shouldBeMade_whenTypeIsBoolean() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import jakarta.persistence.Column;
+ import org.hibernate.annotations.Type;
+
+ public class SomeClass {
+
+ @Column(name = "IS_SOMETHING")
+ @Type(type = "boolean")
+ private boolean isSomething;
+ }
+ """
+ )
+ );
+ }
+
+}