related links: PrimeFaces PickList with OmniFaces validateAll leads to NullPointerException
this problem is similar with this link becuase when I do the debug of the picklistRender I got the same error showed in the link before,the same syntoms, but I am reading all issue history related, Thomas Andraschko sugguest is a problem of mojarra but I tried to test with myfaces-version-22 and myfaces-version-23 and I face the same problem
Im trying to figure out to resolve my example works like showcase p:picklist but not worls as well said the docs, I tried several options like
- don't use mojarra,use myfaces
- change primefaces version 7.0 to 8.0.RC1
- put a custom converter
-jboss-deployment-structure.xml (disables packages from jboss)
When does the error occur?
- loading page
why am I using a converter?
- is an option I tried to fix the problem, but, the ussue raises before, I test with or withoutconverter and happens the same error.
enviroment
-Jboos EAP 7.2
- repo https://github.com/Qleoz12/Primefaces-Mydemo
but always I have this error
java.lang.NullPointerException
viewId=/components/usingCompositeComponent.xhtml
location=I:\developer\Fado\Servidores\jboss-eap-7.2\standalone\deployments\Primefaces-
Mydemo.war\components\usingCompositeComponent.xhtml
phaseId=RENDER_RESPONSE(6)
Caused by:
java.lang.NullPointerException
at org.primefaces.component.picklist.PickListRenderer.encodeMarkup(PickListRenderer.java:103)
xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ccp="http://java.sun.com/jsf/composite/cc"
template="../template/ui.xhtml">
<ui:define name="body">
<p:pickList
id="FF"
value="#{CompositeComponent.cities}"
var="cities"
itemLabel="#{cities}"
itemValue="#{cities}"
converter="PickListConverter"
>
</p:pickList>
</ui:define>
</ui:composition>
bean
package Beans;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Named;
import org.primefaces.model.DualListModel;
#Named
#javax.faces.view.ViewScoped
public class CompositeComponent implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CompositeComponent.class);
private DualListModel<String> cities;
List<String> citiesSource = new ArrayList<String>();
List<String> citiesTarget = new ArrayList<String>();
public CompositeComponent() {
super();
}
#PostConstruct
public void init() {
// Cities
citiesSource.add("San Francisco");
citiesSource.add("London");
citiesSource.add("Paris");
citiesSource.add("Istanbul");
citiesSource.add("Berlin");
citiesSource.add("Barcelona");
citiesSource.add("Rome");
cities = new DualListModel<String>(citiesSource, citiesTarget);
}
public DualListModel<String> getCities() {
return cities;
}
public void setCities(DualListModel<String> cities) {
this.cities = cities;
}
}
converter
package converter;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import org.primefaces.component.picklist.PickList;
import org.primefaces.model.DualListModel;
#SuppressWarnings({"unused", "rawtypes"})
#FacesConverter("PickListConverter")
public class PickListConverter implements Converter{
public Object getAsObject(FacesContext facesContext, UIComponent component, String submittedValue) {
PickList p = (PickList) component;
DualListModel dl = (DualListModel) p.getValue();
return dl.getSource().get(Integer.valueOf(submittedValue));
}
public String getAsString(FacesContext facesContext, UIComponent component, Object value) {
PickList p = (PickList) component;
DualListModel dl = (DualListModel) p.getValue();
return String.valueOf(dl.getSource().indexOf(value));
}
}
question
And for the PickListRenderer the NPE is in line 78 then 128 inside PickListRenderer:
encodeList(context, pickList, clientId + "_target", PickList.TARGET_CLASS, model.getTarget(),
pickList.getFacet("targetCaption"), pickList.isShowTargetFilter(), false);
issue of primefaces
the NPE var is related with model always is null inside encodeMarkup that afterward call encodeList with this model null.
DualListModel model = getModelValueToRender(context, pickList);
stackTrace https://pastebin.com/wLKZWReg
the both question is related because in sme point in the other question they can achieve to resolve the problem but Im following all stuffs they made, but I cant figure out, yeah both questions are similar , them have somo little differets but for me is the same scenary
7: If it is not mojarra related, please remove the mojarra tag. 8: Run you jsf application in JSF development mode.
yes I trying to resolve this error testing with mojarra or testing myfaces for that I dont remove the tag of mojarra.
problems
-Fix on the xhtml the name of the bean the name of the bean usually starts with lowercase for that I chabge
value="#{CompositeComponent.cities}"
to this
value="#{compositeComponent.cities}"
-for Strings remove the converter , but for custom objects you must to write a own implemantation of the converter, I put an example into my repo in github.
I test two ways to handle JSF anottation and anothers stuff the project
you must choose one, dont use both or you have some error on deploying stage.
<!-- javax.* APIs -->
<!-- old way -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<!-- end old way -->
<!-- new way -->
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-atinject_1.0_spec</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-interceptor_1.2_spec</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-annotation_1.3_spec</artifactId>
<version>1.0</version>
</dependency>
Related
This question already has answers here:
Identifying and solving javax.el.PropertyNotFoundException: Target Unreachable
(18 answers)
Closed 1 year ago.
I am trying to make a simple JSF projects but getting errors along the way... I updated my project as a maven project but still it does not work.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-
4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>BeatifulThingsWebapp</groupId>
<artifactId>BeatifulThingsWebapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>16</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.3</version>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.sun.faces/jsf-impl -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.faces/jsf-api -->
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.20</version>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
</project>
this is my index.xhtml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<h1>Please fill out the form</h1>
<h:form>
Tell me about something nice:
<h:inputText value="#{bt.thingTitle}"/>
Now describe it:
<h:inputText value="#{bt.thingDescription}"/>
Rate this item:
<h:inputText value="#{bt.rating}"/>
<h:commandButton action="#{controller.onSubmitEdit()}" value="OK"/>
</h:form>
</body>
</html>
java classes
package beans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.view.ViewScoped;
#ManagedBean(name="bt")
#ViewScoped
public class BeautifulThing implements Serializable{
int id;
String thingTitle;
String thingDescription;
int rating;
//ManagedBean has to have a non argument constructor
public BeautifulThing(int id, String thingTitle, String thingDescription, int rating) {
super();
this.id = id;
this.thingTitle = thingTitle;
this.thingDescription = thingDescription;
this.rating = rating;
}
public BeautifulThing() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getThingTitle() {
return thingTitle;
}
public void setThingTitle(String thingTitle) {
this.thingTitle = thingTitle;
}
public String getThingDescription() {
return thingDescription;
}
public void setThingDescription(String thingDescription) {
this.thingDescription = thingDescription;
}
public int getRating() {
return rating;
}
public void setRating(int rating) {
this.rating = rating;
}
#Override
public String toString() {
return "BeautifulThing [id=" + id + ", thingTitle=" + thingTitle + ", rating=" +
rating + "]";
}
}
--------------------
package controllers;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
#ManagedBean(name="controller")
public class FormController implements Serializable{
//ManagedBean has to have a non argument constructor
public void onSubmitEdit() {
//when the user clicks on the submit button
System.out.println("You clicked the OK button");
}
public FormController() {
super();
// TODO Auto-generated constructor stub
}
}
the error I am getting:
HTTP Status 500 – Internal Server Error
--------------------------------------------------------------------------------
Type Exception Report
Message /index.xhtml #13,41 value="#{bt.thingTitle}": Target Unreachable, identifier [bt]
resolved to null
Description The server encountered an unexpected condition that prevented it from
fulfilling
the request.
Exception
javax.servlet.ServletException: /index.xhtml #13,41 value="#{bt.thingTitle}": Target
Unreachable, identifier [bt] resolved to null
javax.faces.webapp.FacesServlet.service(FacesServlet.java:671)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause
javax.el.PropertyNotFoundException: /index.xhtml #13,41 value="#{bt.thingTitle}": Target
Unreachable, identifier [bt] resolved to null
com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:100)
com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInpu
tRenderer.java:95)
javax.faces.component.UIInput.getConvertedValue(UIInput.java:1067)
javax.faces.component.UIInput.validate(UIInput.java:981)
javax.faces.component.UIInput.executeValidate(UIInput.java:1270)
javax.faces.component.UIInput.processValidators(UIInput.java:714)
javax.faces.component.UIForm.processValidators(UIForm.java:253)
javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1195)
com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause
javax.el.PropertyNotFoundException: Target Unreachable, identifier [bt] resolved to null
org.apache.el.parser.AstValue.getTarget(AstValue.java:73)
org.apache.el.parser.AstValue.getType(AstValue.java:57)
org.apache.el.ValueExpressionImpl.getType(ValueExpressionImpl.java:173)
com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:98)
com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInpu
tRenderer.java:95)
javax.faces.component.UIInput.getConvertedValue(UIInput.java:1067)
javax.faces.component.UIInput.validate(UIInput.java:981)
javax.faces.component.UIInput.executeValidate(UIInput.java:1270)
javax.faces.component.UIInput.processValidators(UIInput.java:714)
javax.faces.component.UIForm.processValidators(UIForm.java:253)
javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1261)
javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1195)
com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Note The full stack trace of the root cause is available in the server logs.
--------------------------------------------------------------------------------
Apache Tomcat/9.0.50
Your JSF container dont create your BeautifulThing bean and therefore jsf servler dont find it.
Try change #MangedBean("bt") to #Named("bt") or delete constructor with arguments. (And totaly delete super(); because your bean don't extend any other object).
If no one from this will be work, look to logs of your application server from start or deploy war.
Am using JSF Primefaces 7.0 to render an XHTML file to display a list of users (along with their e-mail addresses) inside a single HTML dropdown list.
pom.xml:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>7.0</version>
</dependency>
<dependency>
<groupId>org.primefaces.extensions</groupId>
<artifactId>primefaces-extensions</artifactId>
<version>7.0.3</version>
</dependency>
User class:
package com.myapp.model;
import static org.apache.commons.lang3.StringUtils.isBlank;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;
#NoArgsConstructor
#Data
public class User implements Serializable {
private String firstName;
private String lastName;
// this is their e-mail address
private String username;
public String getName() {
final StringBuilder sb = new StringBuilder();
if (!isBlank(getFirstName())) {
sb.append(getFirstName()).append(' ');
}
if (!isBlank(getLastName())) {
sb.append(getLastName());
}
return sb.toString().trim();
}
}
Inside users.xhtml:
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core"
>
<f:selectItems
value="#{userReport.users}"
var="user"
itemLabel="#{user.name} (#{user.username})"
itemValue="#{user}"/>
</p:selectOneMenu>
</html>
This renders correctly for an individual item if the (user.name is not null) inside an HTML dropdown list:
John Doe (jdoe#email.com)
How can I use a conditional (<c:if> with <c:else> or even the ? : ternary operator) to set the itemLabel attribute to render just the user.username without parenthesis if the user.name is empty string or null?
So, it should set to this (the e-mail address) if user.name is null or an empty string:
itemLabel="#{user.username}"
To make display (if user.name is null or empty string):
jdoe#email.com
Tried doing this:
itemLabel="#{not empty user.name ? user.name (user.username) : user.username}"
Which gives me the following stack trace:
javax.servlet.ServletException: Method not found: class com.myapp.model.User.name(java.lang.String)
at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:749)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:475)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
Caused by: javax.el.MethodNotFoundException: Method not found: class com.myapp.model.User.name(java.lang.String)
at javax.el.Util.findWrapper(Util.java:373)
at javax.el.Util.findMethod(Util.java:219)
at javax.el.BeanELResolver.invoke(BeanELResolver.java:149)
at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:79)
... 35 more
Don't understand why this is the case because the original attribute did find the User.getName() method:
itemLabel="#{user.name} (#{user.username})"
Is there a better way to do this?
Figured it out by using the += concatenation operator:
itemLabel="#{!empty user.name ? user.name += ' (' += user.username += ')' : user.username}"
I need your help is solving the error in the log. In my jsp, I am having selectmanycheckbox:
<?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">
<%# page deferredSyntaxAllowedAsLiteral="true" %>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:form>
<h:selectManyCheckbox value="#{com.favoriteCar2}">
<f:selectItems value="#{com.favoriteCar2Value}" />
</h:selectManyCheckbox>
<br/>
<h:selectManyCheckbox value="#{com.favoriteCar3}">
<f:selectItems value="#{com.favoriteCar3Value}" />
</h:selectManyCheckbox>
<h:commandButton value="Submit" action="results" />
<h:commandButton value="Reset" type="reset" />
</h:form>
and mybean:
import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class com implements Serializable{
private static final long serialVersionUID = 7134492943336358840L;
public String[] favoriteCar1;
public String[] favoriteCar2;
public String[] favoriteCar3;
public String[] favoriteCar4;
public String[] getFavoriteCar2Value()
{
favoriteCar2 = new String [5];
favoriteCar2[0] = "116";
favoriteCar2[1] = "118";
favoriteCar2[2] = "X1";
favoriteCar2[3] = "Series 1 Coupe";
favoriteCar2[4] = "120";
return favoriteCar2;
}
public String getFavoriteCar2InString()
{
return Arrays.toString(favoriteCar2);
}
private static Map<String, Object> car3Value;
static
{
car3Value = new LinkedHashMap<String, Object>();
car3Value.put("Car3 - 316", "BMW 316");
car3Value.put("Car3 - 318", "BMW 318");
car3Value.put("Car3 - 320", "BMW 320");
car3Value.put("Car3 - 325", "BMW 325");
car3Value.put("Car3 - 330", "BMW 330");
}
public Map<String, Object> getFavoriteCar3Value()
{
return car3Value;
}
public String getFavoriteCar3InString() {
return Arrays.toString(favoriteCar3);
}
}
The log is showing the error and no checkbox is shown in the jsp:
java.lang.IllegalArgumentException: Expected a child component type of UISelectItem/UISelectItems for component type javax.faces.SelectMany(j_id_id2). Found [Ljava.lang.String
Even I tried static children and it is not populating them.
So can you please help
It's because your SelectItems value is a String[], see the java docs regarding the value attribute of SelectItems in JSF 1.2 :
Value binding expression pointing at a List or array of SelectItem
instances containing the information for these options.
You are also returning the value of your selectManyCheckbox in the SelectItems which doesn't make sense, you should better learn more about how to use SelectItems. You can find many examples in the selectOneMenu wiki page which is very similar to the selectManyCheckbox, Or in The Java EE 6 Tutorial (Note that this links are JSF 2.0 but that may help you to understand the concept).
Regarding your example, that should be something like this:
private List<SelectItem> favoriteCar2Value;
// (we will add only a getter, setter is not necessary)
public List<SelectItem> getFavoriteCar2Value() {
favoriteCar2Value = new ArrayList<SelectItem>();
favoriteCar2Value.add(new SelectItem("116", "116 label"));
favoriteCar2Value.add(new SelectItem("118", "118 label"));
favoriteCar2Value.add(new SelectItem("X1", "X1 label"));
favoriteCar2Value.add(new SelectItem("Series 1 Coupe", "Series 1 Coupe label"));
favoriteCar2Value.add(new SelectItem("120", "120 label"));
return favoriteCar2Value;
}
Finnaly, maybe it's time for you to consider migrating to JSF 2.0 which may let you working with facelets instead of JSP, benefit from Ajax support... For a clear comparative see: What are the main disadvantages of Java Server Faces 2.0?
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.
I've tried to follow the solution in f:param or f:attribute support on primefaces autocomplete? to pass a parameter to primefaces 3.3.1 autocomplete component with no success. If I iterates in the Map returns by UIComponent.getCurrentComponent().getAttributes, it doesn't contain the attribute name I set in the .xhtml file, so I get a null pointer when I try to get the attribute. Is there any changes in primefaces implementation after the solution above?
I'm using Eclipse Indigo with Glassfish 3.1.2 and Mojarra 2.0.9.
Part of my code
xhtml :
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions"
template="WEB-INF/template.xhtml">
...
<p:autoComplete
id="sourceSubMemberLookup" value="#{transactionTransferBacking.sourceSubMember}"
size="64"
completeMethod="#{transactionTransferBacking.completeSourceOpSubMember}"
var="smb" itemLabel="#{smb.displayText}" itemValue="#{smb}"
converter="opSubMemberConverter"
forceSelection="true" dropdown="true"
required="true" rendered="#{loggedInUser.subMemberType eq 1}" >
<f:attribute name="attrSourceMemberId" value="#{transactionTransferBacking.sourceMember.Id">
</p:autoComplete>
...
</ui:composition>
java :
package com.mysoft.backing;
import java.io.Serializable;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.servlet.http.HttpServletRequest;
import javax.enterprise.context.RequestScoped;
#Named
#ManagedBean
#RequestScoped
public class TransactionTransferBacking implements Serializable {
...
public List<OpSubMember> completeSourceOpSubMember(String query) {
List<OpSubMember> members=null;
//Retrieve list of submembers based on partial user input (autocomplete)
//Based on loggedInUser own member's memberId
FacesContext context = FacesContext.getCurrentInstance();
if (context==null) this.getLogger().debug("completeSourceOpSubMeber: faces is null");
UIComponent current = UIComponent.getCurrentComponent(context);
this.getLogger().debug("completeSourceOpSubMember: currentComponent="+current.getId());
//Map<Object, Object> attrMap = context.getAttributes();
Map<String, Object> attrMap = current.getAttributes();
for (Map.Entry entry : attrMap.entrySet()) {
this.getLogger().debug("completeSourceOpSubMember: attrMap.Key="+entry.getKey());
}
int memberId = (int) attrMap.get("attrSourceMemberId");
this.getLogger().debug("completeSourceOpSubMember: MemberId from attribute = "+memberId);
...
return members;
}
}
The log correctly print the current component name as the desired AutoComplete, but the problem is "attrSourceMemberId" is not in the "attrMap" Map, as printed in the log.
Thank you, guys.