-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WINDUPRULE-945 JavaEE to Quarkus - JAX-RS, pom.xml setup, CDI, Static…
… Resources (#946) * WINDUPRULE-945 JavaEE to Quarkus - JAX-RS, pom.xml setup, CDI, Static Resources * WINDUPRULE-945 cdi-to-quarkus-groovy-00010: Optimized inner queries * WINDUPRULE-945 Fixed new Groovy rules JDK 17 compatibility (cherry picked from commit 4d01695)
- Loading branch information
Showing
29 changed files
with
1,757 additions
and
0 deletions.
There are no files selected for viewing
177 changes: 177 additions & 0 deletions
177
rules/rules-reviewed/quarkus/java-ee/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,177 @@ | ||
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("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("javax.enterprise.context.{scope}").at(TypeReferenceLocation.ANNOTATION).as("placeholder1"), | ||
JavaClass.references("javax.inject.Singleton").at(TypeReferenceLocation.ANNOTATION).as("placeholder2"), | ||
) | ||
) | ||
.where("scope").matches("(ApplicationScoped|ConversationScoped|Dependent|RequestScoped|SessionScoped)") | ||
.withId("cdi-to-quarkus-groovy-00000") | ||
.addRule() | ||
.when( | ||
JavaClass.references("javax.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("javax.enterprise.context.(ApplicationScoped|ConversationScoped|Dependent|RequestScoped|SessionScoped)")) | ||
.as("discard") | ||
.evaluate(event, context) | ||
final boolean injectedClassHasSingletonAnnotations = | ||
JavaClass.references(annotatedClass) | ||
.at(TypeReferenceLocation.TYPE) | ||
.annotationMatches(new AnnotationTypeCondition("javax.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 | ||
if (Query.fromType(FileModel.class).withProperty(FileModel.FILE_PATH, QueryPropertyComparisonType.CONTAINS_TOKEN, payload.getFile().getProjectModel().getRootFileModel().getPrettyPath() + "/").as(FROM_FILES_IN_PROJECT).evaluate(event, context) | ||
&& 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("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("javax.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 javax.enterprise:cdi-api transitive dependency") | ||
.withText(""" | ||
Transitive dependency `javax.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("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("javax.inject.{*}").at(TypeReferenceLocation.ANNOTATION).as("discard"), | ||
XmlFile.matchesXpath("/m:project/m:dependencies[count(m:dependency/m:artifactId[contains(., 'javax.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 javax.inject:javax.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("cdi-to-quarkus-groovy-00030") |
68 changes: 68 additions & 0 deletions
68
rules/rules-reviewed/quarkus/java-ee/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,68 @@ | ||
<?xml version="1.0"?> | ||
<ruleset xmlns="http://windup.jboss.org/schema/jboss-ruleset" id="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="cdi-to-quarkus-00000"> | ||
<when> | ||
<xmlfile in="pom.xml" matches="/m:project/m:dependencies/m:dependency[m:artifactId/text() = 'cdi-api' and m:groupId/text() = 'javax.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 javax.enterprise:cdi-api dependency" effort="1" category-id="mandatory"> | ||
<message> | ||
Dependency `javax.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 javax.inject dependency if no Quarkus dependency has been already added --> | ||
<rule id="cdi-to-quarkus-00020"> | ||
<when> | ||
<xmlfile in="pom.xml" matches="/m:project/m:dependencies/m:dependency[m:artifactId/text() = 'javax.inject' and m:groupId/text() = 'javax.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 javax.inject:javax.inject dependency" effort="1" category-id="mandatory"> | ||
<message> | ||
Dependency `javax.inject:javax.inject` 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="cdi-to-quarkus-00030"> | ||
<when> | ||
<xmlfile in="beans.xml" matches="/b:beans" as="root"> | ||
<namespace prefix="b" uri="http://xmlns.jcp.org/xml/ns/javaee" /> | ||
</xmlfile> | ||
</when> | ||
<perform> | ||
<iteration over="root"> | ||
<hint title="`beans.xml` descriptor content is ignored" effort="3" category-id="potential"> | ||
<message> | ||
`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> | ||
</rules> | ||
</ruleset> |
72 changes: 72 additions & 0 deletions
72
rules/rules-reviewed/quarkus/java-ee/javaee-api-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,72 @@ | ||
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.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.project.condition.Artifact | ||
import org.jboss.windup.project.condition.Project | ||
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.ocpsoft.rewrite.config.And | ||
import org.ocpsoft.rewrite.context.EvaluationContext | ||
|
||
import java.util.stream.Collectors | ||
import java.util.stream.StreamSupport | ||
|
||
final IssueCategory mandatoryIssueCategory = new IssueCategoryRegistry().getByID(IssueCategoryRegistry.MANDATORY) | ||
final Link guideLink = Link.to("Quarkus - Guides", "https://quarkus.io/guides/resteasy") | ||
|
||
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("javaee-api-to-quarkus-groovy") | ||
.addSourceTechnology(new TechnologyReference("java-ee", null)) | ||
.addTargetTechnology(new TechnologyReference("quarkus", null)) | ||
.addRule() | ||
.when( | ||
And.all( | ||
JavaClass.references("javax.ws.rs.{*}").at(TypeReferenceLocation.IMPORT).as("discard"), | ||
Project.dependsOnArtifact(Artifact.withGroupId("javax").andArtifactId("javaee-api")).as("dependency") | ||
) | ||
) | ||
.perform( | ||
Iteration.over("dependency").perform( | ||
new AbstractIterationOperation<FileLocationModel>() { | ||
void perform(GraphRewrite event, EvaluationContext context, FileLocationModel payload) { | ||
if (matchesProject(event, payload)) { | ||
((Hint) Hint.titled("Replace JAX-RS dependency") | ||
.withText(""" | ||
At least one Java class importing from the `javax.ws.rs` package has been found so the dependency `javax:javaee-api` has to be replaced with `io.quarkus:quarkus-resteasy` artifact. | ||
""") | ||
.withIssueCategory(mandatoryIssueCategory) | ||
.with(guideLink) | ||
.withEffort(1) | ||
).performParameterized(event, context, payload) | ||
} | ||
} | ||
} | ||
) | ||
.endIteration() | ||
) | ||
.withId("javaee-api-to-quarkus-groovy-00000") |
Oops, something went wrong.