How to pass the validator method to a composite component - jsf-2

I have my own inputText composite component created which wraps the p:inputText from Primefaces 3.4.5. It works well, but I can not figure out how to pass a bean validator method to the validator attribute in the p:inputText. I have read about using f:validator tags inside the composite component, but I really need to use the validator attribute on the p:inputText. The method and validation code works fine if I remove the composite component from my xhtml and just use a regular p:inputText.
My cc attribute is:
<composite:attribute name="validator" method-signature="void f(javax.faces.context.FacesContext,
javax.faces.component.UIComponent,
java.lang.Object)" targets="inputTextField"/>
my inputText inside the composite component is:
<p:inputText id="inputTextField"
... other attributes ...
validator="#{cc.attrs.validator}" />
when I use this composite component and pass a validator method to it, I get a property not found message...
Exception type: class javax.el.PropertyNotFoundException
Exception message: /view/configuration/dictionaryupdate/DictionaryItem.xhtml #27,123 validator="#{dictionaryUpdateController.validateCode}": The class 'com.ntst.caremanager.feature.dictionaryupdate.controllers.DictionaryUpdateController' does not have the property 'validateCode'.
However, I do have that method defined in my view-scoped controller bean:
public void validateCode(FacesContext context, UIComponent component, Object value) throws ValidatorException {
... code ....
}
Does anyone know what I am missing?
I am using Mojarra 2.1.21
Thank you

Related

#FacesConverter without converter-id and forClass

What should work properly if I do not specify the converter-id and(or) forClass in determining the #FacesConverter annotation?
For example:
#FacesConverter
public class SplitConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
//...
}
#Override
public String getAsString(FacesContext context, UIComponent component,
Object value) {
//...
}
After registred in faces-config.xml and use that on .xhtml page:
<h:inputText id="badges" value="#{article.badges}"
required="true">
<f:converter converterId="com.katcgr.SplitConverter" />
</h:inputText>
And all is work. The documentation say that
if converter-id is the empty string, Application.addConverter(java.lang.Class,java.lang.String) is called, passing the converter-for-class as the first argument and the derived converter-class as the second argument.
But why everything works fine even if I not specified the forClass ?
After registred in faces-config.xml
Registration via #FacesConverter and <converter> in faces-config.xml are mutually exclusive whereby the XML registration overrides any annotation registration. So, when your converter is referenced via the converter ID as registered in XML, then the converter instance behaves basically exactly as if it had no annotations. If you remove the XML registration, then you should have retrieved the below exception on specified converterId:
javax.faces.FacesException: Expression Error: Named Object: com.katcgr.SplitConverter not found.
at com.sun.faces.application.ApplicationImpl.createConverter(ApplicationImpl.java:1339)
at javax.faces.application.ApplicationWrapper.createConverter(ApplicationWrapper.java:393)
at com.sun.faces.facelets.tag.jsf.ConverterTagHandlerDelegateImpl.createConverter(ConverterTagHandlerDelegateImpl.java:158)
...
This would basically only work if you had a
#FacesConverter("com.katcgr.SplitConverter")
If you however remove both the XML configuration and the <f:converter>, then it will "work" because the #FacesConverter without an explicit forClass will be automatically invoked for every bean property which is an instance of java.lang.Object (basically, everything), which does not have a more specific converter already registered. In other words, your converter will behave like:
#FacesConverter(forClass=Object.class)
It hopefully doesn't need an elaborate explanation that this is a terribly bad idea. It will also confuse PrimeFaces, because it will then internally initialize and use it as default converter for String class.

Use ManagedBean in FacesConverter

I want to use ManagedBean in my Converter. The ManagedBean is responsible for getting data from database. In Converter I want to convert string into object which must be get from database.
This is my Converter
#FacesConverter(forClass=Gallery.class, value="galleryConverter")
public class GalleryConverter implements Converter {
// of course this one is null
#ManagedProperty(value="#{galleryContainer}")
private GalleryContainer galleryContainer;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String galleryId) {
return galleryContainer.findGallery(galleryId);
...
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object gallery) {
...
}
}
I know that galleryContainer will be null and if I want to inject ManagedBean into Converter I can mark it as ManagedBean too. The problem is that I want to do it in beautiful way, I don't want to look for some 'strange solution'. Maybe the problem is in my application? Maybe there is some other good solution to create object which must get data from database and used in converter? I want also to mention that I will prefer to use DependencyInjection instead of creating new object using new statement (it is easier to test and maintain). Any suggestions?
Instead of using #FacesConverter you should use #ManagedBean, because currently faces converter isn't a valid injection target. Nonetheless, you can choose your converter to be a managed bean, thus refer to it in your view as converter="#{yourConverter}" (by managed bean name) instead of converter="yourConverter" (by converter id).
Basic usage example:
#ManagedBean
#RequestScoped
public class YourConverter implements Converter {
#ManagedProperty...
...
//implementation of converter methods
}
Of course, reading BalusC's invaluable Communication in JSF 2.0 will shed some light on this question as well.
It is also worth mentioning that the scope of your converter bean may be changed to, for example, application or session, if it is not supposed to hold any state.

