How view parameters are obtained/attached from/to the URL query string (examples) ?
Let’s dissect several simple use cases and see how view parameters works (view parameters names are not mandatory to match the request parameters passed via URL query string, but in this post we will focus on this case):
CASE 1
In index.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
...
<h:form>
Enter name:<h:inputText value="#{playersBean.playerName}"/>
Enter surname:<h:inputText value="#{playersBean.playerSurname}"/>
<h:commandButton value="Send" action="results?faces-redirect=true&includeViewParams=true"/>
</h:form>
In results.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>In PlayersBean we have:
@Named
@RequestScoped
public class PlayersBean {
private String playerName;
private String playerSurname;
...
}What is happening when application reaches in (is not important how you set the query string; you can do it manually, or navigate via with here) index.xhtml?playernameparam=rafael&playersurnameparam=nadal ?
- The request parameters names matches the names of the view parameters, so the view parameters take the request parameters values and, finally, stores them in the
PlayersBeanmanaged bean underplayerNameandplayerSurnamefields. So, roughly said, you set the managed bean fields via view parameters. - The view is rendered (HTML markup is generated and sent to browser), so you can see
rafaelandnadalin the text inputs, since they are fetched from the managed bean properties (these are#{playersBean.playerName}and#{playersBean.playerSurname}). - You (as user) can manually modify these values (texts) in the text inputs (or leave them like that). Now, when you click on the
Send button, you practically submit the form with current values (the part delimitated by<h:form>
</h:form>). So, the name and surname are submitted and override/init the current values in the data model (even if you didn’t modify them). During encoding (rendering) the view, JSF will encode view parameters also against thePlayersBeanmanaged bean. - Further, JSF notices that you want to attach the view parameters (you signal this as:
?faces-redirect=true&includeViewParams=true) before navigating to the next target page (results.xhtml). The view parameters have been evaluated against thePlayersBeanmanaged bean earlier in this request. So, JSF process the view parameters and attaches to the action URL the corresponding query string computed from view parameters names and values. - JSF navigates to the target URL (which now contains the query string). This is visible thanks to
faces-redirect=true.
CASE 2
In index.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
<h:form>
Enter name:<h:inputText value="#{playersBean.playerName}"/>
Enter surname:<h:inputText value="#{playersBean.playerSurname}"/>
<h:commandButton value="Send" action="results?faces-redirect=true&includeViewParams=true"/>
</h:form>In results.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>In PlayersBean we have:
@Named
@RequestScoped
public class PlayersBean {
private String playerName = "roger";
private String playerSurname = "federer";
...
}
What is happening when application reaches in index.xhtml ? (no query string)
- There is no query string (no request parameters). So, the view parameters cannot be initialized from the query string, and they doesn’t set anything in
PlayersBeanalso! - The view is rendered (HTML markup is generated and sent to browser), and the text inputs reflect the
roger andfederer initalizationdata (these are the result of evaluating#{playersBean.playerName}and#{playersBean.playerSurname}). - You (as user) can modify these values in the text inputs (or not!). Now, when you click on the
Sendbutton, you practically submit the form (the data that belongs to the part delimitated by<h:form>
</h:form>). So, the name and surname are submitted and override/init the current values in model (even if you didn’t modify them). During encoding (rendering) the view, JSF will encode view parameters also against thePlayersBeanmanaged bean. - Further, JSF notices that you want to attach the view parameters (you signal this as:
?faces-redirect=true&includeViewParams=true) before navigating to the next target page (results.xhtml). The view parameters have been evaluated against thePlayersBeanmanaged bean earlier in this request. So, JSF process the view parameters and attaches to the action URL the corresponding query string computed from view parameters names and values. - JSF navigates to the target URL (which now contains the query string). This is visible thanks to
faces-redirect=true.
CASE 3
In index.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
<h:link value="Send" outcome="results" includeViewParams="true"/>In results.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>In PlayersBean we have:
@Named
@RequestScoped
public class PlayersBean {
private String playerName;
private String playerSurname;
...
}What is happening when application reaches in (is not important how you set the query string; you can do it manually, or navigate via with here) index.xhtml?playernameparam=rafael&playersurnameparam=nadal ?
- The request parameters names matches the names of the view parameters, so the view parameters take request parameters values and stores them in the managed bean under
playerNameandplayerSurname. So, you set the managed bean fields via view parameters. - The view is rendered (HTML markup is generated and sent to browser), so in the text inputs you can see
rafaelandnadaltexts, since they are fetched from the managed bean (these are the results of evaluating#{playersBean.playerName}and#{playersBean.playerSurname}). During encoding (rendering) the view, JSF will encode view parameters also against thePlayersBeanmanaged bean. Now, check the source code of the page and notice that the<a href>corresponding to<h:link>was generated as below (notice that this isfix!). So, JSF transforms the<h:link>into a<a href>and attaches the query string containing the view parameters right from the initial request. TheincludeViewParams="true"attribute causes the below link: - When you click the link, you DON’T submit any data (
<h:link>should never be in a<h:form>). You simply execute the above static HTML code, which is a simple GET request! - JSF navigates to the target URL via this GET (which contains the query string). There is no need for
faces-redirect=true.
CASE 4
In index.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
<h:link value="Send" outcome="results" includeViewParams="true"/>
In results.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>
In PlayersBean we have:
@Named
@RequestScoped
public class PlayersBean {
private String playerName = "roger";
private String playerSurname = "federer";
...
}
What is happening when application reaches in index.xhtml ? (no query string)
- There are no request parameters. So, the view parameters cannot be initialized from the query string. The view parameters doesn’t set anything in the managed bean also!
- The view is rendered (HTML markup is generated and sent to browser), so you can see roger and
federerin the text inputs, since they are fetched from the managed bean (these are the result of evaluating the#{playersBean.playerName}and#{playersBean.playerSurname}). During encoding (rendering) the view, JSF will encode view parameters also against thePlayersBeanmanaged bean (obtainingrogerandfederer). Now, check the source code of the page and notice that the<a href>corresponding to<h:link>was generated as below (notice that this isfix!). So, JSF transforms the<h:link>into a<a href>and attaches the query string containing the view parameters right from the initial request. TheincludeViewParams="true"attribute causes the below link: - When you click the link, you DON’T submit any data. You simply execute the above static HTML code, which is a simple GET request!
- JSF navigates to the target URL via this GET (which contains the query string). There is no need for
faces-redirect=true.
CASE 5
In index.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
<h:link value="Send" outcome="results" includeViewParams="true"/>In results.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>In PlayersBean we have:
@Named
@RequestScoped
public class PlayersBean {
private String playerName; // this is null
private String playerSurname; // this is null
...
}What is happening when application reaches in index.xhtml ? (no query string)
- There are no request parameters. So, the view parameters cannot be initialized from the query string. The view parameters doesn’t set anything in the bean!
- The view is rendered (HTML markup is generated and sent to browser), so you can’t see anything in the text inputs, since they are fetched from the bean (these are
#{playersBean.playerName}and#{playersBean.playerSurname}which arenull– you cannot expect to see textnull!). During encoding (rendering) the view, JSF will encode view parameters also against thePlayersBeanmanaged bean (obtainingnull). Now, check the source code of the page and notice that the<a href>corresponding to<h:link>was generated as below (notice that this isfix!). So, JSF transforms the<h:link>into a<a href>, but there is no query string containing the view parameters because JSF sees theincludeViewParams="true"attribute, but it cannot generate this HTML: <a href=”/…/results.xhtml?playernameparam=null&playersurnameparam=null“>Send</a> So, JSF will “ignore” thenullvalues and there is no query string to attach: <a href=”/…/results.xhtml”>Send</a> - When you click the link, you DON’T submit any data. You simply execute the above static HTML code, which is a simple GET request!
- JSF navigates to the target URL via this GET (which contains the query string). There is no need for faces-redirect=true.
CASE 6 – for better understanding null values
In index.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
<h:form>
Enter name:<h:inputText value="#{playersBean.playerName}"/>
Enter surname:<h:inputText value="#{playersBean.playerSurname}"/>
<h:commandButton value="Send" action="results?faces-redirect=true&includeViewParams=true"/>
</h:form>In results.xhtml page we have:
<f:metadata>
<f:viewParam name="playernameparam" value="#{playersBean.playerName}"/>
<f:viewParam name="playersurnameparam" value="#{playersBean.playerSurname}"/>
</f:metadata>
You requested name: <h:outputText value="#{playersBean.playerName}"/><br/>
You requested surname: <h:outputText value="#{playersBean.playerSurname}"/>In PlayersBean we have:
@Named
@RequestScoped
public class PlayersBean {
private String playerName; // this is null
private String playerSurname; // this is null
...
}What is happening when application reaches in index.xhtml ? (no query string)
- There are no request parameters. So, the view parameters cannot be initialized from the query string. The view parameters doesn’t set anything in the bean also!
- The view is rendered (HTML markup is generated and send to browser), and you can see two empty text inputs (these are the results of evaluating the
#{playersBean.playerName}and#{playersBean.playerSurname}). You cannot expect to see text, null! - As a user, don’t type anything in these text inputs and press on the
Sendbutton. Practically, you will submit the form (the data that belongs to the part delimitated by<h:form></h:form>). So, the name and surname (which are empty spaces) are submitted and override/init the current values in model. During encoding (rendering) the view, JSF will encode view parameters also against thePlayersBeanmanaged bean (will obtain empty spaces). - Further, JSF notices that you want to attach the view parameters (you signal this as:
?faces-redirect=true&includeViewParams=true) before navigating to the next target page (results.xhtml). The view parameters have been evaluated against thePlayersBeanmanaged bean earlier in this request. So, JSF process the view parameters and attaches to the action URL the corresponding query string computed from view parameters names and values. - JSF navigates to the target URL (which now contains the query string). This is visible thanks to
faces-redirect=true.
http://localhost:8080/.../results.xhtml?playernameparam=&playersurnameparam=
Notice the values of playernameparam and playersurnameparam! Since you have submitted empty spaces, this is what you will see. Of course, this looks “ugly” and pretty useless. Maybe you will prefer to treat empty spaces as null values. For this you can set in web.xml the following context parameter:
<context-param> <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name> <param-value>true</param-value> </context-param>
Now, clean and build the app and run it again with the same scenario. This time when you press on the
Send button, you notice this link:
- http://localhost:8080/ch2_6/faces/results.xhtml
So, no query string is reflecting the view parameters presence! Well, you just instructed JSF to treat submitted empty string as null values. But, as you know, null values are “ignored” when the view parameters are attached.
NOTE
The way of attaching view params can be seen in Mojarra, in com.sun.faces.application.view.MultiViewHandler. Especially in:
// Mojarra 2.2.9, MultiViewHandler#addViewParameters()
protected void addViewParameters(FacesContext ctx,
String viewId,
Map<String,List<String>> existingParameters) {
UIViewRoot currentRoot = ctx.getViewRoot();
String currentViewId = currentRoot.getViewId();
Collection<UIViewParameter> toViewParams = Collections.emptyList();
Collection<UIViewParameter> currentViewParams;
boolean currentIsSameAsNew = false;
currentViewParams = ViewMetadata.getViewParameters(currentRoot);
if (currentViewId.equals(viewId)) {
currentIsSameAsNew = true;
toViewParams = currentViewParams;
} else {
ViewDeclarationLanguage pdl = getViewDeclarationLanguage(ctx, viewId);
ViewMetadata viewMetadata = pdl.getViewMetadata(ctx, viewId);
if (null != viewMetadata) {
UIViewRoot root = viewMetadata.createMetadataView(ctx);
toViewParams = ViewMetadata.getViewParameters(root);
}
}
if (toViewParams.isEmpty()) {
return;
}
for (UIViewParameter viewParam : toViewParams) {
String value = null;
// don't bother looking at view parameter if it's been overridden
if (existingParameters.containsKey(viewParam.getName())) {
continue;
}
if (paramHasValueExpression(viewParam)) {
value = viewParam.getStringValueFromModel(ctx);
}
if (value == null) {
if (currentIsSameAsNew) {
value = viewParam.getStringValue(ctx);
} else {
value = getStringValueToTransfer(ctx, viewParam, currentViewParams);
}
}
// SO, IF VALUE IS NULL, DON'T CONSIDER THIS A VIEW PARAM
if (value != null) {
List<String> existing = existingParameters.get(viewParam.getName());
if (existing == null) {
existing = new ArrayList<String>(4);
existingParameters.put(viewParam.getName(), existing);
}
existing.add(value);
}
}
}| Reference: | How view parameters are obtained/attached from/to the URL query string (examples) ? from our JCG partner Anghel Leonard at the JSF and OmniFaces Fans blog. |




