ApplicationScoped bean not injected in JSF 2.3 FacesConverter - cdi

I have following FacesConverter:
#FacesConverter(forClass = Onderwerp.class, managed = true)
public class OnderwerpConverter implements Converter<Onderwerp> {
#Inject
private Web web;
#Override
public Onderwerp getAsObject(FacesContext context, UIComponent component, String value) {
log.trace("Converting to object from string: " + value);
return web.getAllActiveOnderwerpen().stream().filter(o -> o.getId().equals(Long.parseLong(value))).findFirst().get();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Onderwerp onderwerp) {
log.trace("Converting to string from object: " + onderwerp);
return onderwerp.getId().toString();
}
}
The referenced CDI bean is:
#Named
#ApplicationScoped
public class Web { ... }
Faces-config.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd" version="2.3">
Now whatever kind of bean I inject via #Inject it is always null. It seems the injection feature in 2.3 is not working (yet), or I am missing something :)
I'm using Mojarra 2.3.0 on EAP 7.0. Also tested without success using 2.3.3 on EAP 7.0 and 7.1.
My current workaround is replacing the code where I need the injected CDI bean like this:
return CDI.current().select(Web.class).get().getAllActiveOnderwerpen().stream().filter(o -> o.getId().equals(Long.parseLong(value))).findFirst().get();
This works fine, but is kinda ugly of course :)
Anyone has experienced this behavior?

I had the same issue and I foud the solution.
You must create a config bean indicating JSF version:
import javax.faces.annotation.FacesConfig;
import javax.faces.annotation.FacesConfig.Version;
#FacesConfig(
// Activates CDI build-in beans
version=Version.JSF_2_3
)
public class ConfigBean {
}

Related

Instance null after injecting #SessionScoped CDI bean into a JSF #ManagedBean

I have :
- Repository Class:
#SessionScoped
public class EmployeeRepository {
#PersistenceContext
EntityManager entityManager;
public List<Employee> getEmployees(){
TypedQuery<Employee> qu = entityManager.createQuery("select * from Employee", Employee.class);
List<Employee> emp2 = qu.getResultList();
return emp2;
}
}
and
Managed Bean:
#ManagedBean(name = "helloWorldBean")
public class HelloWorldBean {
#Inject
private EmployeeRepository employeerepo;
public String getMsg() {
return "Hallo";
}
public String getEmployees() {
return String.valueOf(employeerepo.getEmployees().size());
}
}
and a JSF Page:
<h:head>
<title>JavaCodeGeeks</title>
</h:head>
<h:body>
- Message : <h:outputText value="#{helloWorldBean.msg}" />
- Employee count : <h:outputText value="#{helloWorldBean.employees}" />
</h:body>
</html>
I have an beans.xml in my META-INF Folder (src\META-INF) without special configurations:
<?xml version="1.0"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all" version="1.1">
</beans>
Problem:
Page throws nullpointer exception, because the EmployeeRepository is not injected in the HelloWorldBean.
What to do to be able to inject Instances of classes in my case ?
As you are using CDI, you should not be using #ManagedBean (which is a JSF annotation). While I have actually seen this working, most implementations will not allow you to inject a CDI bean into a classic JSF bean.
To allow for CDI injection in JSF beans, the CDI specification allows you to define JSF backing beans by specifying the #Named annotation in combination with a scope (#RequestScoped, #javax.faces.view.ViewScoped, #SessionScoped and #ApplicationScoped).
So in summary, the following piece of code should solve your problem,
#Named
#RequestScoped
public class HelloWorldBean {
#Inject
private EmployeeRepository employeerepo;
public String getMsg() {
return "Hallo";
}
public String getEmployees() {
return String.valueOf(employeerepo.getEmployees().size());
}
}
You can also read up further on the topic via some old Q/A's here on the site,
How to inject a CDI Bean in a ManagedBean?
#ManagedProperty does not work in a CDI managed bean
CDI beans injection

Interceptors don't work with JSF managed beans?

