I am developing a custom JSF UIInput which will expect a specially crafted value from the user. In order to validate the user input, I need to run a series of checks which relate only the application at hand. It's not just a normal email, or phonenumber input field. It's a text input which has a composite value that needs to be deconstructed into parts and each part needs to be validated.
I managed to create the component itself.
#FacesComponent("MyComponent")
public class MyComponent extends UIInput {
public String getFamily() {...}
encodeBegin() {...}
encodeEnd() {...}
}
mycomponent.taglib.xml is bundled inside META-INF and I can use and test the component successfully.
I also have a validator class implemented which does all the work. It's ready.
public class AutomationDetectionValidator implements Validator {
public void validate(...) throws ValidatorException {...}
}
However, I need to include a custom validator to this component as a default. I can do this manually as follows:
<custom:myComponent>
<f:validator validatorId=”myComponentValidator”/>
</custom:myComponent>
But the expected usage would be
<custom:myComponent/>
And the validator should be there automatically.
I've been googling all day now, but I can find are basic examples of the usage we don't want.
Just add it in component's constructor.
public MyComponent() {
addValidator(new AutomationDetectionValidator());
}
Related
In a JSF project, we wrote our own PartialViewContext to listen to some events fired by pages beans:
#RequestScoped
public class OurPartialViewContext extends PartialViewContextWrapper
{
...
// called by cdi
#SuppressWarnings("unused")
private void listenForUpdate(#Observes OurRefreshEvent event)
{
...
And we wrote the matching factory, injecting it:
public class OurPartialViewContextFactory extends PartialViewContextFactory
{
#Inject
private OurPartialViewContext customPartialViewContext;
...
Problem is that in the newest versions of JSF, the empty constructor for PartialViewContextWrapper is deprecated, asking us to use another constructor with the wrapped object in parameter.
Currently, our PartialViewContext needs to be tied to the request scope, in order to be modified during the request by the observed events and to be used by a custom PartialResponseWriter we also wrote.
So our PartialViewContext currently both:
must have an empty constructor, as it is a #RequestScoped bean;
should not have an empty constructor, as it is deprecated for PartialViewContextWrapper which it inherits from.
How could we find a solution there?
We tried to remove it from the scope and build it in the Factory with a simple new OurPartialViewContext(), but then the #Observes methods are never called.
You are required to pass the wrapped instance into the constructor and to use getWrapped() over all place in delegate methods. Otherwise your application will most probably not work when you install other JSF libraries which also ship with their own PartialViewContext implementation such as OmniFaces and PrimeFaces. You would be effectively completely skipping the functionality of their PartialViewContext implementation. This mistake was previously observed in too many custom implementations of factory-provided classes. Hence the urge to mark the default constructor as #Deprecated so that the developers are forced to use the proper design pattern.
Your specific issue can be solved by simply refactoring the listenForUpdate() method into a fullworthy request scoped CDI bean, which you then inject in the factory who in turn ultimately passes it into the constructor of your PartialViewContext implementation.
Thus, so:
#RequestScoped
public class OurEventObserver {
public void listenForUpdate(#Observes OurRefreshEvent event) {
// ...
}
}
public class OurPartialViewContextFactory extends PartialViewContextFactory {
#Inject
private OurEventObserver observer;
public OurPartialViewContextFactory(PartialViewContextFactory wrapped) {
super(wrapped);
}
#Override
public PartialViewContext getPartialViewContext(FacesContext context) {
PartialViewContext wrapped = getWrapped().getPartialViewContext(context);
return new OurPartialViewContext(wrapped, observer);
}
}
public class OurPartialViewContext extends PartialViewContextWrapper {
private OurEventObserver observer;
public OurPartialViewContext(PartialViewContext wrapped, OurEventObserver observer) {
super(wrapped);
this.observer = observer;
}
// ...
}
Inside any of the overridden methods of OurPartialViewContext you can simply access the state of the observer, provided that the listenForUpdate() modifies some instance variables representing the state.
Implementation: org.glassfish 2.2.12
I have the following session-scoped validator:
#ManagedBean
#SessionScoped
public class CreateGroupNameValidator extends LengthValidator implements Serializable{
#ManagedProperty(value="#{myDao}")
private MyDao myDao;
//Validate methods
}
In spite of being session-scoped and Serializable, the validator fails to restore the value of the property myDao when postback comes. I used debugger and figuredOut that the state is saved by the class StateHolderSaver which has the following consturctor:
public StateHolderSaver(FacesContext context, Object toSave) {
className = toSave.getClass().getName();
if (toSave instanceof StateHolder) {
// do not save an attached object that is marked transient.
if (!((StateHolder) toSave).isTransient()) {
Serializable [] tuple = new Serializable[StateHolderTupleIndices.LastMember.ordinal()];
tuple[StateHolderTupleIndices.StateHolderSaverInstance.ordinal()] =
(Serializable) ((StateHolder) toSave).saveState(context);
if (toSave instanceof UIComponent) {
tuple[StateHolderTupleIndices.ComponentAddedDynamically.ordinal()] = ((UIComponent)toSave).getAttributes().containsKey(DYNAMIC_COMPONENT) ? Boolean.TRUE : Boolean.FALSE;
}
savedState = tuple;
} else {
className = null;
}
} else if (toSave instanceof Serializable) {
savedState = (Serializable) toSave;
className = null;
}
}
So, since LenghtValidator implements javax.faces.component.StateHolder it didn't save my initial Dao value. Is it a normal behavior?
This is indeed specified behavior. See also a.o. Validator javadoc:
...
Validator implementations must have a zero-arguments public constructor. In addition, if the Validator class wishes to have configuration property values saved and restored with the view, the implementation must also implement StateHolder.
...
Converters and validators can be saved in JSF state so that the JSF implementation can ensure that they have after restoring the view exactly the intented property values as they were during rendering the view of the previous request (such as minimum and maximum in case of LengthValidator, might it happen that they refer a dynamic EL expression).
Although I must admit that they did during designing the JSF 1.0 specification (on which the converter/validator is still based) not really thought about the possibility to inject business service instances in a JSF converter/validator. You of course don't want to save it in the JSF view state. In case of managed properties (and thus not EJB/CDI proxies), it would only blow up the JSF view state (and thus also the HTTP session in case of server side state saving).
If you don't need your validator being JSF state aware, use composition instead of inheritance.
public class CreateGroupNameValidator {
private LengthValidator lengthValidator;
public CreateGroupNameValidator() {
lengthValidator = new LengthValidator();
}
// ...
}
Nonetheless, putting a validator in the session scope is kind of fishy. This implies that the validator's behavior is specific to the current HTTP session. I can't think of sensible real world use cases for this as they are inherently view scoped (not the validator instances but the validator properties). Usually the session scoped data (such as logged-in user) is instead injected/resolved on a thread local basis. You'd better make it request scoped if it's stateful (i.e. validator properties may vary on a per request/view basis), or application scoped if it's stateless (i.e. validator properties are the same throughout application's lifetime).
I'm trying to understand the working principles of UIInput component and EL-expressions in JSF. Here is the code fragment of UIInput component source code:
public void updateModel(FacesContext context) {
if (context == null) {
throw new NullPointerException();
}
if (!isValid() || !isLocalValueSet()) {
return;
}
ValueExpression ve = getValueExpression("value");
if (ve != null) {
Throwable caught = null;
FacesMessage message = null;
try {
ve.setValue(context.getELContext(), getLocalValue()); //1
setValue(null);
setLocalValueSet(false);
}
//catch clause
Now, I have a simple bean and the input component binded to its property:
<h:inputText value="#{myBean.hello}" />
#ManagedBean
#SessionScoped
public class MyBean{
private String hello;
//getter,setter
}
As far as I understand, the updateModel method is called by the inherited from the UIComponentBase class processUpdates(FacesContext) method which is a standard callback for the Update Model Values phase. So, after setting breakpoint at //1 and performing step next the flow's stopped at the corresponding bean property setter method.
My question is about of purpose of javax.el.ValueExpression. Is it resposible for all interatctions (incapsulates) between the component class and the bean's property in order for getting/setting values to bean's properties?
EL is like a "path" and is needed to navigate the bean. The UIInput is the MVC "view" to the MVC "model" represented by your bean. EL links the two together. It only encapsulates the traversal itself. It identifies the subject of the interaction, but the interactions are defined by the component class. Compare h:outputText to h:inputText: both basically take a value="#{some.el}" attribute; the fact that one allows the user to modify it is a fact about the component, not the path to the bean property itself.
Some components define attributes that should be populated by references to methods rather than bean properties, but again, the EL is just the traversal—invoking those methods is something the component does. And in that case you would be dealing with a MethodExpression instead of a ValueExpression.
The JSF lifecycle dictates that things happen in a certain overall order, but the component author still has ample opportunity to be creative (or wreak havoc) by doing things their own way.
I'm looking for a minimal example on how to pass a method expression to a custom component. I tried the following, but the responsible setter of my component is never called.
Bean for my view:
public String bar(){
//do stuff
return "";
}
My view:
<my:comp foo="#{bean.bar}" />
Bean for my component:
private static final String FOO = "foo";
public void setFoo(MethodExpression me){
//never called
getStateHelper().put(FOO, me);
}
public MethodExpression getFoo(){
//actually gets called
return (MethodExpression) getStateHelper().get(FOO);
}
Inside my component renderer, I call component.getFoo() and get a NPE.
You need to implement the ActionSource2 interface:
#FacesComponent(MyComponent.COMPONENT_TYPE)
public class Mycomponent extends UIComponentBase implements ActionSource2 {
// ...
}
Or, easier, to extend from UICommand class (which are also used by <h:commandXxx> components) which has all of those ActionSource2 methods already implemented the right way so that you don't need to repeat the job:
#FacesComponent(MyComponent.COMPONENT_TYPE)
public class Mycomponent extends UICommand {
// ...
}
Either way, you can use action="#{some method expression}" and even attach actionlisteners on it. Note that you can't rename the attribute name action. It really has to be action.
An open source example of such a custom component is the OmniFaces <o:commandScript>. The source code is available here.
I have a request scoped CDI manage bean(Also tried with jsf managed bean but the same problem!) :
#Named
#RequestScoped
public class myController{
private HashMap<String, MyModel> modelMap;
#PostConstruct
private void init() {
logModelMap = new HashMap<String, MyModel>();
logModelMap.put("CONSTANT_1", new MyModel());
logModelMap.put("CONSTANT_2", new MyModel());
logModelMap.put("CONSTANT_4", new MyModel());
}
public HashMap getModelMap() {
return logModelMap;
}
}
And MyModel class which is a simple pojo:
public class MyModel{
private String type = "";
private Date date;
//constructor, getter and setter methods
}
I have written a composit component using jsf and bind fields to textbox and calendar and I want to access fields inside hashmap and set some values:
#{myController.modelMap['CONSTANST_1'].type}
#{myController.modelMap['CONSTANST_1'].date}
#{myController.modelMap['CONSTANST_2'].type}
#{myController.modelMap['CONSTANST_2'].date}
#{myController.modelMap['CONSTANST_3'].type}
#{myController.modelMap['CONSTANST_3'].date}
but just the first two lines for constant_1 works and for other two constants, type and date are null !
I saw in firebug that values are sent to server properly but fields inside map are not set!
By the way I'm using primefaces command button with ajax to send data to server.
Finally I got where the problem was.
I had nested forms!!!
One form that wraps my composite component and one form where I used my composite component!