How to get UIComponent value in Java? - jsf

I have a method in my JSF controller that is invoked by an ajax tag nested inside a visual component (really irrelevant which one). The method takes a single argument of type AjaxBehaviorEvent, from which I can obtain a Java representation of the invoking HTML visual component as a UIComponent and also downcast it to its specific corresponding type (e.g. h:inputText corresponding to HtmlInputText).
I understand that, in most cases, the value of the HTML visual component would be retrieved easily by referencing either the controller or entity [g|s]etters to which the form fields are mapped in the view. However, in my particular case, I would like to fetch the value of the visual component (in my case a form field) through its Java object rendering. While studying the faces API, I found ways to read various properties of the object, such as the ID or context but not the value that the component currently holds in the view.
Can anybody explain whether I am just not finding the right way to read it or it is so by design? If the latter, can you explain why it is designed like that? Is it to disable "backdoor" access to form fields as opposed to going through the view mapping?

There are a multitude of ways to pull values off a component. Going by what you already have UIInputt#getValue() and UIInput#getSubmittedValue() will provide the value.
The UIInput#getSubmittedValue() is fit for the purpose only between the APPLY_REQUEST_VALUES and VALIDATE phases of the JSF request. All other phases after, use the UIInputt#getValue(). You'll be using UIInput instead of the raw UIComponent you pulled from the event (UIInput extends UIComponent and it's the parent class for all input components that accept user-edited values). What you'll have will eventually look like:
UIInput theInput = (UIInput)event.getSource();
Object theValue = theInput.getValue();
There are other ways (not as clean) to get values within the request lifecycle also

Related

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.

Can JSF be configured to not invoke Entity setter unless the field actually changed?

When a JSF form field is wired into an entity bean field (which is mapped to a DB field), each setter in the entity bean is called regardless of whether the user changed the form field value in the front end, i.e. the setters on unchanged fields are invoked the same as those that have changed but their new value is the same as the old value.
My question is simple: Is there a way to configure JSF to only call the setters mapped to the fields that have changed in the front end? The reason for this is that I have a requirement by which I have to detect deltas on every persist and log them, more about which can be read in this question.
Maybe I didn't understand you clearly, but why are you mapping directly your entity beans to a JSF view ?! IMHO it would be better if you add managed beans between your JSF pages and the entities in order to better separate your business logic from data access.
Any way, I think the easiest solution to impelement for that case is by making use of Value Change Events which are invoked "normally" after the Process Validations phase (unless you make use of the immediate attribute).
The good news about Value Change Events (regarding your example) is they are invoked ONLY after you force form submit using JavaScript or Command components AND the new value is different from the old value.
So, as an example on how to use value change listeners, you can add valueChangeListner attribute to each of your JSF tags like following:
<h:inputText id="input" value="#{someBean.someValue}"
valueChangeListener="#{someBean.valueChanged} />
Then, implement your valueChanged() method to look something like:
public void valueChanged(ValueChangeEvent event) {
// You can use event.getOldValue() and event.getNewValue() to get the old or the new value
}
Using the above implementation, may help you to separate your logging code (it will be included in the listeners) from your managed properties setters.
NB: Value Change Listeners may also be implemetend otherwise using the f:valueChangeListener Tag, but this is not the best choice for your example (you can find some examples in the section below, just in case)
See also:
Valuechangelistener Doubt in JSF
JSF 2 valueChangeListener example
When to use valueChangeListener or f:ajax listener?

How to programmatically generate JSF components at run time?

I've got to create screens to display a lot of JPA entities in the View. It would be great to create one facelet and pass to it a collection of fields e.g. List<Object>.
The facelet/custom component would need to convert each element of the list into the appropriate tag for display e.g. an enum field to h:selectOneMenu, String field to h:inputText, etc. This would need to be done at run time.
What's the easiest way to do this?
Worked on a project previously that created entire pages dynamically from stored configuration. There are two basic things you need
A BackingBean. You'll used this to get access to the UIComponent on the facelet which will act as the parent to the generated UIComponents. Something like a panelGroup. But, you'll need to bind the UIComponent to the backing bean, in order to have a parent against which you'll add the dynamically-created UIComponents
Access to the Application component. Typically FacesContext.getApplication() (I worked on this in JavaEE 5, so it might look a little different with injection). Once you have the Application component, you call the createComponent method, passing in the type of component you want to create.
It then becomes an activity of creating components dynamically, configuring them in code and adding them to the parent UIComponent defined via a binding bean. It can be tricky, but it can be done.

