I have the following dropdown in a Facelets page:
<h:selectOneMenu value="#{contactBean.selectedContact}" converter="#{contactConverter}">
<f:selectItems value="#{contactsHolder.contacts}" var="contact"
itemLabel="#{contact.firstName}" itemValue="#{contact}" />
</h:selectOneMenu>
The problem is, no matter what I put in for itemLabel (JSF EL expression or just plain text), it doesn't display. Any idea what I'm doing wrong?
Here's ContactConverter:
#ManagedBean(name = "contactConverter")
#RequestScoped
public class ContactConverter implements Converter, Serializable {
#ManagedProperty(value = "#{contactsHolder}")
private ContactsHolder contactsHolder;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return contactsHolder.getContacts().get(value);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Contact) value).getContactID();
}
//getter & setters...
}
And ContactsHolder:
#ManagedBean
#SessionScoped
public class ContactsHolder implements Serializable {
private Map<String, Contact> contacts;
#PostConstruct
public void init() {
contacts = new LinkedHashMap<String, Contact>();
//get Contacts data and populate map...
}
//getters & setters...
}
You're feeding a Map<String, Contact> to <f:selectItems value>. Each item in var attribute will be a Map.Entry<String, Contact> which has only getKey() and getValue() methods returning the String map key and Contact map value respectively. The Map.Entry class indeed doesn't have a getFirstName() method.
Fix it accordingly:
<f:selectItems value="#{contactsHolder.contacts}" var="contact"
itemLabel="#{contact.value.firstName}" itemValue="#{contact.value}" />
Or, if you target a Servlet 3.0 / EL 2.2 capable container which allows invoking non-getter methods, so that you can use Map#values() to get a Collection<Contact>:
<f:selectItems value="#{contactsHolder.contacts.values()}" var="contact"
itemLabel="#{contact.firstName}" itemValue="#{contact}" />
Or, make the #{contactsHolder.contacts} a List<Contact> instead so that your initial view code will work:
<f:selectItems value="#{contactsHolder.contacts}" var="contact"
itemLabel="#{contact.firstName}" itemValue="#{contact}" />
Related
I'm trying to Write my own converter
I want to Inject my EJBs into my converter with #EJB .
my #EJB works in Other my ManagedBean but it doesn't work here in my converter
#ManagedBean
#ViewScoped
public class ServerTypeConverter implements Converter {
#EJB
private ServerTypeFacade serverTypeFacade;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
} else {
int id = Integer.parseInt(value);
return serverTypeFacade.findById(id);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
} else {
Integer id = ((ServerType) value).getServer_type_id();
return String.valueOf(id);
}
}
}
ServerTypeFacade returns null. why ?
here is the way i use converter
<h:selectOneMenu value="#{serverMB.selectedServerType}">
<f:converter converterId="serverTypeConverter"/>
<f:selectItems value="#{serverMB.serverTypesList}" var="servertypes" itemLabel="#{servertypes.server_type_name}" />
<f:ajax listener="#{serverMB.changeServerType}" render="dd" />
</h:selectOneMenu>
The #EJB in converter works only if you declare it as a managed bean by #ManagedBean and use it as managed bean by #{serverTypeConverter}.
However, you're using the converter as a faces converter by converterId="serverTypeConverter". Apparently you've also declared it as a faces converter by #FacesConverter on the class or <converter> in faces-config.xml.
Those two ways of declaring and using the converter are mutually exclusive. In order to get #EJB to work, you should be using the converter as a managed bean:
<f:converter binding="#{serverTypeConverter}" />
See also:
CDI Injection into a FacesConverter
This question already has answers here:
Pick Custom Object from Select one menu JSF [duplicate]
(2 answers)
Closed 9 years ago.
i want to pick custom object from select one menu. it neither shows an error nor values. what to do? please help me. thanks in advance.
Now i'm seeing Null pointer exception at getAsObject at this line:
return getCurrencyService().getCurrencyBtId(currencyId);
this is my xhtml document
<h:panelGrid columns="2">
<p:outputLabel value="" />
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currency}" converter="currencyConverter" >
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency}" itemLabel="#{currency.currencyName}" >
</f:selectItems>
<p:ajax update="currencyOut" />
</p:selectOneMenu>
<p:outputLabel value="Currency Id : #{CurrencyMB.currency.currencyId}" id="currencyOut" />
</h:panelGrid>
this is my managedBean class.
#ManagedBean(name = "CurrencyMB")
#RequestScoped
public class CurrencyManagedBean implements Serializable{
private Currency currency;
private List<Currency> currencyList;
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public List<Currency> getCurrencyList() {
currencyList = new ArrayList<Currency>();
currencyList.addAll(getiCurrencyService().getCurrencies());
return currencyList;
}
public void setCurrencyList(List<Currency> currencyList) {
this.currencyList = currencyList;
}
}
this is my currencyConverter class code:
**#FacesConverter("currencyConverter")
public class CurrencyConverter implements Converter {
#ManagedProperty(value = "#{currencyService}")
private ICurrencyService currencyService;
public ICurrencyService getCurrencyService() {
return currencyService;
}
public void setCurrencyService(ICurrencyService currencyService) {
this.currencyService = currencyService;
}
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) {
int currencyId = Integer.valueOf(value);
return getCurrencyService().getCurrencyBtId(currencyId);
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
Currency currency = (Currency) value;
int currencyId = currency.getCurrencyId();
return String.valueOf(currencyId);
}
}**
As it can be seen in many questions, and their answers, here, #FacesConverter is not eligible for injection. In your case, you try to inject your service via #ManagedProperty, which yields NPE, as Luiggi told you in a comment to your initial question.
With the current JSF release, all you can do to inject services in your converters is to give up using #FacesConverter and switch to using standard #ManagedBean annotation, thus referring to your converter not by id, but by bean name, like in converter="#{currencyConverter}".
Form snippet:
<h:selectOneMenu id="supervisor" value="#{newTopic.supervisor}">
<s:objectConverter/>
<f:selectItems value="#{supervisors}" var="_supervisor"
itemValue="#{_supervisor}"
itemLabel="#{_supervisor.name.firstName} #{_supervisor.name.lastName}"></f:selectItems>
</h:selectOneMenu>
<h:commandButton action="#{newTopicAction.createTopic}" value="Create topic"/>
Controller action:
#Model
public class NewTopicAction implements Serializable{
#Inject
private TopicManager topicManager;
private ThesisTopic newTopic;
public String createTopic(){
topicManager.createTopic(newTopic);
return "topics?faces-redirect=true";
}
#PostConstruct
public void init(){
newTopic = new ThesisTopic();
}
#Produces
#Model
public ThesisTopic getNewTopic(){
return newTopic;
}
}
Why isn't newTopic.supervisor populated with selected supervisor, when newTopicAction.createTopic is invoked? Every other field works as expected, except this one. It may be something about selectOneMenu what i don't understand properly.
I'm using the PrimeFaces p:autoComplete widget in a search form of my project. The user can choose how many and which form-elements (search parameters) he wants to include so I need to pass an ID to the completeMethod for each of them. I've tried adding onfocus=".." to pass the object to the bean but that only would be activated when the element first is loaded.
My question: How can I pass an attribute to the completeMethod?
XHTML of the element (simple):
<p:autoComplete value="#{filter.value}" label="dynamic search attribute"
completeMethod="#{myBean.complete}" />
The bean (simple):
#Named("myBean")
public class MyController implements Serializable {
public List<String> complete(String query) {
List<String> results = new ArrayList<String>();
// ... code
return results;
}
}
In theory this would seem like the perfect solution:
<p:autoComplete value="#{filter.value}" label="dynamic search attribute"
completeMethod="#{myBean.complete(filter)}" />
And again the bean:
#Named("myBean")
public class MyController implements Serializable {
public List<String> complete(String query, FilterObject o) {
List<String> results = new ArrayList<String>();
// ... database query based on FilterObject o
return results;
}
}
You can set it as an attribute:
<p:autoComplete value="#{filter.value}" label="dynamic search attribute" completeMethod="#{myBean.complete}">
<f:attribute name="filter" value="#{filter}" />
</p:autoComplete>
and get it by UIComponent#getCurrentComponent():
public List<String> complete(String query) {
FacesContext context = FacesContext.getCurrentInstance();
FilterObject o = (FilterObject) UIComponent.getCurrentComponent(context).getAttributes().get("filter");
// ...
}
Alternatively, as that #{filter} appears in your case to be already in the EL scope, you can also leave the <f:attribute> away and get it by evaluating the EL expression programmatically with help of Application#evaluateExpressionGet():
public List<String> complete(String query) {
FacesContext context = FacesContext.getCurrentInstance();
FilterObject o = context.getApplication().evaluateExpressionGet(context, "#{filter}", FilterObject.class);
// ...
}
Or, if it is also a #Named bean, then you can just #Inject it in the parent bean:
#Inject
private FilterObject o;
I'm trying to inject a ManagedBean in my FacesConverted the following way:
#ManagedBean
#RequestScoped
#FacesConverter(forClass = Group.class)
public class GroupConverter implements Converter {
#ManagedProperty("#{groupService}")
private GroupService groupService;
#Override
public Group getAsObject(FacesContext context, UIComponent arg1,
String groupName) {
return groupService.findGroupByName(groupName);
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object group) {
return ((Group) group).getName();
}
public GroupService getGroupService() {
return groupService;
}
public void setGroupService(GroupService groupService) {
this.groupService = groupService;
}
}
The problem is that groupService isn't being injected and I get a NullPointerEx. Shouldn't it be autowired automatically since it's also a ManagedBean? It all works when I change "getAsObject" to "return new Group();" obviously.
Any ideas?
It is likely that you are not resolving the managed bean name.
#ManagedBean(name = "myConverter")
#RequestScoped
#FacesConverter(value = "myConverter")
public class MyConverter implements Converter {
For example, consider these two components:
<h:inputText converter="myConverter" value="#{foo.prop}" />
<h:inputText converter="#{myConverter}" value="#{bar.prop}" />
When the converter is set on the first component, it will be created by Application.createConverter. A converter is not a managed bean. The same rules apply if you match a converter by type.
In the second component, a value expression is used to return a class that implements Converter. This uses the usual managed bean mechanisms. In this case, the #FacesConverter annotation is irrelevant.