cdi bean injection for initialization code - cdi

I have a bean configured which have some initialization logic. I have annotated this bean using #ApplicationScoped annotation. But somehow, cdi is not picking this bean.
beans.xml content:
<?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">
</beans>
Bean file:
#ApplicationScoped
public class Initializer{
#Inject #ConfigProperty(name = "app.name")
private String appName;
#Inject #ConfigProperty(name = "app.token")
private String appToken;
#Inject #ConfigProperty(name = "app.version")
private String appVersion;
#PostConstruct
public void init() {
System.out.println("flow should come here....); //but this line does not execute.
}
}
Code to read config file:
#Exclude
public class ConfigurationFile implements PropertyFileConfig {
#Override
public String getPropertyFileName() {
String env = Util.getEnv();
switch (env) {
case "dev":
case "uat":
case "prod":
return "config/" + env + "/default.properties";
default:
return "config/default.properties";
}
}
#Override
public boolean isOptional() {
return false;
}
}
I am using:
cdiL: for dependency injection,
apache-deltaspike: for reading config file.
wildfly-swarm: server

I have got the solution to this problem.
Issue is solved by changing the method declaration as follows:
public void init(#Observes #Initialized(ApplicationScoped.class) Object init) {
//................code logic here................
}

Related

Custom converter with attributes/injection not working with anymore after upgrade to JSF 2.3

I am trying to upgrade/use a custom converter that worked with JSF 2.2 (on Wildfly 13) to work on JSF 2.3 (with Mojarra 2.3.9.SP02 running on Wildfly 17.0.1)
The converter is used via its own tag defined in a tag library.
Everything's fine as long as no tag attributes are used. The attributes are just not set in the converter. The setters never get called.
But if I remove the managed = true from the converter the attributes are set but then the injection no longer works.
The converter is used like this:
<h:inputText id="text" value="#{welcome.text}">
<cdijsf:converterWithAttr id="myConverter" attr="myAttrValue" />
</h:inputText>
Tag library:
<facelet-taglib version="2.3"
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-facelettaglibrary_2_3.xsd">
<namespace>http://cdijsf.transdata.net/jsf</namespace>
<tag>
<tag-name>converterWithAttr</tag-name>
<converter>
<converter-id>cdijsf.ConverterWithAttr</converter-id>
</converter>
<attribute>
<name>attr</name>
<type>java.lang.String</type>
</attribute>
</tag>
</facelet-taglib>
And this is the converter code:
#Dependent
#FacesConverter(value = "cdijsf.ConverterWithAttr", managed = true)
public class ConverterWithAttr implements Converter<String> {
#Inject
private BeanManager beanManager;
private String attr;
public ConverterWithAttr() {
}
#PostConstruct
private void init() {
// If 'managed = true' beanManager is injected at this point.
// If 'managed = false' beanManager is null at this point
}
#Override
public String getAsObject(FacesContext context, UIComponent component, String value) {
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, String value) {
return value;
}
public String getAttr() {
return attr;
}
public void setAttr(String attr) {
// If 'managed = true' setAttr is never called
// If 'managed = false' setAttr is called
this.attr = attr;
}
}
faces-config.xml:
<faces-config version="2.3"
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">
</faces-config>
And I also explicitly declare JSF 2.3 like this:
#FacesConfig(version = Version.JSF_2_3)
#ApplicationScoped
public class JsfConfiguration {
}
beans.xml:
<?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_2_0.xsd"
version="2.0"
bean-discovery-mode="annotated">
</beans>

#Specializes in Wildfly 10.1.0

We are trying to use alternative bean instance injection for our integration test suite deployed on a Wildfly 10.1.0 server.
According to the CDI 1.2 spec, a possible solution to do so would be to use the #Specializes annotation on an alternative deployed in the integration test archive only.
However, the default implementation is always injected. We tried #Specializes on managed beans, session beans, and tried to select the alternatives in the beans.xml file.
The following example illustrate the issue:
BeanInterface.java
public interface BeanInterface {
void work();
}
Implementation1.java
#Dependent
public class Implementation1 implements BeanInterface {
#Override
public void work() {
System.out.println("test 1");
}
}
Implementation2
#Dependent
#Alternative
#Specializes
public class Implementation2 extends Implementation1 {
#Override
public void work() {
System.out.println("test 2");
}
}
TestSingleton.java:
#Singleton
#Startup
public class TestSingleton {
#Inject
private BeanInterface beanInterface;
#PostConstruct
public void init() {
this.beanInterface.work();
}
}
Packaging these classes in a war (with a web.xml) and deploying on wildfly, the implementation 1 is always injected in the Stateless bean.
Wildfly 10.1.0 uses weld-2.3.SP2 which implements CDI 1.2.
Thanks,
Charly
Although it does not make the #Specializes annotation work as expected, this solution suggested by John Ament allows to inject the second Implementation.
Just change the #javax.enterprise.inject.Specializes annotation with #javax.annotation.Priority (and some value):
#Dependent
#Alternative
#Priority(100)
public class Implementation2 extends Implementation1 {
#Override
public void work() {
System.out.println("test 2");
}
}
Also missing in the OP question was the beans.xml (not web.xml) packaged in the WEB-INF:
<?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="all">
</beans>

JSF #managedproperty and #PostConstruct

I have a problem with JSF2 #ManagedProperty annotation. I have a managed bean that create a user, then i want to pass this user to another bean to display other informations relative to that user. So my code is below :
#Named("userController")
#SessionScoped
public class UserController implements Serializable {
#EJB
private session.UserFacade ejbFacade;
private List<User> items = null;
private User selected;
private User utente;
private String user;
private String pass;
----getter and setter----
In the Schedule Bean I use the userController bean in the #PostConstruct :
#Named(value = "scheduleController")
#SessionScoped
public class ScheduleController implements Serializable {
private ScheduleModel eventModel;
private ScheduleEvent event = new DefaultScheduleEvent();
#EJB
ActivityFacade ejbFacade;
#ManagedProperty(value="#{userController}")
private UserController credentials;
public ScheduleController() {
}
#PostConstruct
public void init(){
eventModel = new DefaultScheduleModel();
List<Activity> daFare =ejbFacade.findForUser(credentials.getUtente().getIdUser());
for(int i=0;i<daFare.size();i++){
eventModel.addEvent(new DefaultScheduleEvent(daFare.get(i).getDescrizione(),daFare.get(i).getDalleOre(),daFare.get(i).getAlleOre() ));
}
}
public void setCredentials(UserController credentials) {
this.credentials = credentials;
}
When i debug the code, I see that the UserController credentials is always null.... What's wrong ? I need to specify something in faces-config.xml ?
Thanks a lot for your tips.
EDIT :
After change #ManagedProperty with #Inject and after add the below beans.xml in WEB-INF folder, the problem persist.
<?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">
The app work in this way:
A user can log in via this xhtml page:
<body>
<h:form>
<p:growl id="msgs" showDetail="true" />
<p:panel header="Inserisci i tuoi dati" style="margin: 0 auto; text-align: center" >
<h:panelGrid columns="2" cellpadding="5" style="margin: 0 auto; text-align: center">
<p:outputLabel value="Username"/>
<p:inputText value="#{userController.user}" required="true" label="Username" size="40"/>
<p:outputLabel value="Password" />
<p:password value="#{userController.pass}" required="true" label="Password" size="40"/>
<p:commandButton action="#{userController.validateLogin}" value="Login" update="msgs" ajax="false" style="text-align: center"/>
</h:panelGrid>
</p:panel>
</h:form>
</body>
After submit the form, the userController verify that this specific user exist in a DB table and then instantiate the User utente ( id, username, password, email as field ). After this, the app redirect to home.xhtml that display several user's information and select several information of a DB table selected by user's id.
Here is the code where I set User utente:
public String validateLogin(){
String output="home";
boolean exist=false;
exist=ejbFacade.logValid(user,pass);
if(!exist){
//FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Username o Password errata","Contattare l'amministratore"));
return "index";
}else{
utente=ejbFacade.setUtente(user);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Accesso eseguito con successo.","Bentornato " + user));
return output;
}
}
The code sequence in which i control the existece of a user and set the utente is:
#Stateless
public class UserFacade extends AbstractFacade<User> {
#PersistenceContext(unitName = "ImmobiliareWebPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public UserFacade() {
super(User.class);
}
public boolean logValid(String user, String pass) {
List<User> utente ;
boolean autorizzato;
String find = "User.findByUsername&Password";
Query query = em.createNamedQuery(find, User.class);
query.setParameter("username", user);
query.setParameter("password", pass);
utente =query.getResultList();
if (utente.isEmpty()) {
autorizzato=false;
}
else{
autorizzato=true;
}
return autorizzato;
}
public User setUtente(String user) {
//SETTO L'UTENTE PER LA SESSIONE DEL PROGRAMMA
User utente;
String find = "User.findByUsername";
Query query = em.createNamedQuery(find, User.class);
query.setParameter("username", user);
utente =(User) query.getSingleResult();
return utente;
}
}
the code where I need user's information is :
#Named(value = "scheduleController")
#RequestScoped
public class ScheduleController implements Serializable {
private ScheduleModel eventModel;
private ScheduleEvent event = new DefaultScheduleEvent();
#EJB
ActivityFacade ejbFacade;
#Inject
private UserController credentials;
public ScheduleController() {
}
#PostConstruct
public void init(){
eventModel = new DefaultScheduleModel();
List<Activity> daFare =ejbFacade.findForUser(credentials.getUtente().getIdUser());
for(int i=0;i<daFare.size();i++){
eventModel.addEvent(new DefaultScheduleEvent(daFare.get(i).getDescrizione(),daFare.get(i).getDalleOre(),daFare.get(i).getAlleOre() ));
}
}
In the ejbFacade i make a simple query :
#Stateless
public class ActivityFacade extends AbstractFacade<Activity> {
#PersistenceContext(unitName = "ImmobiliareWebPU")
private EntityManager em;
#Override
protected EntityManager getEntityManager() {
return em;
}
public ActivityFacade() {
super(Activity.class);
}
public List<Activity> findForUser(int utenteId) {
//RICHIEDO LE ATTIVITA' DEL SINGOLO UTENTE
List<Activity> daFare ;
String find = "Activity.findByUserId";
Query query = em.createNamedQuery(find, Activity.class);
query.setParameter("idUser", utenteId);
daFare =query.getResultList();
return daFare;
}
}
In debug mode i see an istance of UserController with all null fields; it seems to be a new istance of UserController. I use also "import javax.enterprise.context.SessionScoped" . Where is my fault ?
When i debug the code, I see that the UserController credentials is
always null.... What's wrong?
Please note you are mixing up CDI (Context and Dependency Injection) with Managed properties, which is probably causing the described behavior. Your beans are annotated with #Named instead of #ManagedBean so this:
#ManagedProperty(value="#{userController}")
private UserController credentials;
Should be replaced by this:
#Inject
private UserController credentials;
For a really great explanation about the difference between CDI and backing beans see #BalusC answer in this topic: Backing beans (#ManagedBean) or CDI Beans (#Named)?.
I need to specify something in faces-config.xml?
No, but you should include a beans.xml like exemplified here: Packaging CDI applications. As far as I remember this file is mandatory regardless the discovery mode. Here is the beans.xml that you can auto-generate in NetBeans:
New file --> Context and Dependency Injection --> beans.xml (CDI Configuration file).
This is all I've ever needed to make CDI work:
<?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">
</beans>

Java EE 6: How to inject ServletContext into managed bean

(Java EE 6 with Glassfish 3.1)
I have a property file that I want to process only once at start up time, so I did this
public class Config implements ServletContextListener{
private static final String CONFIG_FILE_PATH = "C:\\dev\\harry\\core.cfg";
private static final String CONFIG_ATTRIBUTE_NAME = "config";
private long startupTime;
private ConfigRecord config;
#Override
public void contextInitialized(ServletContextEvent sce) {
this.startupTime = System.currentTimeMillis() / 1000;
this.config = new ConfigRecord(CONFIG_FILE_PATH); //Parse the property file
sce.getServletContext().setAttribute(CONFIG_ATTRIBUTE_NAME, this);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
//Nothing to do here
}
public ConfigRecord getConfig() {
return config;
}
public long getStartupTime() {
return startupTime;
}
}
and in web.xml, i register it as follow
<listener>
<listener-class>com.wf.docsys.core.servlet.Config</listener-class>
</listener>
Now how do I access the ConfigRecord config from the managed bean. I try this
#ManagedBean
#RequestScoped
public class DisplayInbound {
#EJB
private CoreMainEJBLocal coreMainEJBLocal;
#javax.ws.rs.core.Context
private ServletContext servletContext;
public void test(){
Config config = (Config) servletContext.getAttribute("config")
ConfigRecord configRecord = config.getConfig();
}
}
I dont think it work. Got NullPointerException.
That #Context annotation is only applicable in a JAX-RS controller, not in a JSF managed bean. You have to use #ManagedProperty instead. The ServletContext is available by ExternalContext#getContext(). The FacesContext itself is available by #{facesContext}.
#ManagedProperty(value="#{facesContext.externalContext.context}")
private ServletContext context;
Or because you stored the listener as a servletcontext attribute, which is basically the same as the JSF application scope, you could also just set it as managed property by its attribute name:
#ManagedProperty(value="#{config}")
private Config config;
But since you're on JSF 2.0, I'd suggest to use an #ApplicationScoped #ManagedBean instead which is eagerly constructed. With #PostConstruct and #PreDestroy in such a bean you have similar hooks on webapp's startup and shutdown as in a ServletContextListener.
#ManagedBean(eager=true)
#ApplicationScoped
public void Config {
#PostConstruct
public void applicationInitialized() {
// ...
}
#PreDestroy
public void applicationDestroyed() {
// ...
}
}
You can inject it in another beans the usual #ManagedProperty way and access it in the views the usual EL way.

JSF:Resourcebundle Problem with Internationalization

I implemented internationalization like in that tutorial!
When I change the language in my app. It works. But only until the next request happens. Then language settings are reset to my standard language -.-
What am I missing here:
LanguageBean.java
#ManagedBean(name="language")
#SessionScoped
public class LanguageBean implements Serializable{
private static final long serialVersionUID = 1L;
private String localeCode;
private static Map<String,Object> countries;
static{
countries = new LinkedHashMap<String,Object>();
countries.put("Deutsch", Locale.GERMAN); //label, value
countries.put("English", Locale.ENGLISH);
}
public Map<String, Object> getCountriesInMap() {
return countries;
}
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
//value change event listener
public void countryLocaleCodeChanged(ValueChangeEvent e){
String newLocaleValue = e.getNewValue().toString();
//loop country map to compare the locale code
for (Map.Entry<String, Object> entry : countries.entrySet()) {
if(entry.getValue().toString().equals(newLocaleValue)){
FacesContext.getCurrentInstance()
.getViewRoot().setLocale((Locale)entry.getValue());
}
}
}
}
my facelets template:
<h:selectOneMenu value="#{language.localeCode}" onchange="submit()"
valueChangeListener="#{language.countryLocaleCodeChanged}">
<f:selectItems value="#{language.countriesInMap}" />
</h:selectOneMenu>
faces-config:
<application>
<locale-config>
<default-locale>de</default-locale>
</locale-config>
<resource-bundle>
<base-name>org.dhbw.stg.wwi2008c.mopro.ui.text</base-name>
<var>msg</var>
</resource-bundle>
</application>
Add the following line to setLocaleCode().
FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale(localeCode));
See also this tutorial which I wrote.

Resources