I am decide to try interceptors My first interceptor binding annotation is
#Inherited
#InterceptorBinding
#Target({TYPE})
#Retention(RUNTIME)
public #interface WithLog {
// No parameters required
}
And interceptor class is
#Interceptor
#WithLog
public class LogInterceptor {
#AroundInvoke
private Object logMethod(InvocationContext context) throws Exception {
System.out.println("Method " + context.getMethod().getName() +
" of class " + context.getTarget().getClass().getName() + " was called.");
return context.proceed();
}
#PostConstruct
private void construct(InvocationContext context) {
System.out.println("#Postconstruct of " +
context.getMethod().getDeclaringClass().getName() + " started.");
}
}
So, I want to add simple logging for JSF managed bean:
#ManagedBean(name = "departmentRootMB")
#ViewScoped
#WithLog
public class DepartmentRootMB implements Serializable {
long serialVersionUID = 0L;
// . . . properties, methods
}
I read, that to enable interceptors I need to create beans.xml. I created one in the WEB-INF directory:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
<interceptors>
<class>ru.edu.pgtk.weducation.interceptors.LogInterceptor</class>
</interceptors>
</beans>
I rebuild project and no effect. Where is the mistake? What I did wrong? I use glassfish 4.1 with it standard components (WELD, EclipseLink, JSF 2.2.7)
Thanks for your time and best regards.
Interceptors don't work with JSF managed beans?
Correct.
Replace JSF bean management facility by CDI bean management facility.
In other words, replace #ManagedBean and friends by #Named and friends. The JSF bean management facility is on the schedule to be deprecated in favor of CDI in a future Java EE version anyway. This is a good opportunity to migrate now you can.
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?

Use EntityManager in Validator [duplicate]

How can I inject a dependency like #EJB, #PersistenceContext, #Inject, #AutoWired, etc in a #FacesValidator? In my specific case I need to inject a Spring managed bean via #AutoWired:
#FacesValidator("emailExistValidator")
public class EmailExistValidator implements Validator {
#Autowired
private UserDao userDao;
// ...
}
However, it didn't get injected and it remains null, resulting in java.lang.NullPointerException.
It seems that #EJB, #PersistenceContext and #Inject also doesn't work.
How do I inject a service dependency in my validator so that I can access the DB?
JSF 2.3+
If you're already on JSF 2.3 or newer, and want to inject CDI-supported artifacts via e.g. #EJB, #PersistenceContext or #Inject, then simply add managed=true to the #FacesValidator annotation to make it CDI-managed.
#FacesValidator(value="emailExistValidator", managed=true)
JSF 2.2-
If you're not on JSF 2.3 or newer yet, then you basically need to make it a managed bean. Use Spring's #Component, CDI's #Named or JSF's #ManagedBean instead of #FacesValidator in order to make it a managed bean and thus eligible for dependency injection.
E.g., assuming that you want to use CDI's #Named:
#Named
#ApplicationScoped
public class EmailExistValidator implements Validator {
// ...
}
You also need to reference it as a managed bean by #{name} in EL instead of as a validator ID in hardcoded string. Thus, so
<h:inputText ... validator="#{emailExistValidator.validate}" />
instead of
<h:inputText ... validator="emailExistValidator" />
or
<f:validator binding="#{emailExistValidator}" />
instead of
<f:validator validatorId="emailExistValidator" />
For EJBs there's a workaround by manually grabbing it from JNDI, see also Getting an #EJB in #FacesConverter and #FacesValidator.
If you happen to use JSF utility library OmniFaces, since version 1.6 it adds transparent support for using #Inject and #EJB in a #FacesValidator class without any additional configuration or annotations. See also the CDI #FacesValidator showcase example.
See also:
CDI Injection into a FacesConverter
What's new in JSF 2.2 - Injection
You can now inject into JSF validators if you're using Java EE 8 and/or JSF 2.3.
Tested using Mojarra 2.3.9.payara-p2 on Payara Server 5.192 #badassfish.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:body>
Hello from Facelets
<h:form>
<h:messages/>
<h:inputText value="#{someBean.txtField}" validator="someValidator"/>
</h:form>
</h:body>
</html>
import javax.inject.Named;
import javax.enterprise.context.Dependent;
#Named(value = "someBean")
#Dependent
public class SomeBean {
private String txtField;
public String getTxtField() {
return txtField;
}
public void setTxtField(String txtField) {
this.txtField = txtField;
}
}
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
#FacesValidator(value = "someValidator", managed = true)
public class CustomValidator implements Validator<String> {
#Inject
NewClass newClass;
#Override
public void validate(FacesContext context, UIComponent component, String value)
throws ValidatorException {
System.out.println("validator running");
System.out.println("injected bean: " + newClass);
if (value != null && value.equals("badvalue")) {
throw new ValidatorException(new FacesMessage(newClass.getMessage()));
}
}
}
public class NewClass {
public String getMessage() {
return "secret message";
}
}
import javax.faces.annotation.FacesConfig;
// WITHOUT THIS INJECTION WILL NOT WORK!
#FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class ConfigurationBean {
}
Should render something like:
I banged my head on the wall for about an hour before realizing the need for ConfigurationBean. From the documentation:
FacesConfig.Version.JSF_2_3
This value indicates CDI should be used for EL resolution as well as enabling JSF CDI injection, as specified in Section 5.6.3 "CDI for EL Resolution" and Section 5.9 "CDI Integration"
And from this GitHub issue, https://github.com/eclipse-ee4j/glassfish/issues/22094:
By default, JSF 2.3 runs in a compatibility mode with previous releases of JSF, unless a CDI managed bean is included in the application with the annotation #javax.faces.annotation.FacesConfig. To switch into a JSF 2.3 mode you will need a configuration bean like below: (shows ConfigurationBean)
...
The fact that JSF needs to be switched into the "current version" was highly controversial. Pretty much the entire EG voted against that, but eventually we could not get around the backwards compatibility requirements that the JCP sets for Java EE and the spec lead enforces.

