I'm just setting up a simple testclass. Code completions works in eclipse, but I cannot launch the page:
backing bean:
#Named
#RequestScoped
public class TestBean {
public String getString() {
return "click me";
}
}
jsf:
<h:commandButton value="#{testBean.getString()}" />
also tried testBean.string and testBean.getString.
exception:
javax.servlet.ServletException: input.xhtml #41,52 value="#{testBean.getString()}":
The class 'TestBean$Proxy$_$$_WeldClientProxy' does not have the property 'getString'.
What is wrong here??
In JSF you don't use parentheses or the "get" part of the name.
Use this instead.
<h:commandButton value="#{testBean.string}" />
Related
I think the issue is pretty common, but for some reason I cannot manage to fix this.
This is the error I am getting:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reverseController' defined in ServletContext resource [/WEB-INF/app-servlet.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Validator [FormValidator#6b3ded0d] does not support command class [ReverseString]
This is the supports method in my FormValidator class:
public boolean supports(Class clazz) {
return ReverseController.class.isAssignableFrom(clazz);
}
This is the bean definition on my app-servlet.xml:
<bean id="reverseController" class="ReverseController">
<property name="commandName"><value>reverseString</value></property>
<property name="commandClass"><value>ReverseString</value></property>
<property name="formView"><value>reverse</value></property>
<property name="successView"><value>reverseResult</value></property>
<property name="validator"><bean class="FormValidator" /></property>
And finally, this is the main part of my ReverseController:
#Service
public class ReverseController extends SimpleFormController {
public ReverseController() {
//setCommandClass(ReverseString.class);
//setCommandName("reverseString");
}
private ReverseString reverseStringMaster;
#Autowired
public void setWriter(ReverseString reverseStringMaster) {
this.reverseStringMaster = reverseStringMaster;
}
protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors) {
ReverseString revString = (ReverseString) command;
return new ModelAndView(getSuccessView(),"reversedString", revString);
}
public void init() {
System.out.println("Done");
}
}
Any idea what might be causing that issue?
It's an instance of the command class that gets validated on each request - as this gets populated with form data. The controller itself is not validated.
So the supports() method in your FormValidator should actually read:
public boolean supports(Class clazz) {
return ReverseString.class.isAssignableFrom(clazz);
}
Did you add getters and setters for this commandClass variable as well as well? If so, you probably need to remove the #spring.validator type="required" from the setter method method.
Try this code for your app-servlet.xml
1.Define your controller like this.
2.then use reverseController to call ReverseController class method.
<managed-bean>
<managed-bean-name>reverseController</managed-bean-name>
<managed-bean-class>com.action.ReverseController</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
I have developed a navigation menu with primefaces tree component. The tree nodes have a Project object as data inside. I want to be able to load a view with the project details which loads dynamically when I click each project.
For that I have defined an ajax event select on the tree:
<h:form>
<p:tree value="#{treeBean.root}" var="node"
selection="#{treeBean.selectedNode}" id="tree" >
<p:ajax event="select" listener="#treeBean.onNodeSelect}"/>
<p:treeNode styleClass="treeNode">
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
</h:form>
Which calls a onNodeSelectMethod in the treeManagedBean:
#ViewScoped
#Component("treeBean")
#ManagedBean
public class TreeManagedBean{
private Project selectedProject;
public Project getSelectedProject(){
return selectedProject;
}
public void setSelectedProject(Project project){
this.selectedProject = project;
}
public void onNodeSelect(NodeSelectEvent event) {
this.selectedProject = (Project)event.getTreeNode().getData();
FacesContext context = FacesContext.getCurrentInstance();
ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) context.getApplication().getNavigationHandler();
handler.performNavigation("viewProject");
}
And then I load viewProject.xhtml via faces-config.xml, and populate the property in the other managedBean:
#Component("projectView")
#ViewScoped
#ManagedBean
public class ProjectView {
#ManagedProperty("#{treeBean.selectedProject}")
private Project project;
}
The view loads without any errors, but the property is never set. The ajax call works and is setting the property in the first bean. Is this the way to do it?
I solved it just adding an identifier to the managedBeans, for that I was obliged to provide a default constructor:
#ViewScoped
#Component("treeBean")
#ManagedBean("treeBean")
public class TreeManagedBean{
public TreeManagedBean(){}
}
and
#Component("projectView")
#ViewScoped
#ManagedBean("projectView")
public class ProjectView {
#ManagedProperty("#{treeBean.selectedProject}")
private Project project;
public ProjectView(){}
}
I have a (request-scoped) list from which the user may select a "PQ" (list of links). When clicked or otherwise entered into the browser the main page for each PQ shall be displayed. Each PQ's page is of the form
http://localhost:8080/projectname/main.jsf?id=2
Here's the PQ bean first:
#Named
#ViewScoped
public class PqHome implements Serializable
{
#PersistenceContext(unitName="...")
private EntityManager em;
private Integer id;
private PQ instance;
#PostConstruct
public void init()
{
System.out.println("ID is " + id); // ID from URL param
instance = em.find(PQ.class, id);
}
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public PQ getInstance()
{
return instance;
}
}
Here's the main.xhtml:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
...>
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{pqHome.id}">
<f:convertNumber integerOnly="#{true}" />
</f:viewParam>
<!--f:event type="preRenderView" listener="#{pqHome.init}" /-->
</f:metadata>
</ui:define>
<ui:define name="title">
<h:outputText value="Main" />
</ui:define>
...
</ui:composition>
Any time I select or otherwise refresh the page/URL I get a NullPointerException from the EntityManager:
org.jboss.weld.exceptions.WeldException: WELD-000049 Unable to invoke [method] #PostConstruct public de.mycomp.myproj.beans.PqHome.init() on de.mycomp.myproj.beans.PqHome#4f0ea68f
at org.jboss.weld.bean.AbstractClassBean.defaultPostConstruct(AbstractClassBean.java:595)
...
Caused by: java.lang.IllegalArgumentException: id to load is required for loading
at org.hibernate.event.spi.LoadEvent.<init>(LoadEvent.java:87)
at org.hibernate.event.spi.LoadEvent.<init>(LoadEvent.java:59)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:961)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:957)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:787)
at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:762)
at org.jboss.as.jpa.container.AbstractEntityManager.find(AbstractEntityManager.java:221)
at de.mycomp.myproj.beans.PqHome.init(PqHome.java:47)
... 56 more
[Line 47 is em.find(...)]
The line
<f:event type="preRenderView" listener="#{pqHome.init}" />
doesn't make things any better. I'm pretty desparate now.
How do you get URL GET request params into an #ViewScoped bean?
Note: I bet it's not a trivial thing to do. Chances are I'm doing something wrong here conceptually, so any tips on how to improve are welcome. I felt that I needed to choose #ViewScoped because there will be more complex AJAX-based GUI on that page which I'd really like to keep accessible via URL GET params.
Thanks
There is a better way to get id from url. Just use it in #PostConstruct init() method to get "id" from url:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
You can still use ViewScoped and #PostConstruct.
The #PostConstruct is invoked directly after bean's construction and all dependency injection (such as #PersistenceContext, #EJB, #ManagedProperty, #Inject, etc..etc..).
The <f:viewParam> sets its value during the update model values phase, which is far after (post)construction of the bean. So inside the #PostConstruct the <f:viewParam> value is simply not yet been set. It'll be still null at that point.
You're close with <f:event type="preRenderView">, but you have to remove the #PostConstruct annotation.
So:
<f:viewParam name="pq" value="#{pqHome.id}">
<f:convertNumber integerOnly="#{true}" />
</f:viewParam>
<f:event type="preRenderView" listener="#{pqHome.init}" />
with
private Integer id;
public void init() {
instance = em.find(PQ.class, id);
}
Unrelated to the concrete problem, I'd suggest to use a Converter for this instead. See also Communication in JSF 2.0 - Converting and validating GET request parameters.
Also the combination #Named #ViewScoped won't work as intended. The JSF-specific #ViewScoped works in combination with JSF-specific #ManagedBean only. Your CDI-specific #Named will behave like #RequestScoped this way. Either use #ManagedBean instead of #Named or use CDI-specific #ConversationScoped instead of #ViewScoped.
This question already has an answer here:
JSF does not populate #Named #RequestScoped bean with submitted input values
(1 answer)
Closed 5 years ago.
I have a bean with a field called 'name', and a JSF form that has an inputText mapped with this field. The initial value of the field is well displayed on the form.
The problem is when I submit the form, the value is not updated with the content of the inputText. In the savePlayer() method below, the value of name is always 'name', not what I typed inside the form input.
The bean :
#Named
#RequestScoped
public class PlayerForm {
#Inject
private PlayerRepository playerRepository;
private String name = "name";
public String savePlayer(){
Player player = new Player();
player.setName(name);
playerRepository.savePlayer(player);
return "saveUserOk";
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
The form :
<h:form>
<h:inputText value="#{playerForm.name}" />
<h:commandButton value="Submit" action="#{playerForm.savePlayer}" />
</h:form>
Thanks very much for any help!
This can happen if you imported #RequestScoped from the package javax.faces.bean (JSF) instead of from javax.enterprise.context (CDI). Every single EL expression #{} would then create a brand new and completely separate instance of the bean. The given form example would then end up in two instances of the bean, one where the name is set and another where the action is invoked.
The javax.faces.bean.RequestScoped annotation can only be used in conjunction with JSF's own #ManagedBean annotation not with CDI's #Named annotation.
I have <h:inputText> on form and what I need is to execute some method from backing bean on BLUR event:
public void test()
{
System.out.print("HELLO!");
}
Can you help me?
You can use <f:ajax>
<h:form>
<h:inputText value="#{managedBean.val}" >
<f:ajax event="blur" render="result" listener="#{managedBean.test}"/>
</h:inputText>
</h:form>
#ManagedBean(name = "managedBean")
public class Bean {
private String val; // getter and setter
...
public void test() {
System.out.print("HELLO!");
}
}
Alternative :
If you are using richfaces then you can use a4j:jsFunction
See Also
JSF2: Ajax in JSF – using f:ajax tag
How-to-update-a-value-displayed-in-the-page-without-refreshing