How to access a composite component's sibling via clientId

I have a composite component that bundles some input fields. The component will be used multiple times on a page and contains a button to copy the values of another of these components. For this I would need to access one of those siblings via its clientId as a target for an
<f:ajax execute=":XXX:siblingId" render="...">
My problem lies in constructing this ID. I have the name of the sibling and I can make sure that it is located in the same naming container as the component that contains the copy button, but I can't control the complete nesting hierarchy, so it might be :form:foo:bar:parent:child or just form:parent:child. So essentially I would want to get the prefix of the current composite component, but without the component's own ID and then attach the ID of the component from which to copy.
This is similar to these questions:
How to address the surrounding naming container in jsf
How to access the parent naming container of composite
However, both answers make use of PrimeFaces-sepcific features like #parent and widgetVar, which does not apply to my project.
When experimenting with EL's implicit objects I basically tried the same things as the poster of the second question - with the same results: cc.parent.clientId is always empty. I also tried cc.namingContainer.clientId and some combinations of the two, alas - no success. Especially the fact that parent does not work as expected confuses me...
So: Is there a component-library-agnostic way to access the "path" of containing naming containers for a composite component? How is the parent object supposed to work, especially: when can we use it and when not?
PS: I was thinking about using the composite's full clientId and then trimming its actual ID with fn:split, however, if there was a more direct way I'd be happy to use it.
The #{cc.parent} resolves to UIComponent#getCompositeComponentParent() which returns the closest parent composite component. In other words, it returns only non-null when the composite component is by itself nested in another composite component.
The #{cc.namingContainer} simply refers to #{cc} itself, fully conform as specified in UIComponent#getNamingContainer():
Starting with "this", return the closest component in the ancestry that is a NamingContainer or null if none can be found.
Composite components namely implicitly implement NamingContainer themselves.
So your attempts unfortunately won't work. I also do not see any "standard API" ways to achieve the concrete functional requirement. The CompositeComponentAttributesELResolver causes that the #{cc.parent} doesn't resolve to UIComponent#getParent() which is what you ultimately want.
You can however provide a custom UIComponent implementation for the composite which adds an extra getter with an unique name which in turn properly delegates to UIComponent#getParent().
Here's a kickoff example:
#FacesComponent("myComposite")
public class MyComposite extends UINamingContainer {
public UIComponent getParentComponent() {
return super.getParent();
}
}
If you register it as follows in the composite interface:
<cc:interface componentType="myComposite">
then you'll be able to use
#{cc.parentComponent.clientId}
to get the client ID of the real parent UIComponent.
Ultimately you should be able to use the following construct to refer the sibling:
process=":#{cc.parentComponent.clientId}:siblingId"

JSF getValue() v.s. getSubmittedValue()