beans properties and modelDriven in struts 2

I am new to struts 2. I created an action class that insert data from JSP page to a bean using ModelDriven interface.
The problem is that i have some non 'Stringproperties in the bean likeLong,Date` ... etc
The problem is:
when i press submit button in the jsp page i get an error saying that it did not find the a string setter for that particular property.
for example if i have in my bean
package com.hsms.aseza.enteringApproval
Class EnteringApproval
private Date approvalDate
Date getApprovalDate()
{
return employeeId;
}
void setApprovalDate(Date employeeId)
{
this.employeeId = employeeId;
}
when the action class that implement the model driven is executed, it fires a run time exception
java.lang.NoSuchMethodException: com.hsms.aseza.enteringApproval.EnteringApproval.setApprovalDate([Ljava.lang.String;)
Is there anyway to solve this problem without writing a String setter for my Date property?
I think that your problem is conversion i.e. conversion from String to your java.util.Date Object. This class extends this which is responsible for converting from String to other types like Long, Double etc. If you check the source code for DefaultTypeConverter, you won't see any conversion for either java.util.Date or java.sql.Date. So i think what you should do is to write a converter for approvalDate. My previous post on this will guide you on the procedure, all you will need is to edit the code to suit your needs.
On your jsp, follow this datepicker example
Use the same format i.e date format used to display your date in your jsp with SimpleDateFormat to do your conversion in convertFromString method of your converter and return the converted java.util.Date or java.sql.Date.
Let me know if you have issues implementing this.
Try use the s:date tag in your jsp.
Edit:
Try use:
<s:textfield key="objEnteringApproval.approvalDate"></s:textfield>
in which objEnteringApproval is your public accessible variable in your controller.
Make sure you have initialized your bean in your action class
Private YourBean bean = new YourBean();
Or you can have it in the constructor
Make sure your getter and setter are public
If you are trying to type date on the jsp page, please use datepicker e.g. sx:datetimepicker or sj:datepicker

JSF 2.0 view parameters to pass objects

I am trying to pass an object from one page to another page where each page is in a different view.
On the first page I have an input text, where myBean is a ViewScoped Bean and name is an object.
<h:inputText value="#{myBean.name}"/>
The second page contains,
<f:metadata>
<f:viewParam name="userId" value="#{myBean.name}"/>
</f:metadata>
I get the error Conversion Error setting value mypackage.myBean#257100b' for 'null Converter'.
Can we pass objects other than String values to view parameters?
Yes, you can. You just have to supply a converter which converts between the string representation of the object type behind #{myBean.name} and the real object. The string representation is usually the unique technical/natural identifier of the object in question. For example, the table's PK. It has got to be a string, simply because HTTP request parameters can be strings only. You can't pass complex Java objects around in URLs. URLs are just strings.
Here's a kickoff example:
E.g. the following in the initial view:
<h:link value="Edit" outcome="edit">
<f:param name="id" value="#{personViewer.person.id}" />
</h:link>
(which generates an Edit)
and the following in the linked view:
<f:metadata>
<f:viewParam name="id" value="#{personEditor.person}"
converter="#{personConverter}" converterMessage="Bad request. Unknown person."
required="true" requiredMessage="Bad request. Please use a link from within the system."
/>
</f:metadata>
<h:messages />
with this converter
#ManagedBean
#RequestScoped
public class PersonConverter implements Converter {
#EJB
private PersonService personService;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return String.valueOf(((Person) value).getId());
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return personService.find(Long.valueOf(value));
}
}
(oversimplified; all null/number checks omitted, but you got the idea)
See also:
Communication in JSF 2.0 - Converting and validating GET request parameters
Update as per the comments, you actually want to fire a POST request. You don't need a <f:viewParam> at all. It's for setting/validating/converting GET request parameters only. Attempting to serialize the whole object makes also no utter sense. Just use #ManagedProperty.
E.g.
#ManagedBean
#ViewScoped
public class PersonEditor implements Serializable {
#ManagedProperty("#{personViewer.person}")
private Person person;
// ...
}
It's only not bookmarkable anymore and not SEO-friendly (but that's the nature of POST, you're probably already for long aware of this). Note that the #{personViewer} bean must by itself also be #ViewScoped (and thus not #ReqestScoped). You also need to make sure that you don't navigate back with a redirect, but just a forward.

Composite component backing bean location

I'm trying to split my JSF2 pages into composite components. So I decided to put the composite components in a logical file tree. For example:
WebContent/resources/components/page1/component1.xhtml
The associated bean is in
Java resources/src/components/page1/component1.java
Its package is this components.page1.
In this example, component1.xhtml is found and rendered, but the bean is not found by the server.
If I don't use a subpackage:
WebContent/resources/page1/component1.xhtml
Java resources/src/page1/component1.java
So when the class is in the package page1, it works!
Is there a problem with composite component beans and subpackages?
I am using MyFaces 2.0, Tomcat 6 and Eclipse.
You need the componentType attribute of <cc:interface> to explicitly specify the backing component.
<cc:interface componentType="component1">
with
package components.page1;
#FacesComponent("component1")
public class Component1 extends UINamingContainer {
// ...
}

Resources