In this example, why does it need the #ManagedBean annotation? In the setPalyBean() method, it receives a parameter and set it to the the private variable "playerBean". This is just like a regular Java class design in non-JSF world. Would it work the same if the #ManagedBean is removed?
#Named
#SessionScoped
public class PlayersBean {
private String playerName;
private String playerSurname;
public PlayersBean() {
playerName = "Rafael";
playerSurname = "Nadal";
}
//getters and setters
}
#ManagedBean
#ViewScoped
public class ProfileBean {
#ManagedProperty("#{playersBean}")
private PlayersBean playersBean;
private String greetings;
public ProfileBean() {
}
public void setPlayersBean(PlayersBean playersBean) {
this.playersBean = playersBean;
}
}
Those are the rules:
#ManagedBean - required if you:
Want to access your bean from the view, in old-style JSF
Want the container to manage the injection of anything into the bean, in old-style JSF
Want the container to manage the lifecycle of your bean, ...
Want to name your bean something different from the standard class name. The default naming convention is converting the class-name to a standard java, so what you'll have there is a bean named proileBean. If you wanted to address that bean by a different name, say profile, you'll need to use this annotation
#ManagedProperty and the associated setter are required, if you want the container to automatically inject anything into your bean. Them's the rules. It boils down to how the injection happens - Reflection.
Will it work without the annotation? No - without that annotation (and depending on your version of JSF; 2.2 allows all kinds of stuff), the container isn't aware of your bean and won't be prompted to take action
You can save yourself the hassle and adopt CDI conventions:
Replace #ManagedBean with #Named (this annotation is required only if you need to access the bean within a page, otherwise, it's unnecessary -Every bean in a CDI context is automatically managed)
Replace #ManagedProperty with #Inject. With this annotation, you can ditch the setter and getter altogether. You also don't need to worry about the scope of the bean that you're injecting into or from.
Replace your current #ViewScoped with the one from javax.faces.view.ViewScoped
Related
I'm working on a Spring application using beans of different scopes. Many beans are singletons, other request or custom scoped. Especially using those custom scopes makes it sometimes difficult to find out which scope can be safely injected into which other scope or when e.g. a Provider<T> needs to be used.
I am aware that I can just create scope proxies for all beans that are basically not singletons, but in many cases that does not seem to be necessary. For example, a bean might only be supposed to be injected into other beans of the same scope, but not everyone working on the project might be aware of that. Thus, it would be great if one could somehow prevent "misuse" of those beans, especially if one might not always recognize the mistake in time.
So my question is: Is there some way to define which scoped can be safely injected into which scope and then prevent beans with narrower scope from directly (without using Provider<T>) being injected into e.g. singleton beans?
It looks like this can be achieved fairly simple using a custom BeanPostProcessor. Within the postProcessBeforeInitialization, you can simply check the scope of the bean and the scope of all dependencies. Here is a simple example:
#Component
public class BeanScopeValidator implements BeanPostProcessor {
private final ConfigurableListableBeanFactory configurableBeanFactory;
#Autowired
public BeanScopeValidator(ConfigurableListableBeanFactory configurableBeanFactory) {
this.configurableBeanFactory = configurableBeanFactory;
}
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
String beanScope = configurableBeanFactory.getBeanDefinition(beanName).getScope();
String[] dependenciesForBean = configurableBeanFactory.getDependenciesForBean(beanName);
for (String dependencyBeanName : dependenciesForBean) {
String dependencyBeanScope = configurableBeanFactory.getBeanDefinition(dependencyBeanName).getScope();
// TODO: Check if the scopes are compatible and throw an exception
}
return bean;
}
}
This example is still very basic and is not really convenient to use. Most prominently, it lacks the capability of defining which scope can be injected into which other scope. Thus I've created a more complete example here. Using this project, the following injections are allowed by default:
Singletons can be injected into everything
Everything can be injected into prototypes
AOP proxies can be injected into everything
Everything can be injected into beans of the same scope
If you want to allow a bean to be injected into another scope, it needs to be explicitly allowed by using a respective annotation:
#Bean
#Scope("prototype")
#InjectableInto("singleton")
MyBean getMyBean(){
//...
}
actually i'm using spring for developing a web application, the problem i'm facing is that i'm initializing a bean as soon as the spring container is getting loaded, now i have to use that bean in different parts of my program.
constraints that i have
1. i can get application context everywhere and get that bean but according to my problem i should get that bean without writing that redundant code again and again.so is there any way by which i can initialize that bean and use it directly everywhere in my program.
If you already initialized your bean you can get access to it via #Autowired from each Component in your Spring Application.
private SomeClass myBean;
#Autowired
public void setMyBean(SomeClass myBean){
this.myBean =myBean;
}
Or just:
#Autowired
private SomeClass myBean;
I prefer the first method, looks fancier in my eyes.
You should not get your bean from the context directly, instead you should #Autowire them and let Spring inject it for you.
Here’s an example of two dependencies injected via constructor:
#Component
public class Car {
private final Engine engine;
private final Transmission transmission;
#Autowired
public Car(Engine engine, Transmission transmission) {
this.engine = engine;
this.transmission = transmission;
}
}
Note that your class must be a Spring Component itself in order for the injection to occur.
There are actually three types of dependency injection in Spring: constructor, field and setter injection. Spring team recommends using the constructor based approach, and this post brings very nice arguments to this point: https://blog.marcnuri.com/field-injection-is-not-recommended/
You can refer to this link for more information on constructor-based injection: https://www.baeldung.com/constructor-injection-in-spring
I understand that a managed bean works like a controller, because your only task is "link" the View Layer with Model.
To use a bean as a managed bean I must declare #ManagedBeanannotation, doing that I can communicate JSF with bean directly.
If I want to inject some component (from Spring) in this managedBean I have two possibles ways:
Choose the property in ManagedBean (like "BasicDAO dao") and declare #ManagedProperty(#{"basicDAO"}) above the property. Doing it, i'm injecting the bean "basicDAO" from Spring in ManagedBean.
Declared #Controller in ManagedBean Class, then i'll have #ManagedBean and #Controller annotations, all together. And in property "BasicDAO dao" i must use #Autowired from Spring.
Is my understanding correct?
#ManagedBean vs #Controller
First of all, you should choose one framework to manage your beans. You should choose either JSF or Spring (or CDI) to manage your beans. Whilst the following works, it is fundamentally wrong:
#ManagedBean // JSF-managed.
#Controller // Spring-managed.
public class BadBean {}
You end up with two completely separate instances of the very same managed bean class, one managed by JSF and another one managed by Spring. It's not directly clear which one would actually be used in EL when you reference it as #{someBean}. If you have the SpringBeanFacesELResolver registered in faces-config.xml, then it would be the Spring-managed one, not the JSF-managed one. If you don't have that, then it would be the JSF-managed one.
Also, when you declare a JSF managed bean specific scope, such as #RequestScoped, #ViewScoped, #SessionScoped or #ApplicationScoped from javax.faces.* package, it will only be recognized and used by #ManagedBean. It won't be understood by #Controller as it expects its own #Scope annotation. This defaults to singleton (application scope) when absent.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
#Controller // Spring-managed (without own scope, so actually becomes a singleton).
public class BadBean {}
When you reference the above bean via #{someBean}, it would return the Spring-managed application scoped bean, not the JSF-managed view scoped bean.
#ManagedProperty vs #Autowired
The JSF-specific #ManagedProperty works only in JSF-managed beans, i.e. when you're using #ManagedBean. The Spring-specific #Autowired works only in Spring-managed beans, i.e. when you're using #Controller. Below approaches are less or more equivalent and cannot be mixed:
#ManagedBean // JSF-managed.
#RequestScoped // JSF-managed scope.
public class GoodBean {
#ManagedProperty("#{springBeanName}")
private SpringBeanClass springBeanName; // Setter required.
}
#Component // Spring-managed.
#Scope("request") // Spring-managed scope.
public class GoodBean {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
}
Do note that when you have the SpringBeanFacesELResolver registered in faces-config.xml as per the javadoc,
<application>
...
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
and thus you can reference Spring managed beans in EL via #{springBeanName}, then you can just reference them in #ManagedProperty too, as it basically sets the evaluated result of the given EL expression. The other way round, injecting a JSF managed bean via #Autowired, is in no way supported. You can however use #Autowired in a JSF managed bean when you extend your bean from SpringBeanAutowiringSupport. This will automatically register the JSF managed bean instance in Spring autowirable context during constructor invocation, which means that everything #Autowired will be available in #PostConstruct and later.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport implements Serializable {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
// springBeanName is now available.
}
}
Or when your architecture doesn't allow extending beans from a different base class, then you can always manually register the JSF managed bean instance in Spring autowirable context as below. See also How to integrate JSF 2 and Spring 3 (or Spring 4) nicely for the trick.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
FacesContextUtils
.getRequiredWebApplicationContext(FacesContext.getCurrentInstance())
.getAutowireCapableBeanFactory().autowireBean(this);
// springBeanName is now available.
}
}
#XxxScoped vs #Scope
Spring's #Scope has limited support for JSF scopes. There's no equivalent for JSF's #ViewScoped. You'd basically either homegrow your own scopes, or stick to manually registering the JSF managed bean instance in Spring autowirable context as shown above.
And, from the other side on, Spring WebFlow was taken over in JSF 2.2 via new #FlowScoped annotation. So if you happen to be on JSF 2.2 already, then you don't necessarily need to use Spring WebFlow if you solely want the flow scope.
CDI - trying to unify it all
Since Java EE 6, CDI is offered as standard alternative to Spring DI. It has respectively #Named and #Inject annotations for this and also its own set of scopes. I'm not sure how it interacts with Spring as I don't use Spring, but #Inject works inside a #ManagedBean, and #ManagedProperty inside a #ManagedBean can reference a #Named bean. On the other hand, #ManagedProperty doesn't work inside a #Named bean.
The purpose of CDI is to unify all different bean management frameworks into only one specification/inteface. Spring could have been a full CDI implementation, but they choosed to only partially implement it (only JSR-330 javax.inject.* is supported, but JSR-299 javax.enterprise.context.* not). See also Will Spring support CDI? and this tutorial.
JSF will be moving to CDI for bean management and deprecate #ManagedBean and friends in a future version.
#Named // CDI-managed.
#ViewScoped // CDI-managed scope.
public class BetterBean implements Serializable {
#Inject
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
// springBeanName is now available.
}
}
See also:
When is it necessary or convenient to use Spring or EJB3 or all of them together?
JSF Service Layer
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Using JSF as view technology of Spring MVC
How to install and use CDI on Tomcat?
There is another way to use Spring-managed beans in JSF-managed beans by simply extending your JSF bean from SpringBeanAutowiringSupport and Spring will handle the dependency injection.
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean extends SpringBeanAutowiringSupport {
#Autowired
private SpringBeanClass springBeanName; // No setter required.
// springBeanName is now available.
}
The easy way to do this is via XML. I used #Component in already made jsf managed bean but #Autowired did not work because managed bean was already there in faces-config.xml. If it is mandatory to keep that managed bean definition along with its managed property in the xml file then it is suggested to add the spring bean as another managed property inside the managed bean tag. Here the spring bean is there defined in spring-config.xml(can be autowired somewhere alternately). please refer
https://stackoverflow.com/a/19904591/5620851
edited by me. I suggest to either implement it altogether through annotation #Managed and #Component or via xml for both.
You can autowire individual beans without #Autowired by leveraging getBean of the current WebApplication context.
Please refer to #BalusC's answer for more details. This is just a slight modification over his example:
#ManagedBean // JSF-managed.
#ViewScoped // JSF-managed scope.
public class GoodBean implements Serializable {
// #Autowired // No Autowired required
private SpringBeanClass springBeanName; // No setter required.
#PostConstruct
private void init() {
WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
this.springBeanName = ctx.getBean(SpringBeanClass.class);
// springBeanName is now available.
}
}
I am trying to figure out a solution for a small problem I have encountered whilst developing a small application. I am trying to pass an object created within one backing-bean and then later using that same object I created within another backing-bean. However, I would not like to make these backing-beans #SessionScoped, and preferably not use the #ManagedBean as I am using CDIfor my JavaEE application.
Is there anyway I could do this using CDI annotations and injecting one backing-bean to another and then have the ability to access that object previously created?
As an example, refer to the below beans:
#Named
#ViewScoped
public RegisterController implements Serializable {
User user = new User();
// Getter and Setter methods which are populated by the JSF page
}
Get Object User created within the above bean and use it within the controller below:
#Named
#ViewScoped
public PaymentController implements Serializable {
#Inject RegisterController registerController; // Injecting bean
registerController.getUser().getName(); //this is null when I try access the properties of the object 'User'. I am assuming this is because #ViewScoped annotated on the 'RegisterController' class?
// I would like to use the User object created in 'RegisterController' here an access properties etc...
}
Could I use the #Inject annotation offered by the CDI?
UPDATE
Ok, so I have got the above working when I annotate the RegisterController with the SessionScoped annotation, however I do not want this Bean annotated SessionScoped as I will probably run into further implications down the track, such as pre-population of fields, etc... Any ideas how to implement this any other way?
Well, #ViewScoped is too short to the purpose and #SessionScoped is too long. Then why not use #ConversationScoped?
See here.
you can use in RegistrationController:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user", user);
and in PaymentController:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("user");
this is very useful, you can save the objects you want in the map.
i want to use 2 different beans (Spring) for one JSF-Page. I do not like to write every method into one bean, so i tried to separate into two beans like JobEditDataBean and JobEditActionBean.
I want to use the JobEdiDataBean just as "Container" for my data objects and move the actionstuff (like saving, update etc.) to the action bean.
What i did by now (and what seems to work, but feels wrong) is the following:
public class JobEditDataBean{
#Autowired
JobEditActionBean actionBean;
// some objects...
#PostConstruct
public void init() {
actionBean.setJobEditDataBean(this);
// do something ...
}
}
public class JobEditActionBean{
JobEditDataBean dataBean;
// some objects...
}
Do you have any hints or tipps how this can be done better, nicer?
Indeed, you don't need to have one bean per each page. You can use as much beans you want for any page, it is fine, as whenever an expression like #{someMB} is found in your XHTML, JSF will find a bean with that name and create a new instance if necessary.
If you need to inject one bean to another, just use #Autowired already:
#Component
#Scope("request")
public class JobEditActionBean {
#Autowired
private JobEditDataBean dataBean;
#PostConstruct
public void init() {
// dataBean.youCanUseDataBeanMethodsHereAlready()
}
}
You just have to make sure both beans are in the Spring container (annotating them with #Component will do), and choosing the right scope for each one. Beware of the scopes of the beans which you are injecting, cause it usually only makes sense to inject beans of broader scope to beans of the same or more restrict scope.
Having said that, I recommend reading following thread about choosing the right scopes:
How to choose the right bean scope?
One more thing: this is only valid if your JSF beans are really being managed by the Spring container (that was my assumption after you used #Autowired). If you are letting JSF container manage the beans (using #ManagedBean with #RequestScoped or #ViewScoped, for example), the way you inject them is with a #ManagedProperty annotation:
...
#ManagedProperty("#{jobEditDataBean}")
private JobEditDataBean dataBean;