I've been developing a few JSF applications lately and am disturbed with the inconsistency in the web component APIs.
I've noticed that there is extremely unpredictable behavior when calling .getValue() or .getSubmittedValue() on a JSF component object in server side code. Sometimes when I call .getValue() on a drop down list box, I've noticed that I get the value as it was BEFORE I selected my value (so the value from the last page refresh), of which .getSubmittedValue() gets me the correct value, as such:
UIInput name = new UIInput(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the "old" value
someMethod(name.getSubmittedValue().toString()); // Retrieves the correct value
}
Also, I've noticed that calling .getSubmittedValue() on a form field sometimes results in a null pointer exception because that value has not been instantiated in the component object, in which case when I call .getValue() in that circumstance I get the correct value, for example:
HtmlInputText name = new HtmlInputText(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the correct value
someMethod(name.getSubmittedValue().toString()); // Throws NullPointerException
}
Is this just a "quirk" of the JSF framework, or am I just using the API COMPLETELY incorrectly?? Any insight into these two methods would be greatly appreciated. Cheers.
Since this is the #1 result in Google for searching on getValue vs. getSubmittedValue I'd just like to add that the difference between these is critical in validation (i.e. when writing a custom validator)
To quote the API documentation for getSubmittedValue():
This is non-null only between decode
and validate phases, or when
validation for the component has not
succeeded. Once conversion and
validation has succeeded, the
(converted) value is stored in the
local "value" property of this
component, and the submitted value is
reset to null.
Source: http://myfaces.apache.org/core11/myfaces-api/apidocs/javax/faces/component/UIInput.html#getSubmittedValue()
This means that if the validation/conversion has taken place for the binding you are trying to access, you should call getValue() otherwise you'll have to call getSubmittedValue() and deal with parsing it yourself. The order in which these occur seems to be dictated by the order they appear in the UI, but I don't think that's guaranteed. Even if it is, you shouldn't count on that as changing field in your UI shouldn't break your code.
You can detect if the validation/conversion has been done by just looking at what isLocalValueSet() returns. If it returns true, then the valdation/conversion has been done, so you should call getValue(). Otherwise you'll need to call getSubmittedValue() and that'll give you the raw input the user entered and you'll likely want to parse it into something more meaningful.
For example, a calendar object would return a Date object when getValue() was called, but a String object when getSubmittedValue() was called. It's up to your converter to parse the string into a Date so it can be validated.
It'd be great if the JSF spec had a method which would do this for us, but AFAIK it doesn't. If certain dates need to be before other dates, and some are only required in certain circumstances, one will need to write several validators to handle this. So it can easily become an issue. This is similar to the fact that you can't do any kind of validation on a blank field, which means you can't make that field conditionally required. If validation was run on all fields, even blank ones, a custom validator could be written to throw an exception if it should be required and is not. There are some things with JSF which are just a pain; unless/until they're fixed, we just have to deal with them.
To speak to the specifics of the issue in the original post: the difference here is where you're at in the life cycle. The submit method seems like an action listener for a button, which puts it at the end of the life cycle; actions and action listeners are triggered in the "Invoke Application" phase which comes prior to the render response, but after validation. If you're going to program in JSF, you should learn and understand the life cycle. It's worth the time.
To quote the documentation on EditableValueHolder.getSubmittedValue:
Return the submittedValue value of
this component. This method should
only be used by the encodeBegin()
and/or encodeEnd() methods of this
component, or its corresponding
Renderer.
Generally, you would not even be calling getValue. Instead, the component's value attribute should be bound to your model (a bean, maybe). Your business logic would interact with the model, not the component.
If the submitted value is not being set as the value, then I'd guess that some validation is failing. The only problem with that is that your event is being fired. Two guesses for the problem here:
You have a stale reference to the component object.
You've set the immediate attribute on a UICommand which means that the event is fired in a phase where the component will be in an inappropriate state.
It isn't possible to be certain with the information provided.
I work on xpages which are based on JSF so.. it could be the same...
Anyway, getSubmittedValue(); always returns what you see in firebug/chrome develepers network tab. That is value within sent packet. I have it shown (chrome) in headers tab, in form data section, named $$xspsubmitvalue.
On the other hand, getValue() is component specific. <-- not 100% sure here.
TL;DR answer:
UIViewRoot viewRoot = context.getViewRoot();
UIInput input = (UIInput)viewRoot.findComponent(":form:inputID");
String inputValueString;
if (input.isLocalValueSet()) {
inputValueString = (String)input.getValue(); //validated and converted already
} else {
inputValueString = (String)input.getSubmittedValue(); //raw input
}
or at least that's what the other answers are saying to do...
Just use .getSubmittedValue() and deal with the consequences of having to convert raw input (if necessary, if that raw input needs conversion). .getValue() is broken in this regard, even with the code above. It delays the submitted value if you use it and that's unacceptable.

Resources