1

I use Spring boot with JSF 2.2. My problem is that I can create @ManagedBean from javax.annotation.ManagedBean and it is working in my index.xhtml when I run the app, but when I want to use javax.faces.bean.ManagedBean is not displaying the value. What's the difference between those two? Why I can't use the javax.faces.bean.ManagedBean? ( I don't have web.xml file, all is configured in classes)

Xtreme Biker
  • 28,480
  • 12
  • 120
  • 195
Patryk Imosa
  • 535
  • 1
  • 7
  • 26

1 Answers1

9

The javax.annotation.* annotations are meant to be a move from the classic JSF annotations to a CDI approach. The Spring Framework has the ability to read some CDI annotations, so that could be the reason why this annotation "works". However, the trend in CDI is to use @Named, overall.

In a Spring Boot application, it's Spring the one scanning your annotations, not JSF. So, even you could think that the application works with @ManagedBean, you'll see that the @*Scoped annotations are useless, because all the created beans happen to be singletons, which is Spring's default scope.

In the end the choice I made was to use vanilla Spring annotations and scopes. As Spring lacks the JSF view scope, also a custom scope to emulate it.

MyBean.java:

@Component
@Scope("view")
public class MyBean {
  //Here it goes your logic
}

ViewScope.java:

public class ViewScope implements Scope {

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
        if (viewMap.containsKey(name)) {
            return viewMap.get(name);
        } else {
            Object object = objectFactory.getObject();
            viewMap.put(name, object);

            return object;
        }
    }

    @Override
    public String getConversationId() {
        return null;
    }

    @Override
    public void registerDestructionCallback(String arg0, Runnable arg1) {

    }

    @Override
    public Object remove(String name) {
        return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name);
    }

    @Override
    public Object resolveContextualObject(String arg0) {
        return null;
    }

}

Register the view scope with a CustomScopeConfigurer:

@Bean
public static CustomScopeConfigurer viewScope() {
    CustomScopeConfigurer configurer = new CustomScopeConfigurer();
    configurer.setScopes(
            new ImmutableMap.Builder<String, Object>().put("view", new ViewScope()).build());
    return configurer;
}

Finally, do not forget to add the Spring EL resolver in your faces-config.xml to make the Spring beans available through EL expressions:

<application> 
    <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>

See also:

Community
  • 1
  • 1
Xtreme Biker
  • 28,480
  • 12
  • 120
  • 195