How to inject a CDI Bean in a ManagedBean?

I want to inject a CDI Bean in a ManagedBean either with the annotation #Inject or #Produce. The CDI Bean which I use is:
#Named
#Startup
#ApplicationScoped
public class BaseBean {
private List<String> custs;
public List<String> getCusts() {
return custs;
}
public void setCusts(List<String> emps) {
this.custs = emps;
}
public BaseBean(){
}
#PostConstruct
void init() {
custs = new ArrayList<String>();
custs.add("Cust1");
custs.add("Cust3");
custs.add("Cust2");
custs.add("Cust4");
}
}
The ManagedBean, in which I want to inject the CDI Bean is:
#SessionScoped
#ManagedBean
public class Hello implements Serializable {
#Inject
private BaseBean dBean;
private static final long serialVersionUID = 1L;
private List<String> customers;
private List<String> customersSelect;
public Hello() {
}
#PostConstruct
void init() {
// dBean = new BaseBean();
customers = dBean.getCusts();
}
public List<String> getCustomers() {
return customers;
}
public List<String> getCustomersSelect() {
return customersSelect;
}
public void setCustomersSelect(List<String> customersSelect) {
this.customersSelect = customersSelect;
}
}
In the init function however, it throws NullPointerException. If I use the annotation #Produces instead of #Inject, the result is the same: NullPointerException. Is anything wrong with the CDI Bean (improper annotations)? Do I try to inject it with a wrong way? Does my code lack of something? How can I get it work? Here is the JSF code:
<h:form id ="f">
<h:selectManyCheckbox layout="pageDirection" border="1" value="#{hello.customersSelect}">
<f:selectItems value="#{hello.customers}"></f:selectItems>
</h:selectManyCheckbox><br />
<h:commandButton action="response.xhtml" value="Click me" />
</h:form>
PS: If I use a Stateless Bean as BaseBean and I inject it with the annotation #EJB, it works with no problem.
UPDATE: I have tried it with the annotations #SessionScoped (javax.enterprise.context.SessionScoped) and #Named on the Hello class. Although I do not receive a NullPointerException, the h:selectManyCheckbox is empty. moreover, it strikes me, that when I add the beans.xml file under META-INF folder, I receive a StartException, although the file is there supposed to be. I think my application lacks the proper configuration to be capable of Dependency Injection. What is likely to need additional configuration?
UPDATE 2: This error appears when I add the beans.xml file in the WEB-INF folder. The beans.xml file is empty, it contains only the line :
<?xml version="1.0" encoding="UTF-8"?>
The error is:
Services which failed to start: service jboss.deployment.unit."JSF1.war".PARSE: org.jboss.msc.service.StartException in service jboss.deployment.unit."JSF1.war".PARSE: Failed to process phase PARSE of deployment "JSF1.war"
12:51:11,482 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 1) {"JBAS014653: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"JBAS014671: Failed services" => {"jboss.deployment.unit.\"JSF1.war\".PARSE" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"JSF1.war\".PARSE: Failed to process phase PARSE of deployment \"JSF1.war\""}}}}
What #patlov is suggesting will work if you use #Named on your CDI beans. However, if you're working in an environment that supports CDI, do not use #ManagedBean. Instead, use CDI all the way. See this answer and I'm sure you could find numerous other ones that strongly advise against what you're trying to do.
Just switch from javax.faces.bean.SessionScoped to javax.enterprise.context.SessionScoped and everything will magically work. What you may run into is the absense of #ViewScoped from CDI however, in which case use something like JBoss Seam or Apache Deltaspike that implement it for you. As an added benefit, they will also automatically replace all of the JSF scopes with CDI scopes automatically if you already have existing code written for JSF.
Update:
This should be the content of your beans.xml:
<?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">
</beans>
Make sure you have enabled CDI by putting a WEB-INF/beans.xml file in your application.
If you are using #ManagedBean use #ManagedProperty to inject properties:
#ManagedProperty(value = "#{baseBean}")
private BaseBean dBean;
// getter and setter

