Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2025 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
* <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 lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.AnnotationMatcher;
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.trait.Annotated;
import org.openrewrite.java.tree.J;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

import static org.openrewrite.java.trait.Traits.annotated;

@Value
@EqualsAndHashCode(callSuper = false)
public class UpdateManagedBeanToNamed extends Recipe {

@Override
public String getDisplayName() {
return "Update Faces `@ManagedBean` to use CDI `@Named`";
}

@Override
public String getDescription() {
return "Faces ManagedBean was deprecated in JSF 2.3 (EE8) and removed in Jakarta Faces 4.0 (EE10). " +
"Replace `@ManagedBean` with `@Named` for CDI-based bean management.";
}

@Override
public Set<String> getTags() {
return new HashSet<>(Arrays.asList("jakarta", "faces", "jsf"));
}

private static final AnnotationMatcher MANAGED_BEAN_MATCHER = new AnnotationMatcher("*.faces.bean.ManagedBean");

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new Preconditions.Check(new UsesType<>("*.faces.bean.ManagedBean", false),
new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) {
Optional<Annotated> annotated = annotated(MANAGED_BEAN_MATCHER).get(getCursor());
if (annotated.isPresent()) {
maybeAddImport("jakarta.inject.Named");
maybeRemoveImport("javax.faces.bean.ManagedBean");
maybeRemoveImport("jakarta.faces.bean.ManagedBean");
// Get the name from the @ManagedBean annotation
String beanName = annotated
.flatMap(a -> a.getDefaultAttribute("name"))
.map(name -> name.getValue(String.class))
.orElse(null);
// Replace the @ManagedBean annotation with @Named
if (beanName != null) {
return JavaTemplate.builder("@Named(\"#{}\")")
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "jakarta.inject-api-2.0.1"))
.imports("jakarta.inject.Named")
.build()
.apply(getCursor(), annotation.getCoordinates().replace(), beanName);
}
return JavaTemplate.builder("@Named")
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "jakarta.inject-api-2.0.1"))
.imports("jakarta.inject.Named")
.build()
.apply(getCursor(), annotation.getCoordinates().replace());
}
return annotation;
}
});
}
}
58 changes: 1 addition & 57 deletions src/main/resources/META-INF/rewrite/jakarta-faces-3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ recipeList:
- org.openrewrite.java.migrate.jakarta.RemovedJakartaFacesResourceResolver
- org.openrewrite.java.migrate.jakarta.RemovedStateManagerMethods
- org.openrewrite.java.migrate.jakarta.RemovedUIComponentConstant
- org.openrewrite.java.migrate.jakarta.FacesManagedBeansDeprecated
- org.openrewrite.java.migrate.jakarta.UpgradeFaces3OpenSourceLibraries
---
type: specs.openrewrite.org/v1beta/recipe
Expand Down Expand Up @@ -367,63 +366,8 @@ recipeList:
newFullyQualifiedTypeName: jakarta.el.ELException
ignoreDefinition: true
---
# TODO: currently same as FacesManagedBeansRemoved in Faces4 migration. Should some items be split up?
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.jakarta.FacesManagedBeansDeprecated
displayName: Substitute deprecated Faces Managed Beans
description: >-
This recipe substitutes Faces Managed Beans, which were deprecated in JavaServer Faces 3.0.
recipeList:
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.ApplicationScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.ApplicationScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: jakarta.faces.bean.ApplicationScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.ApplicationScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.ManagedProperty
newFullyQualifiedTypeName: jakarta.faces.annotation.ManagedProperty
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: jakarta.faces.bean.ManagedProperty
newFullyQualifiedTypeName: jakarta.faces.annotation.ManagedProperty
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.NoneScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.Dependent
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: jakarta.faces.bean.NoneScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.Dependent
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.RequestScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.RequestScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: jakarta.faces.bean.RequestScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.RequestScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.SessionScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.SessionScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: jakarta.faces.bean.SessionScoped
newFullyQualifiedTypeName: jakarta.enterprise.context.SessionScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.ViewScoped
newFullyQualifiedTypeName: jakarta.faces.view.ViewScoped
ignoreDefinition: true
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: jakarta.faces.bean.ViewScoped
newFullyQualifiedTypeName: jakarta.faces.view.ViewScoped
ignoreDefinition: true
---
# TODO: should this upgrade to earliest or latest compatible version for EE9?
# TODO: maybe should pick Java8 compatible ones since EE9 recipe doesn't seem to migrate to Java11
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.jakarta.UpgradeFaces3OpenSourceLibraries
displayName: Upgrade Faces open source libraries
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/META-INF/rewrite/jakarta-faces-4.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,11 @@ recipeList:
elementName: web-app
newValue: https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd
---
# TODO: currently same as FacesManagedBeansDeprecated in Faces3 migration. Can this list be pared down?
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.jakarta.FacesManagedBeansRemoved
displayName: Substitute removed Faces Managed Beans
description: >-
This recipe substitutes Faces Managed Beans, which were deprecated in JavaServer Faces 3.0 and have been removed from Jakarta Faces 4.0.
This recipe substitutes Faces Managed Beans, which were deprecated in JavaServer Faces 2.3 and have been removed from Jakarta Faces 4.0.
recipeList:
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: javax.faces.bean.ApplicationScoped
Expand Down Expand Up @@ -254,6 +253,7 @@ recipeList:
oldFullyQualifiedTypeName: jakarta.faces.bean.ViewScoped
newFullyQualifiedTypeName: jakarta.faces.view.ViewScoped
ignoreDefinition: true
- org.openrewrite.java.migrate.jakarta.UpdateManagedBeanToNamed
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.jakarta.UpgradeFaces4OpenSourceLibraries
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2025 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
* <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.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
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 UpdateManagedBeanToNamedTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
spec.parser(JavaParser.fromJavaVersion()
.classpathFromResources(new InMemoryExecutionContext(), "jsf-api-2.1.29-11", "jakarta.faces-api-3.0.0"))
.recipe(new UpdateManagedBeanToNamed());
}

@ParameterizedTest
@ValueSource(strings = {"javax", "jakarta"})
void updateManagedBeanToNamed(String pkg) {
rewriteRun(
//language=java
java(
"""
import %s.faces.bean.ManagedBean;

@ManagedBean
public class ApplicationBean2 {
}
""".formatted(pkg),
"""
import jakarta.inject.Named;

@Named
public class ApplicationBean2 {
}
"""
)
);
}

@ParameterizedTest
@ValueSource(strings = {"javax", "jakarta"})
void updateManagedBeanToNamedWithArg(String pkg) {
rewriteRun(
//language=java
java(
"""
import %s.faces.bean.ManagedBean;

@ManagedBean(name="myBean")
public class ApplicationBean2 {
}
""".formatted(pkg),
"""
import jakarta.inject.Named;

@Named("myBean")
public class ApplicationBean2 {
}
"""
)
);
}
}
Binary file not shown.