-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WINDUPRULE-1041 jakarta cdi to quarkus rules (#1040)
* WINDUPRULE-1041 Work in progress * Update jakarta-cdi-to-quarkus.windup.test.xml attempt to fix test failures * Winduprule 1041 (#9) * cgi to quarkus rules for jakarta classes * remove failing groovy tests --------- Co-authored-by: Phil Cattanach <[email protected]> Co-authored-by: Mark Brophy <[email protected]>
- Loading branch information
1 parent
fa0bfa5
commit 31dd0b8
Showing
17 changed files
with
591 additions
and
12 deletions.
There are no files selected for viewing
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
Binary file not shown.
Binary file added
BIN
+148 KB
rules/rules-reviewed/quarkus/api-jars/jakarta.enterprise.cdi-api-4.0.0.jar
Binary file not shown.
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
178 changes: 178 additions & 0 deletions
178
rules/rules-reviewed/quarkus/java-ee/jakarta-cdi-to-quarkus.windup.groovy
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,178 @@ | ||
package quarkus.javaee | ||
|
||
import org.jboss.windup.ast.java.data.TypeReferenceLocation | ||
import org.jboss.windup.config.GraphRewrite | ||
import org.jboss.windup.config.Variables | ||
import org.jboss.windup.config.metadata.TechnologyReference | ||
import org.jboss.windup.config.operation.Iteration | ||
import org.jboss.windup.config.operation.iteration.AbstractIterationOperation | ||
import org.jboss.windup.config.query.Query | ||
import org.jboss.windup.config.query.QueryPropertyComparisonType | ||
import org.jboss.windup.graph.model.FileLocationModel | ||
import org.jboss.windup.graph.model.FileReferenceModel | ||
import org.jboss.windup.graph.model.ProjectModel | ||
import org.jboss.windup.graph.model.WindupVertexFrame | ||
import org.jboss.windup.graph.model.resource.FileModel | ||
import org.jboss.windup.reporting.category.IssueCategory | ||
import org.jboss.windup.reporting.category.IssueCategoryRegistry | ||
import org.jboss.windup.reporting.config.Hint | ||
import org.jboss.windup.reporting.config.Link | ||
import org.jboss.windup.rules.apps.java.condition.JavaClass | ||
import org.jboss.windup.rules.apps.java.condition.annotation.AnnotationTypeCondition | ||
import org.jboss.windup.rules.apps.java.scan.ast.annotations.JavaAnnotationTypeReferenceModel | ||
import org.jboss.windup.rules.apps.xml.condition.XmlFile | ||
import org.ocpsoft.rewrite.config.And | ||
import org.ocpsoft.rewrite.config.Or | ||
import org.ocpsoft.rewrite.context.EvaluationContext | ||
|
||
import java.util.stream.Collectors | ||
import java.util.stream.StreamSupport | ||
|
||
final IssueCategory potentialIssueCategory = new IssueCategoryRegistry().getByID(IssueCategoryRegistry.POTENTIAL) | ||
final Link guideLink = Link.to("Quarkus - Guides", "https://quarkus.io/guides/cdi-reference") | ||
final Link cdiSpecLink = Link.to("CDI 2.0 - Scopes: Default scope", "https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#default_scope") | ||
|
||
static boolean matchesProject(GraphRewrite event, FileLocationModel payload) { | ||
final Iterable<? extends WindupVertexFrame> previouslyFound = Optional.ofNullable(Variables.instance(event).findVariable("discard")).orElse(Collections.emptySet()) | ||
final Set<ProjectModel> projectModels = StreamSupport.stream(previouslyFound.spliterator(), false) | ||
.map { | ||
if (it instanceof FileReferenceModel) return ((FileReferenceModel) it).getFile().getProjectModel() | ||
else if (it instanceof FileModel) return ((FileModel) it).getProjectModel() | ||
else return null | ||
} | ||
.collect (Collectors.toSet()) | ||
final boolean matchesProject = projectModels.isEmpty() || projectModels.stream().anyMatch{payload.getFile().belongsToProject(it)} | ||
return matchesProject | ||
} | ||
|
||
ruleSet("jakarta-cdi-to-quarkus-groovy") | ||
.addSourceTechnology(new TechnologyReference("java-ee", null)) | ||
.addTargetTechnology(new TechnologyReference("quarkus", null)) | ||
// this rule si required for Windup to know about storing data related to the classes involved in the | ||
// `when` condition because useful later on in the `perform` step of the next rule | ||
.addRule() | ||
.when( | ||
Or.any( | ||
JavaClass.references("jakarta.enterprise.context.{scope}").at(TypeReferenceLocation.ANNOTATION).as("placeholder1"), | ||
JavaClass.references("jakarta.inject.Singleton").at(TypeReferenceLocation.ANNOTATION).as("placeholder2"), | ||
) | ||
) | ||
.where("scope").matches("(ApplicationScoped|ConversationScoped|Dependent|RequestScoped|SessionScoped)") | ||
.withId("jakarta-cdi-to-quarkus-groovy-00000") | ||
.addRule() | ||
.when( | ||
JavaClass.references("jakarta.inject.Inject").at(TypeReferenceLocation.ANNOTATION).as("main") | ||
) | ||
.perform( | ||
Iteration.over("main") | ||
.perform( | ||
new AbstractIterationOperation<JavaAnnotationTypeReferenceModel>() { | ||
public static final String FROM_FILES_IN_PROJECT = "filesInProject" | ||
public static final String INJECT_CLASS_DECLARATION = "injectClassDeclaration" | ||
|
||
void perform(GraphRewrite event, EvaluationContext context, JavaAnnotationTypeReferenceModel payload) { | ||
final String annotatedClass = payload.getAnnotatedType().getResolvedSourceSnippit() | ||
final boolean injectedClassHasScopeAnnotations = | ||
JavaClass.references(annotatedClass) | ||
.at(TypeReferenceLocation.TYPE) | ||
.annotationMatches(new AnnotationTypeCondition("jakarta.enterprise.context.(ApplicationScoped|ConversationScoped|Dependent|RequestScoped|SessionScoped)")) | ||
.as("discard") | ||
.evaluate(event, context) | ||
final boolean injectedClassHasSingletonAnnotations = | ||
JavaClass.references(annotatedClass) | ||
.at(TypeReferenceLocation.TYPE) | ||
.annotationMatches(new AnnotationTypeCondition("jakarta.inject.Singleton")) | ||
.as("discardAsWell") | ||
.evaluate(event, context) | ||
if (!injectedClassHasScopeAnnotations && !injectedClassHasSingletonAnnotations) { | ||
// first of all select only the file belonging to the same root project as the payload | ||
// to reduce (i.e. optimize) the number of files found from the second query | ||
final FileModel fileModel = payload.getFile() | ||
final String filePath = fileModel.getProjectModel().getRootFileModel().getPrettyPath() + "/" | ||
Query.fromType(FileModel.class).withProperty(FileModel.FILE_PATH, QueryPropertyComparisonType.CONTAINS_TOKEN, filePath).as(FROM_FILES_IN_PROJECT).evaluate(event, context) | ||
//Query.fromType(FileModel.class).withProperty(JavaClass.from | ||
JavaClass.from(FROM_FILES_IN_PROJECT).references(annotatedClass).at(TypeReferenceLocation.TYPE).as(INJECT_CLASS_DECLARATION).evaluate(event, context) | ||
Iteration.over(INJECT_CLASS_DECLARATION) | ||
.perform( | ||
((Hint) Hint.titled("Injected class is missing scope annotation") | ||
.withText(""" | ||
A class injected but missing an annotation to define its scope type is not going to be discovered from Quarkus. | ||
Consider adding the `@Dependent` scope which is the default scope for a bean which does not explicitly declare a scope type (ref. [CDI 2.0 - Scopes: Default scope](https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#default_scope)) | ||
""") | ||
.withIssueCategory(potentialIssueCategory) | ||
.with(guideLink) | ||
.with(cdiSpecLink) | ||
.withEffort(1)) | ||
) | ||
.endIteration() | ||
} | ||
} | ||
} | ||
) | ||
.endIteration() | ||
) | ||
.withId("jakarta-cdi-to-quarkus-groovy-00010") | ||
// suggest to replace cdi-api TRANSITIVE dependency if no Quarkus dependency has been already added and 'javax.enterprise.{packages}.{*}' package is used somewhere in the code | ||
.addRule() | ||
.when( | ||
And.all( | ||
JavaClass.references("jakarta.enterprise.{packages}.{*}").at(TypeReferenceLocation.ANNOTATION).as("discard"), | ||
XmlFile.matchesXpath("/m:project/m:dependencies[count(m:dependency/m:artifactId[contains(., 'cdi-api')]) = 0 and count(m:dependency/m:artifactId[contains(., 'quarkus-')]) = 0]") | ||
.inFile("pom.xml") | ||
.namespace("m", "http://maven.apache.org/POM/4.0.0") | ||
.as("dependencies-section") | ||
) | ||
) | ||
.perform( | ||
Iteration.over("dependencies-section").perform( | ||
new AbstractIterationOperation<FileLocationModel>() { | ||
void perform(GraphRewrite event, EvaluationContext context, FileLocationModel payload) { | ||
if (matchesProject(event, payload)) { | ||
((Hint) Hint.titled("Remove jakarta.enterprise:cdi-api transitive dependency") | ||
.withText(""" | ||
Transitive dependency `jakarta.enterprise:cdi-api` should be removed and the `io.quarkus:quarkus-arc` dependency added. | ||
""") | ||
.withIssueCategory(potentialIssueCategory) | ||
.with(guideLink) | ||
.withEffort(1) | ||
).performParameterized(event, context, payload) | ||
} | ||
} | ||
} | ||
) | ||
.endIteration() | ||
) | ||
.where("packages").matches("(context|event|inject|util)") | ||
.withId("jakarta-cdi-to-quarkus-groovy-00020") | ||
// suggest to replace javax.inject TRANSITIVE dependency if no Quarkus dependency has been already added and 'javax.inject' package is used somewhere in the code | ||
.addRule() | ||
.when( | ||
And.all( | ||
JavaClass.references("jakarta.inject.{*}").at(TypeReferenceLocation.ANNOTATION).as("discard"), | ||
XmlFile.matchesXpath("/m:project/m:dependencies[count(m:dependency/m:artifactId[contains(., 'jakarta.inject')]) = 0 and count(m:dependency/m:artifactId[contains(., 'quarkus-')]) = 0]") | ||
.inFile("pom.xml") | ||
.namespace("m", "http://maven.apache.org/POM/4.0.0") | ||
.as("dependencies-section") | ||
) | ||
) | ||
.perform( | ||
Iteration.over("dependencies-section").perform( | ||
new AbstractIterationOperation<FileLocationModel>() { | ||
void perform(GraphRewrite event, EvaluationContext context, FileLocationModel payload) { | ||
if (matchesProject(event, payload)) { | ||
((Hint) Hint.titled("Remove jakarta.inject:jakarta.inject transitive dependency") | ||
.withText(""" | ||
The application has a transitive `javax.inject:javax.inject` dependency because at least one Java class that imports from the `javax.inject` has been found. | ||
The direct dependency injecting `javax.inject:javax.inject` should be identified and replaced with the `io.quarkus:quarkus-arc` dependency. | ||
""") | ||
.withIssueCategory(potentialIssueCategory) | ||
.with(guideLink) | ||
.withEffort(1) | ||
).performParameterized(event, context, payload) | ||
} | ||
} | ||
} | ||
) | ||
.endIteration() | ||
) | ||
.withId("jakarta-cdi-to-quarkus-groovy-00030") |
97 changes: 97 additions & 0 deletions
97
rules/rules-reviewed/quarkus/java-ee/jakarta-cdi-to-quarkus.windup.xml
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,97 @@ | ||
<?xml version="1.0"?> | ||
<ruleset xmlns="http://windup.jboss.org/schema/jboss-ruleset" id="jakarta-cdi-to-quarkus" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd"> | ||
<metadata> | ||
<description> | ||
This ruleset gives hints to migrate CDI usage to Quarkus | ||
</description> | ||
<dependencies> | ||
<addon id="org.jboss.windup.rules,windup-rules-javaee,3.0.0.Final" /> | ||
<addon id="org.jboss.windup.rules,windup-rules-java,3.0.0.Final" /> | ||
<addon id="org.jboss.windup.rules,windup-rules-xml,3.0.0.Final" /> | ||
</dependencies> | ||
<sourceTechnology id="java-ee" /> | ||
<targetTechnology id="quarkus" /> | ||
</metadata> | ||
<rules> | ||
<rule id="jakarta-cdi-to-quarkus-00000"> | ||
<when> | ||
<xmlfile in="pom.xml" matches="/m:project/m:dependencies/m:dependency[m:artifactId/text() = 'jakarta.enterprise.cdi-api' and m:groupId/text() = 'jakarta.enterprise' and (count(../m:dependency/m:groupId[contains(., 'io.quarkus')]) = 0)]" > | ||
<namespace prefix="m" uri="http://maven.apache.org/POM/4.0.0" /> | ||
</xmlfile> | ||
</when> | ||
<perform> | ||
<hint title="Replace jakarta.enterprise:jakarta.enterprise.cdi-api dependency" effort="1" category-id="mandatory"> | ||
<message> | ||
Dependency `jakarta.enterprise:jakarta.enterprise.cdi-api` has to be replaced with `io.quarkus:quarkus-arc` artifact. | ||
</message> | ||
<link title="Quarkus - Guide" href="https://quarkus.io/guides/cdi-reference" /> | ||
</hint> | ||
</perform> | ||
</rule> | ||
<!-- suggest to replace jakarta.inject dependency if no Quarkus dependency has been already added --> | ||
<rule id="jakarta-cdi-to-quarkus-00020"> | ||
<when> | ||
<xmlfile in="pom.xml" matches="/m:project/m:dependencies/m:dependency[m:artifactId/text() = 'jakarta.inject-api' and m:groupId/text() = 'jakarta.inject' and (count(../m:dependency/m:groupId[contains(., 'io.quarkus')]) = 0)]" > | ||
<namespace prefix="m" uri="http://maven.apache.org/POM/4.0.0" /> | ||
</xmlfile> | ||
</when> | ||
<perform> | ||
<hint title="Replace jakarta.inject:jakarta.inject-api dependency" effort="1" category-id="mandatory"> | ||
<message> | ||
Dependency `jakarta.inject:jakarta.inject-api` has to be replaced with `io.quarkus:quarkus-arc` artifact. | ||
</message> | ||
<link title="Quarkus - Guide" href="https://quarkus.io/guides/cdi-reference" /> | ||
</hint> | ||
</perform> | ||
</rule> | ||
<!-- explain beans.xml descriptor content is ignored --> | ||
<rule id="jakarta-cdi-to-quarkus-00030"> | ||
<when> | ||
<xmlfile in="beans.xml" matches="/b:beans" as="root"> | ||
<namespace prefix="b" uri="https://jakarta.ee/xml/ns/jakartaee" /> | ||
</xmlfile> | ||
</when> | ||
<perform> | ||
<iteration over="root"> | ||
<hint title="`beans.xml` descriptor content is ignored" effort="3" category-id="potential"> | ||
<message> | ||
The `beans.xml` descriptor content is ignored and it could be removed from the application. | ||
Refer to the guide referenced below to check the supported CDI feature in Quarkus. | ||
</message> | ||
<link title="Quarkus - Guide" href="https://quarkus.io/guides/cdi-reference#limitations" /> | ||
</hint> | ||
</iteration> | ||
</perform> | ||
</rule> | ||
<rule id="jakarta-cdi-to-quarkus-00040"> | ||
<when> | ||
<javaclass references="jakarta.enterprise.inject.Produces"> | ||
<location>ANNOTATION</location> | ||
</javaclass> | ||
</when> | ||
<perform> | ||
<hint title="Producer annotation no longer required" effort="1" category-id="potential"> | ||
<message>In Quarkus you can skip the @Produces annotation completely if the producer method is annotated with a scope annotation, a stereotype or a qualifier.. | ||
This field could be accessed using a `@Named` getter method instead. | ||
</message> | ||
<link title="Quarkus Simplified Producer Method Declaration" href="https://quarkus.io/guides/cdi-reference#simplified-producer-method-declaration"/> | ||
</hint> | ||
</perform> | ||
</rule> | ||
<rule id="jakarta-cdi-to-quarkus-00050"> | ||
<when> | ||
<javaclass references="jakarta.ejb.Stateless"> | ||
<location>ANNOTATION</location> | ||
</javaclass> | ||
</when> | ||
<perform> | ||
<hint title="Stateless annotation can be replaced with scope" effort="1" category-id="potential"> | ||
<message>The Stateless EJBs can be converted to a cdi bean by replacing the `@Stateless` annotation with a scope eg `@ApplicationScoped` | ||
</message> | ||
<link title="Quarkus CDI reference" href="https://quarkus.io/guides/cdi-reference"/> | ||
</hint> | ||
</perform> | ||
</rule> | ||
</rules> | ||
</ruleset> |
Oops, something went wrong.