Get ManagedBeans in Custom JSF Validator dynamically - jsf

I want to validate values dynamically by using a custom validator that I can be used with several components. The custom validator gets those values from different ManagedBeans depending on its usage.
How to determine which ManagedBean the value is retrieved from? So I can get it, validate it, and put it back into a ManagedBean.
My Custom Validator:
#FacesValidator(value = "valid")
public class DateValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component,
Object value) throws ValidatorException {
// Bean bean = ?
}
}

I dont think that is good approach as in validation phase model is still not updated, what you are getting is just input value from view. I wonder why you need bean instance there. If your validation depends on other component in view you can refer link # SO and Validator for multiple fields.
As you refer you need to validate it and put back, thats why validation phase is all about, validate it in your validator and if it fails it will not be passed to managed bean.
Have a look at this link for JSF lifecycle JSF Lifecycle
Hope this helps !!!

Related

How to obtain submitted value from a custom JSF input component? [duplicate]

I have created a custom component. I add a dynamic input text box to it (from the encode function).
The component is correctly is rendered as HTML.
But I want to bind the value of the text box to some property on the Managed Bean. So some other developer can use the component on his jsp with his managed bean.
I want to know, what should I do, so that the value entered in the text box (which my component dynamically creates) is set to the some Managed bean property.
You need to ensure that your custom component class extends UIInput and that you're in the encodeEnd() method of your renderer writing the component's client ID as name attribute of the HTML input element. Then you can in the overriden decode() method of your renderer just grab the submitted value from the request parameter map with the component's client ID as parameter name and set it as UIInput#setSubmittedValue() and let JSF do the remnant of the job of converting, validating and updating the model value.
#Override
public void decode(FacesContext context, UIComponent component) {
// Do if necessary first validation on disabled="true" or readonly="true", if any.
// Then just get the submitted value by client ID as name.
String clientId = component.getClientId(context);
String submittedValue = context.getExternalContext().getRequestParameterMap().get(clientId);
((UIInput) component).setSubmittedValue(submittedValue);
}
Unrelated to the concrete problem, are you aware of the new composite component support in JSP's successor Facelets? I have the impression that you don't necessarily need a custom component for this purpose. Or are you really restricted to using the legacy JSP as view technology in spite of that you're already on JSF 2.x? See also When to use <ui:include>, tag files, composite components and/or custom components?
Well, the problem is solved.
In the encodeEnd() method I added the element as
HtmlInputHidden hidden = new HtmlInputHidden();
hidden.setParent(this);
hidden.setId("someId");
ValueExpression ve = getValueExpression("value");
hidden.setValueExpression("value", ve);
hidden.encodeBegin(context);
hidden.encodeEnd(context);
This seems to have some problem.
Then I changed this to ...
HtmlInputHidden hidden = new HtmlInputHidden();
hidden.setId("someId");
ValueExpression ve = getValueExpression("value");
hidden.setValueExpression("value", ve);
this.getChildren().add(hidden);
hidden.encodeBegin(context);
hidden.encodeEnd(context);
The use of this.getChildren().add(); solved my problem
P.S. Obviously before adding the element, it needs to be checked if the element is already present.

How to make a JSF custom component to store a custom type as its value?

Seems basic enough...
I have a custom JSF component and its associated renderer. The renderer does the decode and encodeEnd.
In decode i successfully retrie the submitted value via component.setSubmittedValue(ctx.getExternalContext().getRequestParameterMap().get(c.getClientId()));
In encodeEnd, i basically create the markup and if component.getValue() is not null, i insert its contents in the markup. So far so good.
Problem is that getValue() can be only be String. I have custom class that represents a compound data type and i want to use that as the component's local value. But doesn't work - JSF converts to String.
I also tried using component.getAttributes() - from the decode method, where i put my custom object in keyed to private static final String someKey = "asd". But later at encodeEnd there is no value/key in the map.
I want the users of this component to be able to specify in their backing bean the custom data type and not worry about serialization/deserialization to text representation between client/server. Presumably i have to use a converter for that? But how can i set up a default and immutable converter for the custom component?
The problem has a simple enough of a solution. Inside the Renderer class (or right into the Component class if using that directly):
#Override
public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
SomeCustomObject thing;
//... do magic to create SomeCustomObject based on submittedValue
return thing;
}
Now whenever getValue() is called on that component, SomeCustomObject will be returned and you can safely cast to it. Also in the backing beans can use SomeCustomObject as the type.
Also note when calling component.getValue() in the actual Renderer, it will return SomeCustomObject as well, so if you're restoring state, you must convert back to its String representation.
For more details see and #Kukeltje's answer above and check how the same thing is done for primefaces calendar component here: https://github.com/primefaces/primefaces/blob/master/src/main/java/org/primefaces/component/calendar/BaseCalendarRenderer.java
For another more concise and clear illustration, check #BalusC's answer as well.

