-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Transient annotation to Entity without JPA annotation (#422)
* Add Transient annotation to Entity without JPA annotation * Add comments * Update jpa anno check * Remove line break * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Tim te Beek <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
- Loading branch information
1 parent
ee91666
commit e31312e
Showing
3 changed files
with
317 additions
and
2 deletions.
There are no files selected for viewing
114 changes: 114 additions & 0 deletions
114
src/main/java/org/openrewrite/java/migrate/javax/AddTransientAnnotationToEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* Copyright 2024 the original author or authors. | ||
* <p> | ||
* 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 | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* 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.javax; | ||
|
||
import lombok.EqualsAndHashCode; | ||
import lombok.Value; | ||
import org.openrewrite.*; | ||
import org.openrewrite.java.JavaIsoVisitor; | ||
import org.openrewrite.java.JavaParser; | ||
import org.openrewrite.java.JavaTemplate; | ||
import org.openrewrite.java.search.FindAnnotations; | ||
import org.openrewrite.java.search.UsesType; | ||
import org.openrewrite.java.tree.J; | ||
import org.openrewrite.java.tree.JavaType; | ||
|
||
import java.util.Comparator; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.regex.Pattern; | ||
|
||
@Value | ||
@EqualsAndHashCode(callSuper = false) | ||
public class AddTransientAnnotationToEntity extends ScanningRecipe<AddTransientAnnotationToEntity.EntityAccumulator> { | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return "Unannotated entity attributes require a Transient annotation"; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "In OpenJPA, attributes that are themselves entity classes are not persisted by default. EclipseLink has " + | ||
"a different default behavior and tries to persist these attributes to the database. To keep the OpenJPA " + | ||
"behavior of ignoring unannotated entity attributes, add the `javax.persistence.Transient` annotation to " + | ||
"these attributes in EclipseLink."; | ||
} | ||
|
||
static class EntityAccumulator { | ||
private final Set<JavaType> entityClasses = new HashSet<>(); | ||
|
||
public void addEntity(JavaType type) { | ||
entityClasses.add(type); | ||
} | ||
public boolean isEntity(JavaType type) { | ||
return entityClasses.contains(type); | ||
} | ||
} | ||
|
||
@Override | ||
public EntityAccumulator getInitialValue(ExecutionContext ctx) { | ||
return new EntityAccumulator(); | ||
} | ||
|
||
@Override | ||
public TreeVisitor<?, ExecutionContext> getScanner(EntityAccumulator acc) { | ||
return Preconditions.check( | ||
new UsesType<>("javax.persistence.Entity", true), | ||
new JavaIsoVisitor<ExecutionContext>() { | ||
@Override | ||
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { | ||
if (FindAnnotations.find(classDecl, "javax.persistence.Entity").isEmpty()) { | ||
return classDecl; | ||
} | ||
// Collect @Entity classes | ||
JavaType type = classDecl.getType(); | ||
if (type != null) { | ||
acc.addEntity(type); | ||
} | ||
return classDecl; | ||
} | ||
} | ||
); | ||
} | ||
|
||
@Override | ||
public TreeVisitor<?, ExecutionContext> getVisitor(EntityAccumulator acc) { | ||
return new JavaIsoVisitor<ExecutionContext>() { | ||
@Override | ||
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { | ||
// Exit if attribute is not an Entity class | ||
if (!acc.isEntity(multiVariable.getType())) { | ||
return multiVariable; | ||
} | ||
// Exit if attribute is already JPA annotated | ||
if (multiVariable.getLeadingAnnotations().stream() | ||
.anyMatch(anno -> anno.getType().toString().contains("javax.persistence"))) { | ||
return multiVariable; | ||
} | ||
// Add @Transient annotation | ||
maybeAddImport("javax.persistence.Transient"); | ||
return JavaTemplate.builder("@Transient") | ||
.contextSensitive() | ||
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "javax.persistence-api-2.2")) | ||
.imports("javax.persistence.Transient") | ||
.build() | ||
.apply(getCursor(), multiVariable.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); | ||
} | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
src/test/java/org/openrewrite/java/migrate/javax/AddTransientAnnotationToEntityTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* Copyright 2024 the original author or authors. | ||
* <p> | ||
* 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 | ||
* <p> | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* 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.javax; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.openrewrite.DocumentExample; | ||
import org.openrewrite.InMemoryExecutionContext; | ||
import org.openrewrite.java.JavaParser; | ||
import org.openrewrite.test.RecipeSpec; | ||
import org.openrewrite.test.RewriteTest; | ||
|
||
import static org.openrewrite.java.Assertions.java; | ||
|
||
class AddTransientAnnotationToEntityTest implements RewriteTest { | ||
@Override | ||
public void defaults(RecipeSpec spec) { | ||
spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "javax.persistence-api-2.2")) | ||
.recipe(new AddTransientAnnotationToEntity()); | ||
} | ||
|
||
@Test | ||
@DocumentExample | ||
void addTransient() { | ||
//language=java | ||
rewriteRun( | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
@Entity | ||
public class EntityA { | ||
@Id | ||
private int id; | ||
private EntityB entityReference; | ||
} | ||
""", | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
import javax.persistence.Transient; | ||
@Entity | ||
public class EntityA { | ||
@Id | ||
private int id; | ||
@Transient | ||
private EntityB entityReference; | ||
} | ||
""" | ||
), | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
@Entity | ||
public class EntityB { | ||
@Id | ||
private int id; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void ignoreJpaAnnotatedEntity() { | ||
//language=java | ||
rewriteRun( | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
@Entity | ||
public class EntityA { | ||
@Id | ||
private int id; | ||
@Id | ||
private EntityB entityReference; | ||
} | ||
""" | ||
), | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
@Entity | ||
public class EntityB { | ||
@Id | ||
private int id; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void addTransientOnNonJpaAnnotatedEntity() { | ||
//language=java | ||
rewriteRun( | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
import java.lang.annotation.Documented; | ||
@Entity | ||
public class EntityA { | ||
@Id | ||
private int id; | ||
@Documented | ||
private EntityB entityReference; | ||
} | ||
""", | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
import javax.persistence.Transient; | ||
import java.lang.annotation.Documented; | ||
@Entity | ||
public class EntityA { | ||
@Id | ||
private int id; | ||
@Documented | ||
@Transient | ||
private EntityB entityReference; | ||
} | ||
""" | ||
), | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
@Entity | ||
public class EntityB { | ||
@Id | ||
private int id; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
|
||
@Test | ||
void ignoreNonEntity() { | ||
//language=java | ||
rewriteRun( | ||
java( | ||
""" | ||
import javax.persistence.Entity; | ||
import javax.persistence.Id; | ||
@Entity | ||
public class EntityA { | ||
@Id | ||
private int id; | ||
private NotEntityB entityReference; | ||
} | ||
""" | ||
), | ||
java( | ||
""" | ||
import javax.persistence.Id; | ||
public class NotEntityB { | ||
@Id | ||
private int id; | ||
} | ||
""" | ||
) | ||
); | ||
} | ||
} |