Skip to content

Commit

Permalink
CDI recipe (#340)
Browse files Browse the repository at this point in the history
* partial cdi recipe

* completed CDI recipe

* add back ticks for code

* remove public class from test classes

* updated tests with isNullable and BeanDiscovery method

* updated recipes based on my comments

* minor refactor

* convert isNullable to false and simplify logic

* Test RemoveBeanIsNullable separately and simplify implementation

Description should end with a dot; and reflect what the recipe does.
Call super in the normal code path.
Remove superfluous nullable annotations.
Add missing space in case `false` is retained.

* Restore jakarta-ee-10.yml

* Apply missing license

* Restore missing type

* remove annotation and clean up code

* fixes the diff failure.

* reverting to not use templete in getEvent

* fixed test

* remove template comment

* should resolve tests

* Add no args constructors to reduce test log output

* Minor polish

* Add individual unit tests to flush out issues

* Add individual unit tests to flush out issues

* Remove DeprecatedCDIAPIsRemoved40Test as it duplicates others

And has issues with whitespace that we don't want

* Drop `FacesManagedBeansRemoved` that had moved to `jakarta-faces-4.yml`

* Further minimize tests

* Only keep one copy of classpath resource jar

---------

Co-authored-by: anuram <[email protected]>
Co-authored-by: cjobinabo <[email protected]>
Co-authored-by: Tim te Beek <[email protected]>
  • Loading branch information
4 people authored Jan 30, 2024
1 parent 006b5d8 commit aa43f7b
Show file tree
Hide file tree
Showing 8 changed files with 430 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2023 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.jakarta;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.Space;
import org.openrewrite.marker.Markers;
import org.openrewrite.staticanalysis.RemoveUnusedLocalVariables;
import org.openrewrite.staticanalysis.SimplifyConstantIfBranchExecution;

import static org.openrewrite.Tree.randomId;

public class RemoveBeanIsNullable extends Recipe {
@Override
public String getDisplayName() {
return "Remove `Bean.isNullable()`";
}

@Override
public String getDescription() {
return "`Bean.isNullable()` has been removed in CDI 4.0.0, and now always returns `false`.";
}

private static final MethodMatcher BEAN_ISNULLABLE = new MethodMatcher("jakarta.enterprise.inject.spi.Bean isNullable()", false);

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaVisitor<ExecutionContext>() {
@Override
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
if (BEAN_ISNULLABLE.matches(method)) {
// clean up leftover conditions and remove unused variables
doAfterVisit(new SimplifyConstantIfBranchExecution().getVisitor());
doAfterVisit(new RemoveUnusedLocalVariables(null).getVisitor());
return new J.Literal(randomId(), Space.SINGLE_SPACE, Markers.EMPTY, Boolean.FALSE, "false", null, JavaType.Primitive.Boolean);
}
return super.visitMethodInvocation(method, ctx);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 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.jakarta;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.J;

public class UpdateAddAnnotatedTypes extends Recipe {
@Override
public String getDisplayName() {
return "Replace `BeforeBeanDiscovery.addAnnotatedType(AnnotatedType)` with `addAnnotatedType(AnnotatedType, String)`";
}

@Override
public String getDescription() {
return "`BeforeBeanDiscovery.addAnnotatedType(AnnotatedType)` is deprecated in CDI 1.1. It is Replaced by `BeforeBeanDiscovery.addAnnotatedType(AnnotatedType, String)`.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {
private final MethodMatcher methodInputPattern = new MethodMatcher(
"*.enterprise.inject.spi.BeforeBeanDiscovery addAnnotatedType(*.enterprise.inject.spi.AnnotatedType)", false);

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
if (methodInputPattern.matches(method)) {
return JavaTemplate.builder("#{any(jakarta.enterprise.inject.spi.AnnotatedType)}, null\"")
.build()
.apply(updateCursor(method),
method.getCoordinates().replaceArguments(),
method.getArguments().get(0));
}
return super.visitMethodInvocation(method, ctx);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2023 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.jakarta;

import org.openrewrite.ExecutionContext;
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.MethodMatcher;
import org.openrewrite.java.tree.J;

public class UpdateBeanManagerMethods extends Recipe {
@Override
public String getDisplayName() {
return "Update `fireEvent()` and `createInjectionTarget()` calls";
}

@Override
public String getDescription() {
return " Updates `BeanManager.fireEvent()` or `BeanManager.createInjectionTarget()`.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {
private final MethodMatcher fireEventMatcher = new MethodMatcher("*.enterprise.inject.spi.BeanManager fireEvent(..)", false);
private final MethodMatcher createInjectionTargetMatcher = new MethodMatcher("*.enterprise.inject.spi.BeanManager createInjectionTarget(..)", false);

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ec) {
J.MethodInvocation mi = super.visitMethodInvocation(method, ec);
if (fireEventMatcher.matches(method)) {
return JavaTemplate.builder("#{any(jakarta.enterprise.inject.spi.BeanManager)}.getEvent().fire(#{any(jakarta.enterprise.inject.spi.BeforeBeanDiscovery)})")
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ec, "jakarta.enterprise.cdi-api-3.0.0-M4"))
.build()
.apply(updateCursor(mi),
mi.getCoordinates().replace(),
mi.getSelect(),
mi.getArguments().get(0));
} else if (createInjectionTargetMatcher.matches(method)) {
return JavaTemplate.builder("#{any(jakarta.enterprise.inject.spi.BeanManager)}.getInjectionTargetFactory(#{any(jakarta.enterprise.inject.spi.AnnotatedType)}).createInjectionTarget(null)")
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ec, "jakarta.enterprise.cdi-api-3.0.0-M4"))
.build()
.apply(updateCursor(mi),
mi.getCoordinates().replace(),
mi.getSelect(),
mi.getArguments().get(0));
}
return mi;
}
};
}
}
Binary file not shown.
12 changes: 12 additions & 0 deletions src/main/resources/META-INF/rewrite/jakarta-ee-10.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ recipeList:
- org.openrewrite.java.migrate.jakarta.RemovedSOAPElementFactory
- org.openrewrite.java.migrate.jakarta.WsWsocServerContainerDeprecation
- org.openrewrite.java.migrate.jakarta.ServletCookieBehaviorChangeRFC6265
- org.openrewrite.java.migrate.jakarta.DeprecatedCDIAPIsRemoved40
- org.openrewrite.java.migrate.BeanDiscovery
- org.openrewrite.java.migrate.jakarta.BeanValidationMessages
- org.openrewrite.java.migrate.jakarta.JavaxBeansXmlToJakartaBeansXml
Expand Down Expand Up @@ -126,10 +127,21 @@ recipeList:
newValue: https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.jakarta.DeprecatedCDIAPIsRemoved40
displayName: Remove deprecated API's not supported in CDI4.0
description: >
Deprecated APIs have been removed in CDI 4.0. This recipe removes and updates the corresponding deprecated methods.
recipeList:
- org.openrewrite.java.migrate.jakarta.RemoveBeanIsNullable
- org.openrewrite.java.migrate.jakarta.UpdateAddAnnotatedTypes
- org.openrewrite.java.migrate.jakarta.UpdateBeanManagerMethods
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.jakarta.JavaxToJakartaCdiExtensions
displayName: Rename CDI Extension to Jakarta
description: Rename `javax.enterprise.inject.spi.Extension` to `jakarta.enterprise.inject.spi.Extension`.
recipeList:
- org.openrewrite.RenameFile:
fileMatcher: '**/javax.enterprise.inject.spi.Extension'
fileName: jakarta.enterprise.inject.spi.Extension

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2023 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.jakarta;

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 RemoveBeanIsNullableTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new RemoveBeanIsNullable())
.parser(JavaParser.fromJavaVersion()
.classpathFromResources(new InMemoryExecutionContext(), "jakarta.enterprise.cdi-api-3.0.0-M4"));
}