Get rendered html code in Backing Component from Composite Component

How can I get the posted form data in the backing component in the
processUpdates method?
#Override
public void processUpdates(FacesContext context) {
//get here rendered html code
}
Or can I get the posted form data in the decode method?
[Edit]:
My goal is to get the posted form data - Not to get the generated html code (Sry I wasn't precisely)
It is unclear what you want to achive, yet. I mean, at high level.
UIComponent.decode and processUpdates are medium-level lifecycle APIs which should be overriden when you want to extend the framework.
If you just need to use the framework, you need a managed bean, not a backing component.
Furthermore, generally only components that extend UIInput need to hook in those phases, because they are bound to a value="#{...}" value expression (which in turn refers to a managed bean, in most cases), and need to synchronize those values with the bound expression.
I suspect you are uselessly complicating your life: hooking into medium or low-level APIs is a real pain if you don't have an excellent understanding about how the framework operates.
Anyway, the standard request parameters decode into input component is this:
String clientId = this.getClientId(context);
Map<String, String> requestMap = context.getExternalContext().getRequestParameterMap();
String newValue = requestMap.get(clientId);
if (newValue != null)
{
this.setSubmittedValue(newValue);
}
Please, post the full xhtml facelet code (not the composite one, but the facelet using that composite), so I can understand where you want to go and I can try to point you to the right tool to use.

JSF extending the UIInput does not invoke UPDATE_MODEL on the bean

I have created a custom components that extendeds UIInput and only overwrites the constructor and getFamily() as follows:
public HtmlInputDateTime() {
super();
setRendererType(RENDERER_TYPE);
}
#Override
public String getFamily() {
return COMP_FAMILY;
}
The I created the appropriate renderer that only overwrites getEndTextToRender. The problem is that although the local value is set and passed among requests (and the value is initially fetched from the model) it never updates the actual backing bean. Any hints why?
Thanks
Using JSF Mojarra 2.2
When creatinf custom components (or any forms in general) it is always a good idea to render h:messages to see if there were any validations that failed.
As it turns out component was working just fine but the since the value was a Date it failed the conversion. After I added <f:convertDateTime/>, it works fine.

Custom Validator, should I use FacesContext#addMessage() or throw ValidatorException?

I was wondering what is the correct way of implementing the custom Validator in JSF 1.2. In my Validator class'
public void validate(FacesContext context, UIComponent component,Object value) throws ValidatorException {}
method, I am doing the validation check and just adding the FacesMessage instance to the context by context.addMessage(new FacesMessage(xxx...); in case of invalid condition. This seems to be working fine in my application. However, I am not sure if I also need to explicitely throw new ValidatorException() for JSF to handle the lifecycle correctly? Or would JSF be smart enough to look at the error messages in context to manage the lifecycle?
You should indeed be throwing a ValidatorException. Otherwise JSF will still continue processing the request and update the model values and invoke the action method. You don't want to have it.
Do not manually add the FacesMessage. Construct the ValidatorException with it and JSF will then automatically add the message to the right component and JSF will then correctly skip the Update Model Values and Invoke Action phases.
if (!valid) {
FacesMessage message = new FacesMessage(SEVERITY_ERROR, "Invalid", null);
throw new ValidatorException(message);
}

Resources