JSF 2.0: How to override base renderers with custom ones?

I am trying to override renderer for h:selectBooleanCheckbox (for the reasons explained here):
However, I find it impossible to register my renderer. I have tried declaring it in my faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.SelectBoolean</component-family>
<renderer-type>javax.faces.Checkbox</renderer-type>
<renderer-class>com.myapp.CustomCheckboxRenderer</renderer-class>
</renderer>
</render-kit>
The values I grabbed from:
component-family: javax.faces.component.html.HtmlSelectBooleanCheckbox
renderer-type: javax.faces.component.html.SelectBooleanCheckboxTag
But it doesn't work.
I also tried verbosely declaring the RenderKit:
<description>Custom renderers</description>
<render-kit-id>???</render-kit-id>
<render-kit-class>com.sun.faces.renderkit.RenderKitImpl</render-kit-class>
But as you can see, I don't really know where to grab value for render-kit-id or if the render-kit-class is correct anyway.
Inside Mojarra package there is file jsf-ri-runtime.xml but it doesn't declare the renderers. It only declares a RenderKitFactory, under which I don't directly find anything of interest.
Pointers?
Your initial <renderer> declaration looks fine, so I tried it here.
package com.myapp;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import com.sun.faces.renderkit.html_basic.CheckboxRenderer;
public class CustomCheckboxRenderer extends CheckboxRenderer {
public CustomCheckboxRenderer() {
System.out.println("CustomCheckboxRenderer <init>");
}
#Override
public void decode(FacesContext context, UIComponent component) {
System.out.println("CustomCheckboxRenderer decode()");
super.decode(context, component);
}
#Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
System.out.println("CustomCheckboxRenderer encodeBegin()");
super.encodeBegin(context, component);
}
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
System.out.println("CustomCheckboxRenderer encodeEnd()");
super.encodeEnd(context, component);
}
}
It works fine. All get printed to stdout. Your problem lies somewhere else. I was using Mojarra 2.0.3 on Tomcat 7.0.5.
I add renderers to my faces-config.xml like so:
<faces-config>
<!--elided-->
<render-kit>
<render-kit-id>HTML_BASIC</render-kit-id>
<renderer>
<display-name>MyRenderer</display-name>
<component-family>javax.faces.Output</component-family>
<renderer-type>foo.MyRenderer</renderer-type>
<renderer-class>foo.MyRenderer</renderer-class>
<!-- TODO: attributes for tooling -->
You don't need to (and shouldn't) declare a new render kit class in this scenario.

Resources