@Test
@DocumentExample
void removeBeanIsNullable() {
rewriteRun(
//language=java
java(
"""
import jakarta.enterprise.inject.spi.Bean;
class Test {
void test(Bean<?> bean) {
if (bean.isNullable()) {
System.out.println("is null");
} else {
System.out.println("not null");
}
}
}
""",
"""
import jakarta.enterprise.inject.spi.Bean;
class Test {
void test(Bean<?> bean) {
System.out.println("not null");
}
}
"""
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.jakarta;

import org.junit.jupiter.api.Test;
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 UpdateAddAnnotatedTypesTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec
.parser(JavaParser.fromJavaVersion()
.classpathFromResources(new InMemoryExecutionContext(), "jakarta.enterprise.cdi-api-3.0.0-M4", "jakarta.enterprise.cdi-api-4.0.1"))
.recipe(new UpdateAddAnnotatedTypes());
}

@Test
void addAnnotatedType() {
rewriteRun(
//language=java
java(
"""
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
class Foo {
void bar(BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
AnnotatedType<String> producerType = beanManager.createAnnotatedType(String.class);
beforeBeanDiscovery.addAnnotatedType(producerType); // Flag this one
beforeBeanDiscovery.addAnnotatedType(producerType, "my unique id"); // Not this one
beforeBeanDiscovery.addAnnotatedType(String.class, "my other unique id"); // Not this one
}
}
""",
"""
import jakarta.enterprise.inject.spi.AnnotatedType;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
class Foo {
void bar(BeforeBeanDiscovery beforeBeanDiscovery, BeanManager beanManager) {
AnnotatedType<String> producerType = beanManager.createAnnotatedType(String.class);
beforeBeanDiscovery.addAnnotatedType(producerType, null); // Flag this one
beforeBeanDiscovery.addAnnotatedType(producerType, "my unique id"); // Not this one
beforeBeanDiscovery.addAnnotatedType(String.class, "my other unique id"); // Not this one
}
}
"""
)
);
}

}
Loading

0 comments on commit aa43f7b

Please sign in to comment.