I am using JSF 2.3 and I want to inject different sublaccess of a session scoped bean as a managed property using CDI.
From the link below
How to inject different subclasses as ManagedProperty JSF 2?
I understood that this was not possible for RequestScoped beans using the "old" JSF and JEE-annotations, but my beans have session scope and I am using CDI injection, and therefore different annotations than the ones used in the above link.
In particular I do have:
public abstract class BaseContainer {
String prop1;
}
#Named
#SessionScoped
public class MaklerContainer extends BaseContainer {
String prop 2;
}
#Named
#SessionScoped
public class AppManagerContainer extends MaklerContainer {
String prop 3;
}
public abstract class BaseBean {
#Inject
#javax.faces.annotation.ManagedProperty(value = "#{maklerSessionContainer}")
private MaklerSessionContainer maklerSessionContainer;
}
Is it possible to inject interchangeably instances of both MaklerContainer and AppManagerContainer as a managed property maklerSessionContainer of the class BaseBean above?
Let me describe one option, there may be others.
First of all, if you want to inject different sublaccess, you have to find a way to disambiguate them for CDI, or it will complain about "Ambiguous dependencies". E.g. given the class hierarchy of the question, the line below results in ambiguous dependency exception, because CDI cannot decide whether to inject the MaklerContainer or the AppManagerContainer that extends it:
#Inject MaklerContainer maklerContainer; // ambiguous!
You can use qualifiers, named beans, or #Typed (perhaps there are even more ways).
Let's use #Named, since it is already present.
The idea is to create a producer that introduces a third bean of type MaklerContainer, with a different name, to the appropriate scope. The producer code will decide which of the 2 implementations to choose at runtime. Something like this:
#ApplicationScoped
public class TheProducer {
#Inject #Named("maklerContainer")
private MaklerContainer maklerContainer;
#Inject #Named("appManagerContainer")
private AppManagerContainer appManagerContainer;
#Inject
private User currentUser;
#Produces
#SessionScoped
#Named("theOne") // choose appropriate name of course
public MaklerContainer makeMaklerContainer() {
if (currentUser.hasRole("Role1")) {
return appManagerContainer;
} else {
return maklerContainer;
}
}
}
Now all you have to do is inject the appropriate named MaklerContainer, like:
#Inject #Named("theOne") MaklerContainer maklerContainer;
Related
I am new to jsf and using JSF 2.0 to keep user information in a session scoped bean. I need to access this information across other beans for grunt work. Presently, this is how i am doing:-
private UserBean myuser1 = (UserBean)FacesUtils.getManagedBean("UserBean");
and then access properties as
if (myuser1.getUserType == 1) ...
this works but some time throws Argument Error: parameter key is null exception. I have been using following method too:-
private UserBean myuser2 = new UserBean();
if (myuser2.getUserType == 1) ...
In second method, my understanding is that if UserBean is already created in session, it would be retried. There are lots of question about 'how to access one bean in another' so i am confused. Please tell me one clean method which should always work and not throw null pointer exception abruptly.
The simplest way I know of is using #ManagedProperty, I don't know what you mean by safest though.
Let's say this is your sessionScoped bean :
#ManagedBean
#SessionScopped
public class UserBean {
//bean attributes and methods
}
Then you can access it in any other bean (provided it has the same or a narrower scope) as an attribute like this :
#ManagedBean
#ViewScoped //in this cas you can use SessionScoped, FlowScoped, or RequestScoped too
public class AnotherBean {
#ManagedProperty("#{userBean}")
UserBean userB;
//rest of the bean
//be sure to add getters and setters for the injected bean
}
For more details check this
Hope this helps.
Actually,
parameter key is null exception: it's either you didn't initialize the object witch can be solver with either adding
object = new Object(); // in the constructor of the class.
The second problem may be that the object is " DETACHED " you need to call the object using the method merge (with the entity manager).
A detached object is a known value but the JPA system doesn't know if it is the latest version from the DB or even sometimes the id value is not set for some reason (Not managed with jpa in other words it can be your case).
If em is your entity manager and you have the following function:
public Object latestVersion(Object o){ em.merge; }
In your Bean with:
#EJB
Service service;
if you do em.latestVersion(o); the problem of detached object is solved.
And for the real answer:
To access a object from another view you can simply do the following.
#ManagedBean
#SessionScoped
..... Bean1 {
public static Object o;
.....
}
#ManagedBean
..... Bean 2 {
private Object b=Bean1.o;
.....
}
Good luck
The standard practice of setting dependency of a scoped bean in another scoped bean is to use #Inject annotation like
#Inject UserBean userBean; in the bean you want use the UserBean object.
Your UserBean should be a stateful one.
#Stateful
#LocalBean
public class UserBean
{
private String name;
public String getName() { return name; }
public void setName( String name_ ) { name = name_; }
}
And just inject it into a stateless bean to modify its state:
#Stateless
#LocalBean
public class MyStatelessBean
{
#EJB
private UserBean userBean;
public String getUserName() { userBean.getName(); };
public void setUserName( String name_ ) { userBean.setName( name_); }
}
Or you can access it from (not wider scoped) managed beans as well in the same way:
#ManagedBean
#Dependent
public class MyJSFManagedBean
{
#EJB
private UserBean userBean;
}
You wrote in your comment you does not use EJBs at all. The picture modify like this:
The UserBean should be a SessionScoped CDI bean
#Named
#SessionScoped
pubilc class UserBean
{}
The othe CDI bean should be in a nearer scope:
#Named
#Request // or #ViewScoped or #Dependent
public class OwnerBean
{
#Inject
UserBean userBean;
}
The container automatically takes care to create the beans in the right scope and insert them into the owers (any kind of container managed objects : servlets, filters, action listeners, JSF/CDI beans). You need to insert a wider scoped resource into a thinner scoped one.
In a Java EE 6, CDI 1.1.x, Seam 3 etc. environment, we need to find all CDI beans of the current view (#ViewScoped). What I have tried so far is using:
#Named
#ViewScoped
public class ViewHelper
{
#Inject
private BeanManager beanManager;
public doSomethingWithTheBeanInstances()
{
Set<Bean<?>> beans = this.getBeanManager().getBeans(
Object.class, new AnnotationLiteral<Any>(){}
);
// do something
...
}
}
However, this returns all beans it manages.
I need to find only those within the scope of the current view and - that would be ideal - only those that implement a specific interface (inherited over over multiple hierarchy levels).
What's the way to do it?
Note since CDI has no view scope, we're using Seam 3 to be able to annotate all our view-scoped beans like:
#Named
#ViewScoped
public class ResultManagerColumnHandler extends BaseColumnHandler
{
....
}
The above would be an instance to look for (the #ViewScoped is a CDI replacement by Seam 3).
How can it be done?
I am not familiar with Seam, but from CDI standpoint, this is what I would try. However, bean it mind that it will only work if beanManager.getContext(ViewScoped.class); returns a valid context instance for you:
#Inject
BeanManager bm;
public List<Object> getAllViewScoped() {
List<Object> allBeans = new ArrayList<Object>();
Set<Bean<?>> beans = bm.getBeans(Object.class);
// NOTE - context has to be active when you try this
Context context = bm.getContext(ViewScoped.class);
for (Bean<?> bean : beans) {
Object instance = context.get(bean);
if (instance != null) {
allBeans.add(instance);
}
}
return allBeans;
}
You also asked to only obtain beans that implement certain interface. For that, simply modify the code line retrieving all beans with desired type:
Set<Bean<?>> beans = bm.getBeans(MyInterface.class);
I have the following classes:
#Named
#ViewScoped
public class BaseClass {
private SomeDependency dep;
public BaseClass(){}
#Inject
public BaseClass(SomeDependency dep) {
this.dep = dep;
}
#PostConstruct
private void initialize() {
dep.doSomething(); // Point "A"
}
public String getProperty() {
return "BaseClass-Property";
}
#Specializes
public class SpecialClass extends BaseClass() {
#Override
public String getProperty() {
return "SpecialClass-Property";
}
}
Now in some .xhtml I have something like
<h:outputText value="#{baseClass.property}" />
This works fine without the SpecialClass. It breaks with a NullPointerException at Point "A" if I include the SpecialClass in the project.
Well, according to the Weld specification, this is more or less intended behavior:
When an enabled bean specializes another bean, the other bean is never
instantiated or called by the container.
Nevertheless, now I have to make sure that every #Specializes bean implements the complete constructor like
public SpecialClass() {}
#Inject
public SpecialClass(SomeDependency dep) { super(dep); }
which IMHO is kind of counter-intuitive and produces a lot of duplicated, boilerplate code, especially with something like 5-6 arguments for every constructor. Also, this is never caught when creating a new specialized bean since the project is always still compile clean.
Am I doing something wrong or is there no alternative to implementing the constructors over and over again?
BTW, I do use Constructor Injection to create easily testable classes where I can just use the constructor to "Inject" dummy implementations of the dependencies.
CDI 1.1 spec at section 4.3 says:
"The only way one bean can completely override a second bean at all
injection points is if it implements all the bean types and declares
all the qualifiers of the second bean."
Your base class is annotated with the Named qualifier and the specializing class is not. You should also mark it with Alternative and enable it in beans.xml. There's also the ViewScoped annotation. Unless it's the Omnifaces' ViewScoped, it looks like you're mixing up JSF managed beans with CDI beans.
I'm new in Java EE/JSF and now read about CDI qualifiers - the possibility to change class implementation. This is great but I have got one question. As far as I understand I can change class implementation using qualifier but I need to change it everywhere I use this implementation. What is the best solution to do it in one place? With my small knowledge about Java EE I figured out this one.
Lets imagine that we are creating simple Calculator application. We need to create few classes:
Calculator (basic implementation of calculator)
ScientificCalculator (scientific implementation of calculator)
MiniCalculator (with minimum potentiality)
MockCalculator (for unit tests)
Qualifier #Calculator (will indicate to the actual implementation of calculator; should I create qualifier for each implementation?)
Here is the question. I've got four implementations of calculator and I want to use one of them in few places but only one at time (in the initial project phase I will use MiniCalculator, then Calculator and so on). How can I change implementation without change code in every place where object is injected? Should I create factory which will be responsible for injecting and will work as method injector? Is my solution correct and meaningful?
Factory
#ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
#Produces #Calculator Calculator getCalculator() {
return new Calculator();
}
}
Class which uses Calculator
public class CalculateUserAge {
#Calculator
#Inject
private Calculator calc;
}
Is this the correct solution? Please correct me if I'm wrong or if there is a better solution. Thanks!.
There are several issues here.
What is the best way to change the desired implementation in the entire application? Look into #Alternatives.
Do I need a qualifier for each implementation? No, see this answer for a lengthy and detailed explanation.
Should I use a producer to decide which implementation is injected? Could be the solution you want, but I doubt it. Producers are generally used to perform some sort of initialization that can't be done in the constructor / #PostConstruct. You could also use it to inspect the injection point and make runtime decisions about what to inject. See the link 2. for some clues.
Is this solution correct? This will work, but you'll still have to mess with the code to change the implementation, so consider 1. first. Also #Calculator Calculator seems highly redundant. Again, see the link at 2.
#ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
#Produces #Calculator Calculator getCalculator() {
return new Calculator();
}
}
Update:
CDI uses qualifiers in addition to types for dependency resolution. In other words, as long as there is only one type that matches the type of the injection point, types alone are enough and qualifiers are not needed. Qualifiers are there for disambiguation when types alone are not enough.
For example:
public class ImplOne implements MyInterface {
...
}
public class ImplTwo implements MyInterface {
...
}
To be able to inject either implementation, you don't need any qualifiers:
#Inject ImplOne bean;
or
#Inject ImplTwo bean;
That's why I say #Calculator Calculator is redundant. If you define a qualifier for each implementation, you're not gaining much, might as well just use the type. Say, two qualifiers #QualOne and #QualTwo:
#Inject #QualOne ImplOne bean;
and
#Inject #QualTwo ImplTwo bean;
The example directly above does not gain anything since in the previous example no dis-ambiguity existed already.
Sure, you can do this for cases where you don't have access to particular implementation types:
#Inject #QualOne MyInterface bean; // to inject TypeOne
and
#Inject #QualTwo MyInterface bean; // to inject TypeTwo
However OP shouldn't be using #Produces when he wants Calculator implementations to be CDI managed.
#Avinash Singh - CDI manages #Produces as well as anything they return, as long as it is CDI that calls the method. See this section of the spec if you please. This includes returning `#...Scoped beans which will support dependency injection, life-cycle callbacks, etc.
I overlooked some details here, so consider the following two:
public class SomeProducer {
#Inject ImplOne implOne;
#Inject ImplTwo implTwo;
#Inject ImplThree implThree;
#Produces
public MyInterface get() {
if (conditionOne()) {
return implOne;
} else if (conditionTwo()) {
return implTwo;
} else {
return implThree;
}
}
}
and
public class SomeProducer {
#Produces
public MyInterface get() {
if (conditionOne()) {
return new ImplOne();
} else if (conditionTwo()) {
return new ImplTwo();
} else {
return new ImplThree;
}
}
}
Then, in the first example, CDI will manage the life cycle (i.e. #PostConstruct and #Inject support) of what's returned from the producer, but in the second one it will not.
Back to the original question - what's the best way to switch between implementations without having to modify the source? The assumption is that you want the change to be application wide.
#Default
public class ImplOne implements MyInterface {
...
}
#Alternative
public class ImplTwo implements MyInterface {
...
}
#Alternative
public class ImplThree implements MyInterface {
...
}
Then, any for any #Inject MyInterface instance, ImplOne will be injected, unless
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>ImplTwo</class>
</alternatives>
</beans>
is specified, in which case ImplTwo will be injected everywhere.
Further Update
There are indeed things in the Java EE environment that are not managed by CDI, such as EJBs and web services.
How would you inject a web service into a CDI managed bean? It's simple really:
#WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
That's it, there you'll have a valid reference to the payment service which is managed outside CDI.
But, what if you didn't want to use the full #WebServiceRef(lookup="java:app/service/PaymentService") everywhere you need it? What if you only want to inject it by type? Then you do this somewhere:
#Produces #WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
and in any CDI bean that needs a reference to that payment service you can simply #Inject it using CDI like this:
#Inject PaymentService paymentService;
Note that before defining the producer field, PaymentService wouldn't be available for injection the CDI way. But it is always available the old way. Also, in either case the web service is not managed by CDI but defining the producer field simply makes that web service reference available for injection the CDI way.
If you want to swap the implementation in your code using a factory method then your factory method is managing the beans and not CDI and so there is really no need for #Calculator.
#ApplicationScoped
public class CalculatorFactory implements Serializable {
enum CalculatorType{MiniCaculator,ScientificCaculator,MockCalculator};
Calculator getCalculator(CalculatorType calctype) {
switch(calctype)
case MiniCaculator : return new MiniCalculator();
case ScientificCalculator : new ScientificCalculator();
case MockCalculator : new MockCalculator();
default:return null;
}
}
public class CalculatorScientificImpl {
private Calculator calc =
CalculatorFactory.getCaclulator(CaclutorType.ScientificCalculator);
doStuff(){}
}
public class CalculatorTest {
private Calculator calc =
CalculatorFactory.getCaclulator(CaclutorType.MockCalculator);
doStuff(){}
}
However if you want your Caclulator beans to be CDI managed for injections and life cycle management using #PostConstruct etc then you can use one of the below approaches.
Approach 1 :
Advantage :You can avoid creating annotation using #Named("miniCalculator")
Disadvantage : compiler will not give an error with this approach if there is a name change from say miniCalculator to xyzCalculator.
#Named("miniCalculator")
class MiniCalculator implements Calculator{ ... }
#ApplicationScoped
public class CalculatorFactory implements Serializable {
private calc;
#Inject
void setCalculator(#Named("miniCalculator") Caclulator calc) {
this.calc = calc;
}
}
Approach 2 : Recommended (Compiler keeps track of injection if any injection fails)
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, TYPE, METHOD})
public #interface MiniCalculator{
}
#ApplicationScoped
public class CalculatorFactory implements Serializable {
private calc;
#Inject
void setCalculator(#MiniCalculator calc) {
this.calc = calc;
}
}
Approach 3: If you are using a factory method to generate your object.Its lifecycle wont be managed be CDI but the Injection will work fine using #Inject .
#ApplicationScoped
public class CalculatorFactory implements Serializable {
private Calculator calc;
#Produces Calculator getCalculator() {
return new Calculator();
}
}
public class CalculateUserAge {
#Inject
private Calculator calc;
}
All three approaches will work for testing , say you have a class named CaculatorTest,
class ScientificCalculatorTest{
Caclulator scientificCalculator;
#Inject
private void setScientificCalculator(#ScientificCalculator calc) {
this.scientificCalculator = calc;
}
#Test
public void testScientificAddition(int a,int b){
scientificCalculator.add(a,b);
....
}
}
if you want to use a mock implementation in your test then do something like this,
class CalculatorTest{
Caclulator calc;
#PostConstruct
init() {
this.calc = createMockCaclulator();
}
#Test
public void testAddition(int a,int b){
calc.add(a,b);
.....
}
}
I'm having troubles working with CDI in JSF project. I cannot force CDI to inject interface-based bean into JSF file.
#Named
public class ClassBasedNamedBean {
public String getMessage() {
return "Class-based Hello World!";
}
}
#Named
public interface InterfaceBasedNamedBean {
public String getMessage();
}
public class InterfaceBasedNamedBeanImpl implements InterfaceBasedNamedBean {
#Override
public String getMessage() {
return "Interface-based Hello World!";
}
}
I can use both beans in WebServlet environment:
#WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
#Inject
private ClassBasedNamedBean classBasedNamedBean;
#Inject
private InterfaceBasedNamedBean interfaceBasedNamedBean;
protected void doGet(...) ... {
PrintWriter pw = response.getWriter();
pw.println("classBasedNamedBean: " + classBasedNamedBean.getMessage());
pw.println("interfaceBasedNamedBean: " + interfaceBasedNamedBean.getMessage());
// Output:
// classBasedNamedBean: Class-based Hello World!
// interfaceBasedNamedBean: Interface-based Hello World!
}
}
But interfaceBasedNamedBean is not available in JSF page:
<p>ClassBasedNamedBean: #{classBasedNamedBean.message}</p>
<p>InterfaceBasedNamedBean: #{interfaceBasedNamedBean.message}</p>
Output:
<p>ClassBasedNamedBean: Class-based Hello World!</p>
<p>InterfaceBasedNamedBean: </p>
How could I fix this issue? Does JSF require some explicit configuration for interfaceBasedNamedBean?
As my best guess:
I don't think that this is mentioned in the spec, but I'm pretty sure that #Named is not intended to be used on interfaces.
After all, it's just a matching between a type and an EL-name - and it seems as if the EL resolver can't find anything (concrete) under the name of the interface.
So, try annotating the implementation, not the interface - this should work. If you need to be flexible with various implementations of the same bean type - inject it in a controller bean and make that bean accessible.
You set javax.enterprise.inject.spi.BeanManager as your BeanManager?
What happens if you add #Named("InterfaceBasedNamedBean") to your Class Definition and remove the annotation from the interface? For what reason are you using the annotations anyways? CDI is not requiring them in contrast to spring.
Have you tried using a producer method?
Try adding scope to your bean with #RequestScoped, for example. From Weld docs:
The #Named annotation is not what makes the class a bean. Most classes in a bean archive are already recognized as beans. The #Named annotation just makes it possible to reference the bean from the EL, most commonly from a JSF view.
CDI defines #Named as a String-based qualifier. A qualifier's purpose is to distinguish which implementation to use at the injection point. The #Named's javadoc gives an example:
public class Car {
#Inject #Named("driver") Seat driverSeat;
#Inject #Named("passenger") Seat passengerSeat;
...
}
Thus #Named must annotate a specific implementation.
#Named as a way to use CDI beans in JSF views can be seen as a secondary function. #Named is not "#Inject for JSF" as it may seem to be.